bson-transpilers
Advanced tools
Comparing version 0.0.0-next-8ec9e3341a4516d0d09c0d9efbbb836758c48228 to 0.0.0-next-8fcca6264afe05c6cb224ee274816efb1ac136ef
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/* eslint complexity: 0, camelcase: 0, "new-cap": 0 */ | ||
@@ -9,3 +10,3 @@ const { | ||
BsonTranspilersTypeError, | ||
BsonTranspilersUnimplementedError | ||
BsonTranspilersUnimplementedError, | ||
} = require('../helper/error'); | ||
@@ -24,84 +25,89 @@ | ||
*/ | ||
module.exports = (ANTLRVisitor) => class CodeGenerationVisitor extends ANTLRVisitor { | ||
constructor() { | ||
super(); | ||
this.idiomatic = true; // PUBLIC | ||
this.clearImports(); | ||
this.state = { declarations: new DeclarationStore() }; | ||
} | ||
module.exports = (ANTLRVisitor) => | ||
class CodeGenerationVisitor extends ANTLRVisitor { | ||
constructor() { | ||
super(); | ||
this.idiomatic = true; // PUBLIC | ||
this.clearImports(); | ||
this.state = { declarations: new DeclarationStore() }; | ||
} | ||
clearImports() { | ||
this.requiredImports = {}; | ||
[300, 301, 302, 303, 304, 305, 306].forEach( | ||
(i) => (this.requiredImports[i] = []) | ||
); | ||
} | ||
/** | ||
* Start the compiler at this.startRule. | ||
* | ||
* "Return" methods are overridden only by the object generator. All | ||
* generators or visitors that translate code to code should not need to | ||
* override these methods. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @return {*} | ||
*/ | ||
returnResult(ctx) { | ||
const rule = `visit${this.startRule.replace(/^\w/, c => c.toUpperCase())}`; | ||
if (!this.startRule || !(rule in this)) { | ||
throw new BsonTranspilersInternalError( | ||
'Unimplemented Visitor: the entry rule for the compiler must be set' | ||
clearImports() { | ||
this.requiredImports = {}; | ||
[300, 301, 302, 303, 304, 305, 306].forEach( | ||
(i) => (this.requiredImports[i] = []) | ||
); | ||
} | ||
return this[rule](ctx); | ||
} | ||
returnResultWithDeclarations(ctx) { | ||
let result = this.returnResult(ctx); | ||
if (this.getState().declarations.length() > 0) { | ||
result = `${this.getState().declarations.toString() + '\n\n'}${result}`; | ||
/** | ||
* Start the compiler at this.startRule. | ||
* | ||
* "Return" methods are overridden only by the object generator. All | ||
* generators or visitors that translate code to code should not need to | ||
* override these methods. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @return {*} | ||
*/ | ||
returnResult(ctx) { | ||
const rule = `visit${this.startRule.replace(/^\w/, (c) => | ||
c.toUpperCase() | ||
)}`; | ||
if (!this.startRule || !(rule in this)) { | ||
throw new BsonTranspilersInternalError( | ||
'Unimplemented Visitor: the entry rule for the compiler must be set' | ||
); | ||
} | ||
return this[rule](ctx); | ||
} | ||
return result; | ||
} | ||
/** | ||
* PUBLIC: This is the entry point for the compiler. Each visitor must define | ||
* an attribute called "startNode". | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {Boolean} useDeclarations - prepend the result string with declarations | ||
* @return {String} | ||
*/ | ||
start(ctx, useDeclarations = false) { | ||
return (useDeclarations ? this.returnResultWithDeclarations(ctx) : this.returnResult(ctx)).trim(); | ||
} | ||
returnResultWithDeclarations(ctx) { | ||
let result = this.returnResult(ctx); | ||
if (this.getState().declarations.length() > 0) { | ||
result = `${this.getState().declarations.toString() + '\n\n'}${result}`; | ||
} | ||
return result; | ||
} | ||
getState() { | ||
return this.state; | ||
} | ||
/** | ||
* PUBLIC: This is the entry point for the compiler. Each visitor must define | ||
* an attribute called "startNode". | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {Boolean} useDeclarations - prepend the result string with declarations | ||
* @return {String} | ||
*/ | ||
start(ctx, useDeclarations = false) { | ||
return ( | ||
useDeclarations | ||
? this.returnResultWithDeclarations(ctx) | ||
: this.returnResult(ctx) | ||
).trim(); | ||
} | ||
clearDeclarations() { | ||
this.getState().declarations.clear(); | ||
} | ||
getState() { | ||
return this.state; | ||
} | ||
/** | ||
* PUBLIC: As code is generated, any classes that require imports are tracked | ||
* in this.Imports. Each class has a "code" defined in the symbol table. | ||
* The imports are then generated based on the output language templates. | ||
* @param {String} mode | ||
* @param {Boolean} driverSyntax (optional) | ||
* @return {String} - The list of imports in the target language. | ||
*/ | ||
getImports(mode, driverSyntax) { | ||
const importTemplate = this.Imports.import.template ? | ||
this.Imports.import.template : | ||
(s) => ( | ||
Object.values(s) | ||
.filter((a, i) => (Object.values(s).indexOf(a) === i)) | ||
.join('\n') | ||
); | ||
// Remove empty arrays because js [] is not falsey :( | ||
[300, 301, 302, 303, 304, 305, 306].forEach( | ||
(i) => { | ||
clearDeclarations() { | ||
this.getState().declarations.clear(); | ||
} | ||
/** | ||
* PUBLIC: As code is generated, any classes that require imports are tracked | ||
* in this.Imports. Each class has a "code" defined in the symbol table. | ||
* The imports are then generated based on the output language templates. | ||
* @param {String} mode | ||
* @param {Boolean} driverSyntax (optional) | ||
* @return {String} - The list of imports in the target language. | ||
*/ | ||
getImports(mode, driverSyntax) { | ||
const importTemplate = this.Imports.import.template | ||
? this.Imports.import.template | ||
: (s) => | ||
Object.values(s) | ||
.filter((a, i) => Object.values(s).indexOf(a) === i) | ||
.join('\n'); | ||
// Remove empty arrays because js [] is not falsey :( | ||
[300, 301, 302, 303, 304, 305, 306].forEach((i) => { | ||
if (i in this.requiredImports && this.requiredImports[i].length === 0) { | ||
@@ -111,771 +117,841 @@ this.requiredImports[i] = false; | ||
}); | ||
this.requiredImports.driver = !!driverSyntax; | ||
const imports = {}; | ||
for (const code of Object.keys(this.requiredImports)) { | ||
if ( | ||
this.requiredImports[code] && | ||
this.Imports[code] && | ||
this.Imports[code].template | ||
) { | ||
imports[code] = this.Imports[code].template(this.requiredImports[code], mode); | ||
this.requiredImports.driver = !!driverSyntax; | ||
const imports = {}; | ||
for (const code of Object.keys(this.requiredImports)) { | ||
if ( | ||
this.requiredImports[code] && | ||
this.Imports[code] && | ||
this.Imports[code].template | ||
) { | ||
imports[code] = this.Imports[code].template( | ||
this.requiredImports[code], | ||
mode | ||
); | ||
} | ||
} | ||
return importTemplate(imports); | ||
} | ||
return importTemplate(imports); | ||
} | ||
/** | ||
* Used by the generators. Makes a copy of the required imports so | ||
* can be rolled back after a recursion if needed. | ||
* | ||
* @return {Object} | ||
*/ | ||
deepCopyRequiredImports() { | ||
const copy = Object.assign({}, this.requiredImports); | ||
[300, 301, 302, 303, 304, 305, 306].forEach((i) => { | ||
copy[i] = Array.from(this.requiredImports[i]); | ||
}); | ||
return copy; | ||
} | ||
/** | ||
* Used by the generators. Makes a copy of the required imports so | ||
* can be rolled back after a recursion if needed. | ||
* | ||
* @return {Object} | ||
*/ | ||
deepCopyRequiredImports() { | ||
const copy = Object.assign({}, this.requiredImports); | ||
[300, 301, 302, 303, 304, 305, 306].forEach((i) => { | ||
copy[i] = Array.from(this.requiredImports[i]); | ||
}); | ||
return copy; | ||
} | ||
/** | ||
* If the compiler reaches a expression in the input language | ||
* that is not implemented yet. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
*/ | ||
unimplemented(ctx) { | ||
const name = this.renameNode(ctx.constructor.name); | ||
throw new BsonTranspilersUnimplementedError( | ||
`'${name}' not yet implemented` | ||
); | ||
} | ||
/** | ||
* If the compiler reaches a expression in the input language | ||
* that is not implemented yet. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
*/ | ||
unimplemented(ctx) { | ||
const name = this.renameNode(ctx.constructor.name); | ||
throw new BsonTranspilersUnimplementedError( | ||
`'${name}' not yet implemented` | ||
); | ||
} | ||
/** | ||
* Some grammar definitions are written so that comparisons will chain and add | ||
* nodes with a single child when the expression does *not* match. This is a | ||
* helper method (right now used just by Python) that skips nodes downwards | ||
* until a node with multiple children is found, or a node matches "goal". | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {String} goal - Optional: the name of the child to find. | ||
* @return {ParserRuleContext} | ||
*/ | ||
skipFakeNodesDown(ctx, goal) { /* eslint no-unused-vars: 0 */ | ||
return ctx; | ||
} | ||
_getType(ctx) { | ||
if (ctx.type !== undefined) { | ||
/** | ||
* Some grammar definitions are written so that comparisons will chain and add | ||
* nodes with a single child when the expression does *not* match. This is a | ||
* helper method (right now used just by Python) that skips nodes downwards | ||
* until a node with multiple children is found, or a node matches "goal". | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {String} goal - Optional: the name of the child to find. | ||
* @return {ParserRuleContext} | ||
*/ | ||
skipFakeNodesDown(ctx, goal) { | ||
/* eslint no-unused-vars: 0 */ | ||
return ctx; | ||
} | ||
if (!ctx.children) { | ||
_getType(ctx) { | ||
if (ctx.type !== undefined) { | ||
return ctx; | ||
} | ||
if (!ctx.children) { | ||
return null; | ||
} | ||
for (const c of ctx.children) { | ||
const typed = this._getType(c); | ||
if (typed) { | ||
return typed; | ||
} | ||
} | ||
return null; | ||
} | ||
for (const c of ctx.children) { | ||
const typed = this._getType(c); | ||
if (typed) { | ||
return typed; | ||
/** | ||
* Recursively descend down the tree looking for a node with the type set. | ||
* Returns the first child node with a type set. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @return {ParserRuleContext} | ||
*/ | ||
findTypedNode(ctx) { | ||
const typed = this._getType(ctx); | ||
if (!typed) { | ||
throw new BsonTranspilersInternalError( | ||
'Type not set on any child nodes' | ||
); | ||
} | ||
return typed; | ||
} | ||
return null; | ||
} | ||
/** | ||
* Recursively descend down the tree looking for a node with the type set. | ||
* Returns the first child node with a type set. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @return {ParserRuleContext} | ||
*/ | ||
findTypedNode(ctx) { | ||
const typed = this._getType(ctx); | ||
if (!typed) { | ||
throw new BsonTranspilersInternalError('Type not set on any child nodes'); | ||
/** | ||
* Get the 'originalType' of ctx, of if it's undefined, keep checking parent | ||
* nodes until an original type is found. Otherwise null. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @return {ParserRuleContext} | ||
*/ | ||
getParentOriginalType(ctx) { | ||
if (ctx.originalType !== undefined) { | ||
return ctx.originalType; | ||
} | ||
if (ctx.parentCtx) { | ||
return this.getParentOriginalType(ctx.parentCtx); | ||
} | ||
return null; | ||
} | ||
return typed; | ||
} | ||
/** | ||
* Get the 'originalType' of ctx, of if it's undefined, keep checking parent | ||
* nodes until an original type is found. Otherwise null. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @return {ParserRuleContext} | ||
*/ | ||
getParentOriginalType(ctx) { | ||
if (ctx.originalType !== undefined) { | ||
return ctx.originalType; | ||
} | ||
if (ctx.parentCtx) { | ||
return this.getParentOriginalType(ctx.parentCtx); | ||
} | ||
return null; | ||
} | ||
compareTypes(expectedType, type, ctx, result) { | ||
// If the types are exactly the same, just return. | ||
if ( | ||
expectedType.indexOf(type) !== -1 || | ||
expectedType.indexOf(type.id) !== -1 | ||
) { | ||
return result; | ||
} | ||
compareTypes(expectedType, type, ctx, result) { | ||
// If the types are exactly the same, just return. | ||
if (expectedType.indexOf(type) !== -1 || | ||
expectedType.indexOf(type.id) !== -1) { | ||
return result; | ||
} | ||
const numericTypes = [ | ||
this.Types._integer, this.Types._decimal, this.Types._hex, | ||
this.Types._octal, this.Types._long | ||
]; | ||
// If both expected and node are numeric literals, cast + return | ||
for (let i = 0; i < expectedType.length; i++) { | ||
if (numericTypes.indexOf(type) !== -1 && | ||
numericTypes.indexOf(expectedType[i]) !== -1) { | ||
// Need to visit the octal node always | ||
if (type.id === '_octal') { | ||
return this.leafHelper( | ||
expectedType[i], | ||
{ | ||
const numericTypes = [ | ||
this.Types._integer, | ||
this.Types._decimal, | ||
this.Types._hex, | ||
this.Types._octal, | ||
this.Types._long, | ||
]; | ||
// If both expected and node are numeric literals, cast + return | ||
for (let i = 0; i < expectedType.length; i++) { | ||
if ( | ||
numericTypes.indexOf(type) !== -1 && | ||
numericTypes.indexOf(expectedType[i]) !== -1 | ||
) { | ||
// Need to visit the octal node always | ||
if (type.id === '_octal') { | ||
return this.leafHelper(expectedType[i], { | ||
type: expectedType[i], | ||
originalType: type.id, | ||
getText: () => ( this.visit(ctx) ) | ||
} | ||
); | ||
getText: () => this.visit(ctx), | ||
}); | ||
} | ||
const child = this.skipFakeNodesDown(ctx); | ||
child.originalType = type; | ||
child.type = expectedType[i]; | ||
return this.leafHelper(expectedType[i], child); | ||
} | ||
const child = this.skipFakeNodesDown(ctx); | ||
child.originalType = type; | ||
child.type = expectedType[i]; | ||
return this.leafHelper(expectedType[i], child); | ||
} | ||
} | ||
// If the expected type is "numeric", accept the number basic & bson types | ||
if (expectedType.indexOf(this.Types._numeric) !== -1 && | ||
(numericTypes.indexOf(type) !== -1 || (type.code === 106 || | ||
type.code === 105 || type.code === 104))) { | ||
return result; | ||
// If the expected type is "numeric", accept the number basic & bson types | ||
if ( | ||
expectedType.indexOf(this.Types._numeric) !== -1 && | ||
(numericTypes.indexOf(type) !== -1 || | ||
type.code === 106 || | ||
type.code === 105 || | ||
type.code === 104) | ||
) { | ||
return result; | ||
} | ||
// If the expected type is any number, accept float/int/_numeric | ||
if ( | ||
numericTypes.some((t) => expectedType.indexOf(t) !== -1) && | ||
(type.code === 106 || | ||
type.code === 105 || | ||
type.code === 104 || | ||
type === this.Types._numeric) | ||
) { | ||
return result; | ||
} | ||
return null; | ||
} | ||
// If the expected type is any number, accept float/int/_numeric | ||
if ((numericTypes.some((t) => ( expectedType.indexOf(t) !== -1))) && | ||
(type.code === 106 || type.code === 105 || type.code === 104 || | ||
type === this.Types._numeric)) { | ||
return result; | ||
} | ||
return null; | ||
} | ||
/** | ||
* Convert between numeric types. Required so that we don't end up with | ||
* strange conversions like 'Int32(Double(2))', and can just generate '2'. | ||
* | ||
* @param {Array} expectedType - types to cast to. | ||
* @param {ParserRuleContext} ctx - ctx to cast from, if valid. | ||
* | ||
* @returns {String} - visited result, or null on error. | ||
*/ | ||
castType(expectedType, ctx) { | ||
const result = this.visit(ctx); | ||
const typedCtx = this.findTypedNode(ctx); | ||
let type = typedCtx.type; | ||
/** | ||
* Convert between numeric types. Required so that we don't end up with | ||
* strange conversions like 'Int32(Double(2))', and can just generate '2'. | ||
* | ||
* @param {Array} expectedType - types to cast to. | ||
* @param {ParserRuleContext} ctx - ctx to cast from, if valid. | ||
* | ||
* @returns {String} - visited result, or null on error. | ||
*/ | ||
castType(expectedType, ctx) { | ||
const result = this.visit(ctx); | ||
const typedCtx = this.findTypedNode(ctx); | ||
let type = typedCtx.type; | ||
let equal = this.compareTypes(expectedType, type, ctx, result); | ||
while (equal === null) { | ||
if (type.type === null) { | ||
return null; | ||
let equal = this.compareTypes(expectedType, type, ctx, result); | ||
while (equal === null) { | ||
if (type.type === null) { | ||
return null; | ||
} | ||
type = type.type; | ||
equal = this.compareTypes(expectedType, type, ctx, result); | ||
} | ||
type = type.type; | ||
equal = this.compareTypes(expectedType, type, ctx, result); | ||
return equal; | ||
} | ||
return equal; | ||
} | ||
/** | ||
* Validate each argument against the expected argument types defined in the | ||
* Symbol table. | ||
* | ||
* @param {Array} expected - An array of arrays where each subarray represents | ||
* possible argument types for that index. | ||
* @param {Array} args - empty if no args. | ||
* @param {String} name - The name of the function for error reporting. | ||
* @param {Object} namedArgs - Optional: if named arguments exist, this is the | ||
* mapping of name to default value. | ||
* | ||
* @returns {Array} - Array containing the generated output for each argument. | ||
*/ | ||
checkArguments(expected, args, name, namedArgs) { | ||
const argStr = []; | ||
if (args.length === 0) { | ||
if (expected.length === 0 || expected[0].indexOf(null) !== -1) { | ||
return argStr; | ||
} | ||
throw new BsonTranspilersArgumentError( | ||
`Argument count mismatch: '${name}' requires least one argument` | ||
); | ||
} | ||
if (args.length > expected.length) { | ||
throw new BsonTranspilersArgumentError( | ||
`Argument count mismatch: '${name}' expects ${ | ||
expected.length} args and got ${args.length}` | ||
); | ||
} | ||
for (let i = 0; i < expected.length; i++) { | ||
if (args[i] === undefined) { | ||
if (expected[i].indexOf(null) !== -1) { | ||
/** | ||
* Validate each argument against the expected argument types defined in the | ||
* Symbol table. | ||
* | ||
* @param {Array} expected - An array of arrays where each subarray represents | ||
* possible argument types for that index. | ||
* @param {Array} args - empty if no args. | ||
* @param {String} name - The name of the function for error reporting. | ||
* @param {Object} namedArgs - Optional: if named arguments exist, this is the | ||
* mapping of name to default value. | ||
* | ||
* @returns {Array} - Array containing the generated output for each argument. | ||
*/ | ||
checkArguments(expected, args, name, namedArgs) { | ||
const argStr = []; | ||
if (args.length === 0) { | ||
if (expected.length === 0 || expected[0].indexOf(null) !== -1) { | ||
return argStr; | ||
} | ||
throw new BsonTranspilersArgumentError( | ||
`Argument count mismatch: too few arguments passed to '${name}'` | ||
`Argument count mismatch: '${name}' requires least one argument` | ||
); | ||
} | ||
if (args.length > expected.length) { | ||
throw new BsonTranspilersArgumentError( | ||
`Argument count mismatch: '${name}' expects ${expected.length} args and got ${args.length}` | ||
); | ||
} | ||
for (let i = 0; i < expected.length; i++) { | ||
if (args[i] === undefined) { | ||
if (expected[i].indexOf(null) !== -1) { | ||
return argStr; | ||
} | ||
throw new BsonTranspilersArgumentError( | ||
`Argument count mismatch: too few arguments passed to '${name}'` | ||
); | ||
} | ||
const toCompare = this.checkNamedArgs(expected[i], args[i], namedArgs); | ||
const result = this.castType(...toCompare); | ||
if (result === null) { | ||
const typeStr = expected[i].map((e) => { | ||
const id = e && e.id ? e.id : e; | ||
return e ? id : '[optional]'; | ||
}).join(', '); | ||
const message = `Argument type mismatch: '${name}' expects types ${ | ||
typeStr} but got type ${this.findTypedNode(args[i]).type.id | ||
} for argument at index ${i}`; | ||
const toCompare = this.checkNamedArgs(expected[i], args[i], namedArgs); | ||
const result = this.castType(...toCompare); | ||
if (result === null) { | ||
const typeStr = expected[i] | ||
.map((e) => { | ||
const id = e && e.id ? e.id : e; | ||
return e ? id : '[optional]'; | ||
}) | ||
.join(', '); | ||
const message = `Argument type mismatch: '${name}' expects types ${typeStr} but got type ${ | ||
this.findTypedNode(args[i]).type.id | ||
} for argument at index ${i}`; | ||
throw new BsonTranspilersArgumentError(message); | ||
throw new BsonTranspilersArgumentError(message); | ||
} | ||
argStr.push(result); | ||
} | ||
argStr.push(result); | ||
return argStr; | ||
} | ||
return argStr; | ||
} | ||
/* | ||
* Overriden only by the object generator. | ||
*/ | ||
returnFunctionCallLhs(code, name) { | ||
return name; | ||
} | ||
returnFunctionCallLhsRhs(lhs, rhs, lhsType, l) { | ||
if (lhsType.argsTemplate) { | ||
rhs = lhsType.argsTemplate.bind(this.getState())(l, ...rhs); | ||
} else { | ||
rhs = `(${rhs.join(', ')})`; | ||
/* | ||
* Overriden only by the object generator. | ||
*/ | ||
returnFunctionCallLhs(code, name) { | ||
return name; | ||
} | ||
return `${lhs}${rhs}`; | ||
} | ||
returnAttributeAccess(lhs, rhs, type) { | ||
if (type && type.attr[rhs].template) { | ||
return type.attr[rhs].template(lhs, rhs); | ||
returnFunctionCallLhsRhs(lhs, rhs, lhsType, l) { | ||
if (lhsType.argsTemplate) { | ||
rhs = lhsType.argsTemplate.bind(this.getState())(l, ...rhs); | ||
} else { | ||
rhs = `(${rhs.join(', ')})`; | ||
} | ||
return `${lhs}${rhs}`; | ||
} | ||
return `${lhs}.${rhs}`; | ||
} | ||
returnParenthesis(expr) { | ||
return `(${expr})`; | ||
} | ||
returnSet(args, ctx) { | ||
return this.visitChildren(ctx); | ||
} | ||
/** | ||
* Generate a function call, diverting to process or emit methods if they | ||
* exist. | ||
* @param {ParserRuleContext} ctx | ||
* @return {*} | ||
*/ | ||
generateFunctionCall(ctx) { | ||
const funcNameNode = this.getFunctionCallName(ctx); | ||
const lhs = this.visit(funcNameNode); | ||
let l = lhs; | ||
let lhsType = this.findTypedNode(funcNameNode).type; | ||
if (typeof lhsType === 'string') { | ||
lhsType = this.Types[lhsType]; | ||
returnAttributeAccess(lhs, rhs, type) { | ||
if (type && type.attr[rhs].template) { | ||
return type.attr[rhs].template(lhs, rhs); | ||
} | ||
return `${lhs}.${rhs}`; | ||
} | ||
// Special case | ||
if (`process${lhsType.id}` in this) { | ||
return this[`process${lhsType.id}`](ctx); | ||
returnParenthesis(expr) { | ||
return `(${expr})`; | ||
} | ||
if (`emit${lhsType.id}` in this) { | ||
return this[`emit${lhsType.id}`](ctx); | ||
returnSet(args, ctx) { | ||
return this.visitChildren(ctx); | ||
} | ||
// Check if left-hand-side is callable | ||
ctx.type = lhsType.type; | ||
if (!lhsType.callable) { | ||
throw new BsonTranspilersTypeError(`${lhsType.id} is not callable`); | ||
} | ||
/** | ||
* Generate a function call, diverting to process or emit methods if they | ||
* exist. | ||
* @param {ParserRuleContext} ctx | ||
* @return {*} | ||
*/ | ||
generateFunctionCall(ctx) { | ||
const funcNameNode = this.getFunctionCallName(ctx); | ||
const lhs = this.visit(funcNameNode); | ||
let l = lhs; | ||
let lhsType = this.findTypedNode(funcNameNode).type; | ||
if (typeof lhsType === 'string') { | ||
lhsType = this.Types[lhsType]; | ||
} | ||
// Check arguments | ||
const expectedArgs = lhsType.args; | ||
const rhs = this.checkArguments( | ||
expectedArgs, this.getArguments(ctx), lhsType.id, lhsType.namedArgs | ||
); | ||
// Special case | ||
if (`process${lhsType.id}` in this) { | ||
return this[`process${lhsType.id}`](ctx); | ||
} | ||
if (`emit${lhsType.id}` in this) { | ||
return this[`emit${lhsType.id}`](ctx); | ||
} | ||
// Apply the arguments template | ||
if (lhsType.argsTemplate) { | ||
l = this.visit(this.getIfIdentifier(funcNameNode)); | ||
} | ||
const expr = this.returnFunctionCallLhsRhs(lhs, rhs, lhsType, l); | ||
const constructor = lhsType.callable === this.SYMBOL_TYPE.CONSTRUCTOR; | ||
// Check if left-hand-side is callable | ||
ctx.type = lhsType.type; | ||
if (!lhsType.callable) { | ||
throw new BsonTranspilersTypeError(`${lhsType.id} is not callable`); | ||
} | ||
return this.Syntax.new.template | ||
? this.Syntax.new.template(expr, !constructor, lhsType.code) | ||
: expr; | ||
} | ||
// Check arguments | ||
const expectedArgs = lhsType.args; | ||
const rhs = this.checkArguments( | ||
expectedArgs, | ||
this.getArguments(ctx), | ||
lhsType.id, | ||
lhsType.namedArgs | ||
); | ||
/** | ||
* Visit a symbol and error if undefined. Otherwise check symbol table and | ||
* replace if template exists. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @return {*} | ||
*/ | ||
generateIdentifier(ctx) { | ||
const name = this.visitChildren(ctx); | ||
ctx.type = this.Symbols[name]; | ||
if (ctx.type === undefined) { | ||
throw new BsonTranspilersReferenceError(`Symbol '${name}' is undefined`); | ||
} | ||
this.requiredImports[ctx.type.code] = true; | ||
// Apply the arguments template | ||
if (lhsType.argsTemplate) { | ||
l = this.visit(this.getIfIdentifier(funcNameNode)); | ||
} | ||
const expr = this.returnFunctionCallLhsRhs(lhs, rhs, lhsType, l); | ||
const constructor = lhsType.callable === this.SYMBOL_TYPE.CONSTRUCTOR; | ||
if (ctx.type.template) { | ||
return ctx.type.template(); | ||
return this.Syntax.new.template | ||
? this.Syntax.new.template(expr, !constructor, lhsType.code) | ||
: expr; | ||
} | ||
return this.returnFunctionCallLhs(ctx.type.code, name); | ||
} | ||
/** | ||
* Generate attribute access. Visitors are in charge of making sure that | ||
* if lhs type attribute access is not supported, an error is thrown. | ||
* | ||
* NOTE: If the attribute isn't defined on the lhsType, then it will check the | ||
* lhsType.type to see if defined. It will loop, checking the lhs type's type, | ||
* until the attribute exists or the .type is null. If the type is null, | ||
* and the class is a BSON class, then error. If it is a native type however, | ||
* do not error and just return the original attribute. This is to not annoy | ||
* people with attribute errors in languages where it wouldn't throw anyway. | ||
* It feels better to be strict about BSON than the whole language, but it's | ||
* up for debate. TODO: could set type checking to 'strict' or 'non-strict' in | ||
* the visitor, and then only error if we are compiling from a strictly typed | ||
* language. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @return {*} | ||
*/ | ||
generateAttributeAccess(ctx) { | ||
if ('emitAttributeAccess' in this) { | ||
return this.emitAttributeAccess(ctx); | ||
/** | ||
* Visit a symbol and error if undefined. Otherwise check symbol table and | ||
* replace if template exists. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @return {*} | ||
*/ | ||
generateIdentifier(ctx) { | ||
const name = this.visitChildren(ctx); | ||
ctx.type = this.Symbols[name]; | ||
if (ctx.type === undefined) { | ||
throw new BsonTranspilersReferenceError( | ||
`Symbol '${name}' is undefined` | ||
); | ||
} | ||
this.requiredImports[ctx.type.code] = true; | ||
if (ctx.type.template) { | ||
return ctx.type.template(); | ||
} | ||
return this.returnFunctionCallLhs(ctx.type.code, name); | ||
} | ||
const lhsNode = this.getAttributeLHS(ctx); | ||
const lhs = this.visit(lhsNode); | ||
const rhs = this.getAttributeRHS(ctx).getText(); | ||
let type = this.findTypedNode(lhsNode).type; | ||
if (typeof type === 'string') { | ||
type = this.Types[type]; | ||
} | ||
while (type !== null) { | ||
if (!(type.attr.hasOwnProperty(rhs))) { | ||
if (type.id in this.BsonTypes && this.BsonTypes[type.id].id !== null) { // TODO: tell symbols vs types | ||
throw new BsonTranspilersAttributeError( | ||
`'${rhs}' not an attribute of ${type.id}` | ||
); | ||
/** | ||
* Generate attribute access. Visitors are in charge of making sure that | ||
* if lhs type attribute access is not supported, an error is thrown. | ||
* | ||
* NOTE: If the attribute isn't defined on the lhsType, then it will check the | ||
* lhsType.type to see if defined. It will loop, checking the lhs type's type, | ||
* until the attribute exists or the .type is null. If the type is null, | ||
* and the class is a BSON class, then error. If it is a native type however, | ||
* do not error and just return the original attribute. This is to not annoy | ||
* people with attribute errors in languages where it wouldn't throw anyway. | ||
* It feels better to be strict about BSON than the whole language, but it's | ||
* up for debate. TODO: could set type checking to 'strict' or 'non-strict' in | ||
* the visitor, and then only error if we are compiling from a strictly typed | ||
* language. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @return {*} | ||
*/ | ||
generateAttributeAccess(ctx) { | ||
if ('emitAttributeAccess' in this) { | ||
return this.emitAttributeAccess(ctx); | ||
} | ||
const lhsNode = this.getAttributeLHS(ctx); | ||
const lhs = this.visit(lhsNode); | ||
const rhs = this.getAttributeRHS(ctx).getText(); | ||
let type = this.findTypedNode(lhsNode).type; | ||
if (typeof type === 'string') { | ||
type = this.Types[type]; | ||
} | ||
while (type !== null) { | ||
if (!Object.prototype.hasOwnProperty.call(type.attr, rhs)) { | ||
if ( | ||
type.id in this.BsonTypes && | ||
this.BsonTypes[type.id].id !== null | ||
) { | ||
// TODO: tell symbols vs types | ||
throw new BsonTranspilersAttributeError( | ||
`'${rhs}' not an attribute of ${type.id}` | ||
); | ||
} | ||
type = type.type; | ||
if (typeof type === 'string') { | ||
type = this.Types[type]; | ||
} | ||
} else { | ||
break; | ||
} | ||
type = type.type; | ||
if (typeof type === 'string') { | ||
type = this.Types[type]; | ||
} | ||
} else { | ||
break; | ||
} | ||
} | ||
if (type === null) { | ||
ctx.type = this.Types._undefined; | ||
// TODO: how strict do we want to be? | ||
if (type === null) { | ||
ctx.type = this.Types._undefined; | ||
// TODO: how strict do we want to be? | ||
return this.returnAttributeAccess(lhs, rhs, type); | ||
} | ||
ctx.type = type.attr[rhs]; | ||
return this.returnAttributeAccess(lhs, rhs, type); | ||
} | ||
ctx.type = type.attr[rhs]; | ||
return this.returnAttributeAccess(lhs, rhs, type); | ||
} | ||
/** | ||
* This helper function checks for an emit method then applies the templates | ||
* if they exist for a function call node. Used primarily by process methods. | ||
* | ||
* @param {ParserRuleContext} ctx - The function call node | ||
* @param {Object} lhsType - The type | ||
* @param {Array} args - Arguments to the template | ||
* @param {String} defaultT - The default name if no template exists. | ||
* @param {String} defaultA - The default arguments if no argsTemplate exists. | ||
* @param {Boolean} skipNew - Optional: If true, never add new. | ||
* @param {Boolean} skipLhs - Optional: If true, don't add lhs to result. | ||
* | ||
* @return {*} | ||
*/ | ||
generateCall(ctx, lhsType, args, defaultT, defaultA, skipNew, skipLhs) { | ||
if (`emit${lhsType.id}` in this) { | ||
return this[`emit${lhsType.id}`](ctx); | ||
/** | ||
* This helper function checks for an emit method then applies the templates | ||
* if they exist for a function call node. Used primarily by process methods. | ||
* | ||
* @param {ParserRuleContext} ctx - The function call node | ||
* @param {Object} lhsType - The type | ||
* @param {Array} args - Arguments to the template | ||
* @param {String} defaultT - The default name if no template exists. | ||
* @param {String} defaultA - The default arguments if no argsTemplate exists. | ||
* @param {Boolean} skipNew - Optional: If true, never add new. | ||
* @param {Boolean} skipLhs - Optional: If true, don't add lhs to result. | ||
* | ||
* @return {*} | ||
*/ | ||
generateCall(ctx, lhsType, args, defaultT, defaultA, skipNew, skipLhs) { | ||
if (`emit${lhsType.id}` in this) { | ||
return this[`emit${lhsType.id}`](ctx); | ||
} | ||
const lhsArg = lhsType.template ? lhsType.template() : defaultT; | ||
const rhs = lhsType.argsTemplate | ||
? lhsType.argsTemplate.bind(this.getState())(lhsArg, ...args) | ||
: defaultA; | ||
const lhs = skipLhs ? '' : lhsArg; | ||
return this.Syntax.new.template | ||
? this.Syntax.new.template(`${lhs}${rhs}`, skipNew, lhsType.code) | ||
: `${lhs}${rhs}`; | ||
} | ||
const lhsArg = lhsType.template | ||
? lhsType.template() | ||
: defaultT; | ||
const rhs = lhsType.argsTemplate | ||
? lhsType.argsTemplate.bind(this.getState())(lhsArg, ...args) | ||
: defaultA; | ||
const lhs = skipLhs ? '' : lhsArg; | ||
return this.Syntax.new.template | ||
? this.Syntax.new.template(`${lhs}${rhs}`, skipNew, lhsType.code) | ||
: `${lhs}${rhs}`; | ||
} | ||
generateObjectLiteral(ctx) { | ||
if (this.idiomatic && 'emitIdiomaticObjectLiteral' in this) { | ||
return this.emitIdiomaticObjectLiteral(ctx); | ||
generateObjectLiteral(ctx) { | ||
if (this.idiomatic && 'emitIdiomaticObjectLiteral' in this) { | ||
return this.emitIdiomaticObjectLiteral(ctx); | ||
} | ||
const type = this.Types._object; | ||
if (`emit${type.id}` in this) { | ||
return this[`emit${type.id}`](ctx); | ||
} | ||
ctx.type = type; | ||
this.requiredImports[10] = true; | ||
ctx.indentDepth = this.findIndentDepth(ctx) + 1; | ||
let args = ''; | ||
const keysAndValues = this.getKeyValueList(ctx); | ||
if (ctx.type.argsTemplate) { | ||
args = ctx.type.argsTemplate.bind(this.getState())( | ||
this.getKeyValueList(ctx).map((k) => { | ||
return [this.getKeyStr(k), this.visit(this.getValue(k))]; | ||
}), | ||
ctx.indentDepth | ||
); | ||
} else { | ||
args = this.visit(keysAndValues); | ||
} | ||
ctx.indentDepth--; | ||
if (ctx.type.template) { | ||
return ctx.type.template.bind(this.getState())(args, ctx.indentDepth); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
const type = this.Types._object; | ||
if (`emit${type.id}` in this) { | ||
return this[`emit${type.id}`](ctx); | ||
} | ||
ctx.type = type; | ||
this.requiredImports[10] = true; | ||
ctx.indentDepth = this.findIndentDepth(ctx) + 1; | ||
let args = ''; | ||
const keysAndValues = this.getKeyValueList(ctx); | ||
if (ctx.type.argsTemplate) { | ||
args = ctx.type.argsTemplate.bind(this.getState())( | ||
this.getKeyValueList(ctx).map((k) => { | ||
return [this.getKeyStr(k), this.visit(this.getValue(k))]; | ||
}), | ||
ctx.indentDepth); | ||
} else { | ||
args = this.visit(keysAndValues); | ||
} | ||
ctx.indentDepth--; | ||
if (ctx.type.template) { | ||
return ctx.type.template.bind(this.getState())(args, ctx.indentDepth); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
generateArrayLiteral(ctx) { | ||
const type = this.Types._array; | ||
if (`emit${type.id}` in this) { | ||
return this[`emit${type.id}`](ctx); | ||
generateArrayLiteral(ctx) { | ||
const type = this.Types._array; | ||
if (`emit${type.id}` in this) { | ||
return this[`emit${type.id}`](ctx); | ||
} | ||
ctx.type = type; | ||
ctx.indentDepth = this.findIndentDepth(ctx) + 1; | ||
this.requiredImports[9] = true; | ||
let args = ''; | ||
const list = this.getList(ctx); | ||
const visitedElements = list.map((child) => this.visit(child)); | ||
if (ctx.type.argsTemplate) { | ||
// NOTE: not currently being used anywhere. | ||
args = visitedElements | ||
.map((arg, index) => { | ||
const last = !visitedElements[index + 1]; | ||
return ctx.type.argsTemplate.bind(this.getState())( | ||
arg, | ||
ctx.indentDepth, | ||
last | ||
); | ||
}) | ||
.join(''); | ||
} else { | ||
args = visitedElements.join(', '); | ||
} | ||
if (ctx.type.template) { | ||
return ctx.type.template(args, ctx.indentDepth); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
ctx.type = type; | ||
ctx.indentDepth = this.findIndentDepth(ctx) + 1; | ||
this.requiredImports[9] = true; | ||
let args = ''; | ||
const list = this.getList(ctx); | ||
const visitedElements = list.map((child) => ( this.visit(child) )); | ||
if (ctx.type.argsTemplate) { // NOTE: not currently being used anywhere. | ||
args = visitedElements.map((arg, index) => { | ||
const last = !visitedElements[index + 1]; | ||
return ctx.type.argsTemplate.bind(this.getState())(arg, ctx.indentDepth, last); | ||
}).join(''); | ||
} else { | ||
args = visitedElements.join(', '); | ||
} | ||
if (ctx.type.template) { | ||
return ctx.type.template(args, ctx.indentDepth); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
/** | ||
* Called from the process methods of numeric class constructors. | ||
* We know there will be a single (sometimes optional) argument that is | ||
* a number or string. | ||
* | ||
* Required because we want to pass the argument type to the template | ||
* so that we can determine if the generated number needs to be parsed or | ||
* casted. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @returns {String} | ||
*/ | ||
generateNumericClass(ctx) { | ||
const funcNameNode = this.getFunctionCallName(ctx); | ||
const lhsStr = this.visit(funcNameNode); | ||
let lhsType = this.findTypedNode(funcNameNode).type; | ||
if (typeof lhsType === 'string') { | ||
lhsType = this.Types[lhsType]; | ||
} | ||
ctx.type = lhsType.type; | ||
if (`emit${lhsType.id}` in this) { | ||
this[`emit${lhsType.id}`](ctx); | ||
} | ||
/** | ||
* Called from the process methods of numeric class constructors. | ||
* We know there will be a single (sometimes optional) argument that is | ||
* a number or string. | ||
* | ||
* Required because we want to pass the argument type to the template | ||
* so that we can determine if the generated number needs to be parsed or | ||
* casted. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @returns {String} | ||
*/ | ||
generateNumericClass(ctx) { | ||
const funcNameNode = this.getFunctionCallName(ctx); | ||
const lhsStr = this.visit(funcNameNode); | ||
let lhsType = this.findTypedNode(funcNameNode).type; | ||
if (typeof lhsType === 'string') { | ||
lhsType = this.Types[lhsType]; | ||
} | ||
ctx.type = lhsType.type; | ||
if (`emit${lhsType.id}` in this) { | ||
this[`emit${lhsType.id}`](ctx); | ||
} | ||
// Get the original type of the argument | ||
const expectedArgs = lhsType.args; | ||
let args = this.checkArguments( | ||
expectedArgs, this.getArguments(ctx), lhsType.id, lhsType.namedArgs | ||
); | ||
let argType; | ||
// Get the original type of the argument | ||
const expectedArgs = lhsType.args; | ||
let args = this.checkArguments( | ||
expectedArgs, | ||
this.getArguments(ctx), | ||
lhsType.id, | ||
lhsType.namedArgs | ||
); | ||
let argType; | ||
if (args.length === 0) { | ||
args = ['0']; | ||
argType = this.Types._integer; | ||
} else { | ||
const argNode = this.getArgumentAt(ctx, 0); | ||
const typed = this.findTypedNode(argNode); | ||
argType = typed.originalType !== undefined ? | ||
typed.originalType : | ||
typed.type; | ||
if (args.length === 0) { | ||
args = ['0']; | ||
argType = this.Types._integer; | ||
} else { | ||
const argNode = this.getArgumentAt(ctx, 0); | ||
const typed = this.findTypedNode(argNode); | ||
argType = | ||
typed.originalType !== undefined ? typed.originalType : typed.type; | ||
} | ||
return this.generateCall( | ||
ctx, | ||
lhsType, | ||
[args[0], argType.id], | ||
lhsStr, | ||
`(${args.join(', ')})` | ||
); | ||
} | ||
return this.generateCall( | ||
ctx, lhsType, [args[0], argType.id], lhsStr, `(${args.join(', ')})` | ||
); | ||
} | ||
/** | ||
* Same as generateCall but for type literals instead of function calls. | ||
* | ||
* @param {ParserRuleContext} ctx - The literal node | ||
* @param {Object} lhsType - The type | ||
* @param {Array} args - Arguments to the template | ||
* @param {String} defaultT - The default if no template exists. | ||
* @param {Boolean} skipNew - Optional: If true, never add new. | ||
* | ||
* @return {*} | ||
*/ | ||
generateLiteral(ctx, lhsType, args, defaultT, skipNew) { | ||
if (`emit${lhsType.id}` in this) { | ||
return this[`emit${lhsType.id}`](ctx); | ||
/** | ||
* Same as generateCall but for type literals instead of function calls. | ||
* | ||
* @param {ParserRuleContext} ctx - The literal node | ||
* @param {Object} lhsType - The type | ||
* @param {Array} args - Arguments to the template | ||
* @param {String} defaultT - The default if no template exists. | ||
* @param {Boolean} skipNew - Optional: If true, never add new. | ||
* | ||
* @return {*} | ||
*/ | ||
generateLiteral(ctx, lhsType, args, defaultT, skipNew) { | ||
if (`emit${lhsType.id}` in this) { | ||
return this[`emit${lhsType.id}`](ctx); | ||
} | ||
if (lhsType.template) { | ||
const str = lhsType.template(...args); | ||
return this.Syntax.new.template | ||
? this.Syntax.new.template(str, skipNew, lhsType.code) | ||
: str; | ||
} | ||
return defaultT; | ||
} | ||
if (lhsType.template) { | ||
const str = lhsType.template(...args); | ||
return this.Syntax.new.template | ||
? this.Syntax.new.template(str, skipNew, lhsType.code) | ||
: str; | ||
} | ||
return defaultT; | ||
} | ||
/** | ||
* Helper method for generating literals. Called from the visit methods for | ||
* literal nodes. | ||
* | ||
* @param {Object} setType - the type to set the literal to. | ||
* @param {ParserRuleContext} ctx - the tree node. | ||
* @return {*} | ||
*/ | ||
leafHelper(setType, ctx) { | ||
ctx.type = setType; | ||
this.requiredImports[ctx.type.code] = true; | ||
/** | ||
* Helper method for generating literals. Called from the visit methods for | ||
* literal nodes. | ||
* | ||
* @param {Object} setType - the type to set the literal to. | ||
* @param {ParserRuleContext} ctx - the tree node. | ||
* @return {*} | ||
*/ | ||
leafHelper(setType, ctx) { | ||
ctx.type = setType; | ||
this.requiredImports[ctx.type.code] = true; | ||
// Pass the original argument type to the template, not the casted type. | ||
const parentOriginalType = this.getParentOriginalType(ctx); | ||
const type = parentOriginalType === null ? ctx.type : parentOriginalType; | ||
// Pass the original argument type to the template, not the casted type. | ||
const parentOriginalType = this.getParentOriginalType(ctx); | ||
const type = parentOriginalType === null ? ctx.type : parentOriginalType; | ||
if (`process${ctx.type.id}` in this) { | ||
return this[`process${ctx.type.id}`](ctx); | ||
if (`process${ctx.type.id}` in this) { | ||
return this[`process${ctx.type.id}`](ctx); | ||
} | ||
if (`emit${ctx.type.id}` in this) { | ||
return this[`emit${ctx.type.id}`](ctx); | ||
} | ||
const children = ctx.getText(); | ||
return this.generateLiteral( | ||
ctx, | ||
ctx.type, | ||
[children, type.id], | ||
children, | ||
true | ||
); | ||
} | ||
if (`emit${ctx.type.id}` in this) { | ||
return this[`emit${ctx.type.id}`](ctx); | ||
} | ||
const children = ctx.getText(); | ||
return this.generateLiteral(ctx, ctx.type, [children, type.id], children, true); | ||
} | ||
findIndentDepth(ctx) { | ||
while (ctx.indentDepth === undefined) { | ||
ctx = ctx.parentCtx; | ||
if (ctx === undefined || ctx === null) { | ||
return -1; | ||
findIndentDepth(ctx) { | ||
while (ctx.indentDepth === undefined) { | ||
ctx = ctx.parentCtx; | ||
if (ctx === undefined || ctx === null) { | ||
return -1; | ||
} | ||
} | ||
return ctx.indentDepth; | ||
} | ||
return ctx.indentDepth; | ||
} | ||
/** | ||
* Process required for BSON regex types so we can validate the flags. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {Object} type - The type of the LHS | ||
* @param {Object} symbolType - The type of the Symbol | ||
* @return {*} | ||
*/ | ||
generateBSONRegex(ctx, type, symbolType) { | ||
if (`emit${type.id}` in this) { | ||
return this[`emit${type.id}`](ctx); | ||
} | ||
ctx.type = type; | ||
/** | ||
* Process required for BSON regex types so we can validate the flags. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {Object} type - The type of the LHS | ||
* @param {Object} symbolType - The type of the Symbol | ||
* @return {*} | ||
*/ | ||
generateBSONRegex(ctx, type, symbolType) { | ||
if (`emit${type.id}` in this) { | ||
return this[`emit${type.id}`](ctx); | ||
} | ||
ctx.type = type; | ||
const args = this.checkArguments( | ||
symbolType.args, this.getArguments(ctx), type.id, symbolType.namedArgs | ||
); | ||
const args = this.checkArguments( | ||
symbolType.args, | ||
this.getArguments(ctx), | ||
type.id, | ||
symbolType.namedArgs | ||
); | ||
const expectedFlags = this.Syntax.bsonRegexFlags | ||
? this.Syntax.bsonRegexFlags | ||
: { i: 'i', m: 'm', x: 'x', s: 's', l: 'l', u: 'u' }; | ||
const expectedFlags = this.Syntax.bsonRegexFlags | ||
? this.Syntax.bsonRegexFlags | ||
: { i: 'i', m: 'm', x: 'x', s: 's', l: 'l', u: 'u' }; | ||
let flags = null; | ||
const pattern = args[0]; | ||
if (args.length === 2) { | ||
flags = args[1]; | ||
for (let i = 1; i < flags.length - 1; i++) { | ||
if (!(flags[i] in expectedFlags)) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Invalid flag '${flags[i]}' passed to Regexp` | ||
); | ||
let flags = null; | ||
const pattern = args[0]; | ||
if (args.length === 2) { | ||
flags = args[1]; | ||
for (let i = 1; i < flags.length - 1; i++) { | ||
if (!(flags[i] in expectedFlags)) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Invalid flag '${flags[i]}' passed to Regexp` | ||
); | ||
} | ||
} | ||
flags = flags.replace(/[imxlsu]/g, (m) => expectedFlags[m]); | ||
} | ||
flags = flags.replace(/[imxlsu]/g, m => expectedFlags[m]); | ||
} | ||
return this.generateCall( | ||
ctx, symbolType, [pattern, flags], 'Regex', | ||
`(${pattern}${flags ? ', ' + flags : ''})` | ||
); | ||
} | ||
/** | ||
* Code is processed in every language because want to generate the scope as | ||
* a non-idiomatic document. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {Object} type - The type of the LHS | ||
* @param {Object} symbolType - The type of the Symbol | ||
* @param {boolean} requireString - if the code argument must be a string. | ||
* @return {*} | ||
*/ | ||
generateBSONCode(ctx, type, symbolType, requireString) { | ||
if (`emit${type.id}` in this) { | ||
return this[`emit${type.id}`](ctx); | ||
} | ||
ctx.type = type; | ||
const argList = this.getArguments(ctx); | ||
if (!(argList.length === 1 || argList.length === 2)) { | ||
throw new BsonTranspilersArgumentError( | ||
'Argument count mismatch: Code requires one or two arguments' | ||
return this.generateCall( | ||
ctx, | ||
symbolType, | ||
[pattern, flags], | ||
'Regex', | ||
`(${pattern}${flags ? ', ' + flags : ''})` | ||
); | ||
} | ||
let code = ''; | ||
if (requireString) { | ||
const arg = this.getArgumentAt(ctx, 0); | ||
code = this.visit(arg); | ||
if (this.findTypedNode(arg).type !== this.Types._string) { | ||
/** | ||
* Code is processed in every language because want to generate the scope as | ||
* a non-idiomatic document. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {Object} type - The type of the LHS | ||
* @param {Object} symbolType - The type of the Symbol | ||
* @param {boolean} requireString - if the code argument must be a string. | ||
* @return {*} | ||
*/ | ||
generateBSONCode(ctx, type, symbolType, requireString) { | ||
if (`emit${type.id}` in this) { | ||
return this[`emit${type.id}`](ctx); | ||
} | ||
ctx.type = type; | ||
const argList = this.getArguments(ctx); | ||
if (!(argList.length === 1 || argList.length === 2)) { | ||
throw new BsonTranspilersArgumentError( | ||
'Argument type mismatch: Code requires first argument to be a string' | ||
'Argument count mismatch: Code requires one or two arguments' | ||
); | ||
} | ||
} else { | ||
code = removeQuotes(this.getArgumentAt(ctx, 0).getText()); | ||
} | ||
let scope = undefined; | ||
let scopestr = ''; | ||
let code = ''; | ||
if (requireString) { | ||
const arg = this.getArgumentAt(ctx, 0); | ||
code = this.visit(arg); | ||
if (this.findTypedNode(arg).type !== this.Types._string) { | ||
throw new BsonTranspilersArgumentError( | ||
'Argument type mismatch: Code requires first argument to be a string' | ||
); | ||
} | ||
} else { | ||
code = removeQuotes(this.getArgumentAt(ctx, 0).getText()); | ||
} | ||
let scope = undefined; | ||
let scopestr = ''; | ||
if (argList.length === 2) { | ||
const idiomatic = this.idiomatic; | ||
this.idiomatic = false; | ||
const compareTo = this.checkNamedArgs( | ||
[this.Types._object], this.getArgumentAt(ctx, 1), symbolType.namedArgs | ||
); | ||
scope = this.castType(...compareTo); | ||
if (scope === null) { | ||
throw new BsonTranspilersArgumentError( | ||
'Code expects argument \'scope\' to be object' | ||
if (argList.length === 2) { | ||
const idiomatic = this.idiomatic; | ||
this.idiomatic = false; | ||
const compareTo = this.checkNamedArgs( | ||
[this.Types._object], | ||
this.getArgumentAt(ctx, 1), | ||
symbolType.namedArgs | ||
); | ||
scope = this.castType(...compareTo); | ||
if (scope === null) { | ||
throw new BsonTranspilersArgumentError( | ||
"Code expects argument 'scope' to be object" | ||
); | ||
} | ||
this.idiomatic = idiomatic; | ||
scopestr = `, ${scope}`; | ||
this.requiredImports[113] = true; | ||
this.requiredImports[10] = true; | ||
} | ||
this.idiomatic = idiomatic; | ||
scopestr = `, ${scope}`; | ||
this.requiredImports[113] = true; | ||
this.requiredImports[10] = true; | ||
return this.generateCall( | ||
ctx, | ||
symbolType, | ||
[code, scope], | ||
'Code', | ||
`(${code}${scopestr})` | ||
); | ||
} | ||
return this.generateCall( | ||
ctx, symbolType, [code, scope], 'Code', `(${code}${scopestr})` | ||
); | ||
} | ||
/** | ||
* Gets a process method because need to tell the template if | ||
* the argument is a number or a date. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @returns {String} - generated code | ||
*/ | ||
generateObjectIdFromTime(ctx) { | ||
const funcNameNode = this.getFunctionCallName(ctx); | ||
const lhsStr = this.visit(funcNameNode); | ||
let lhsType = this.findTypedNode(funcNameNode).type; | ||
if (typeof lhsType === 'string') { | ||
lhsType = this.Types[lhsType]; | ||
/** | ||
* Gets a process method because need to tell the template if | ||
* the argument is a number or a date. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @returns {String} - generated code | ||
*/ | ||
generateObjectIdFromTime(ctx) { | ||
const funcNameNode = this.getFunctionCallName(ctx); | ||
const lhsStr = this.visit(funcNameNode); | ||
let lhsType = this.findTypedNode(funcNameNode).type; | ||
if (typeof lhsType === 'string') { | ||
lhsType = this.Types[lhsType]; | ||
} | ||
const args = this.checkArguments( | ||
lhsType.args, | ||
this.getArguments(ctx), | ||
lhsType.id, | ||
lhsType.namedArgs | ||
); | ||
const isNumber = | ||
this.findTypedNode(this.getArgumentAt(ctx, 0)).type.code !== 200; | ||
return this.generateCall( | ||
ctx, | ||
lhsType, | ||
[args[0], isNumber], | ||
lhsStr, | ||
`(${args.join(', ')})`, | ||
true | ||
); | ||
} | ||
const args = this.checkArguments( | ||
lhsType.args, this.getArguments(ctx), lhsType.id, lhsType.namedArgs | ||
); | ||
const isNumber = this.findTypedNode( | ||
this.getArgumentAt(ctx, 0)).type.code !== 200; | ||
return this.generateCall( | ||
ctx, lhsType, [args[0], isNumber], lhsStr, `(${args.join(', ')})`, true | ||
); | ||
} | ||
generateFuncDefExpression() { | ||
throw new BsonTranspilersUnimplementedError( | ||
'Support for exporting functions to languages other than javascript is not yet available.' | ||
); | ||
} | ||
generateFuncDefExpression() { | ||
throw new BsonTranspilersUnimplementedError( | ||
'Support for exporting functions to languages other than javascript is not yet available.' | ||
); | ||
} | ||
/** | ||
* Overrides the ANTLR visitChildren method so that options can be set. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {Object} options: | ||
* start - child index to start iterating at. | ||
* end - child index to end iterating after. | ||
* step - how many children to increment each step, 1 visits all children. | ||
* separator - a string separator to go between generated children. | ||
* ignore - an array of child indexes to skip. | ||
* children - the set of children to visit. | ||
* @returns {String} | ||
*/ | ||
visitChildren(ctx, options) { | ||
const opts = { | ||
start: 0, | ||
step: 1, | ||
separator: '', | ||
ignore: [], | ||
children: ctx.children, | ||
}; | ||
Object.assign(opts, options ? options : {}); | ||
opts.end = 'end' in opts ? opts.end : opts.children.length - 1; | ||
/** | ||
* Overrides the ANTLR visitChildren method so that options can be set. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {Object} options: | ||
* start - child index to start iterating at. | ||
* end - child index to end iterating after. | ||
* step - how many children to increment each step, 1 visits all children. | ||
* separator - a string separator to go between generated children. | ||
* ignore - an array of child indexes to skip. | ||
* children - the set of children to visit. | ||
* @returns {String} | ||
*/ | ||
visitChildren(ctx, options) { | ||
const opts = { | ||
start: 0, step: 1, separator: '', ignore: [], children: ctx.children | ||
}; | ||
Object.assign(opts, options ? options : {}); | ||
opts.end = ('end' in opts) ? opts.end : opts.children.length - 1; | ||
let code = ''; | ||
for (let i = opts.start; i <= opts.end; i += opts.step) { | ||
if (opts.ignore.indexOf(i) === -1) { | ||
code = `${code}${this.visit(opts.children[i])}${ | ||
i === opts.end ? '' : opts.separator | ||
}`; | ||
} | ||
} | ||
return code; | ||
} | ||
let code = ''; | ||
for (let i = opts.start; i <= opts.end; i += opts.step) { | ||
if (opts.ignore.indexOf(i) === -1) { | ||
code = `${code}${this.visit( | ||
opts.children[i] | ||
)}${(i === opts.end) ? '' : opts.separator}`; | ||
/** | ||
* Visit a end-of-file symbol. Universal for all grammars. | ||
* * | ||
* @returns {String} | ||
*/ | ||
visitEof() { | ||
if (this.Syntax.eof.template) { | ||
return this.Syntax.eof.template(); | ||
} | ||
return ''; | ||
} | ||
return code; | ||
} | ||
/** | ||
* Visit a end-of-file symbol. Universal for all grammars. | ||
* * | ||
* @returns {String} | ||
*/ | ||
visitEof() { | ||
if (this.Syntax.eof.template) { | ||
return this.Syntax.eof.template(); | ||
/** | ||
* Visit a end-of-line symbol. Universal for all grammars. | ||
* * | ||
* @returns {String} | ||
*/ | ||
visitEos() { | ||
if (this.Syntax.eos.template) { | ||
return this.Syntax.eos.template(); | ||
} | ||
return '\n'; | ||
} | ||
return ''; | ||
} | ||
/** | ||
* Visit a end-of-line symbol. Universal for all grammars. | ||
* * | ||
* @returns {String} | ||
*/ | ||
visitEos() { | ||
if (this.Syntax.eos.template) { | ||
return this.Syntax.eos.template(); | ||
/** | ||
* Visit a leaf node and return a string. Universal for all grammars. | ||
* * | ||
* @param {ParserRuleContext} ctx | ||
* @returns {String} | ||
*/ | ||
visitTerminal(ctx) { | ||
return ctx.getText(); | ||
} | ||
return '\n'; | ||
} | ||
/** | ||
* Visit a leaf node and return a string. Universal for all grammars. | ||
* * | ||
* @param {ParserRuleContext} ctx | ||
* @returns {String} | ||
*/ | ||
visitTerminal(ctx) { | ||
return ctx.getText(); | ||
} | ||
}; | ||
}; |
@@ -0,8 +1,10 @@ | ||
'use strict'; | ||
/* | ||
* Class for handling edge cases for csharp code generation. Defines "emit" methods. | ||
*/ | ||
module.exports = (Visitor) => class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; | ||
module.exports = (Visitor) => | ||
class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/** | ||
@@ -45,3 +46,5 @@ * Stores declarations for use in the DriverTemplate | ||
for (var i = 0; i < existing.length; i++) { | ||
const candidate = `${this.varTemplateRoot(templateID, varRoot)}${i > 0 ? i : ''}`; | ||
const candidate = `${this.varTemplateRoot(templateID, varRoot)}${ | ||
i > 0 ? i : '' | ||
}`; | ||
const current = this.vars[declaration(candidate)]; | ||
@@ -56,3 +59,5 @@ if (current !== undefined) { | ||
const varTemplateRoot = this.varTemplateRoot(templateID, varRoot); | ||
return Object.values(this.vars).filter(varName => varName.startsWith(varTemplateRoot)); | ||
return Object.values(this.vars).filter((varName) => | ||
varName.startsWith(varTemplateRoot) | ||
); | ||
} | ||
@@ -59,0 +64,0 @@ |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
const antlr4 = require('antlr4'); | ||
@@ -22,3 +23,8 @@ | ||
syntaxError(recognizer, symbol, line, column, message, payload) { | ||
throw new BsonTranspilersSyntaxError(message, { symbol, line, column, payload }); | ||
throw new BsonTranspilersSyntaxError(message, { | ||
symbol, | ||
line, | ||
column, | ||
payload, | ||
}); | ||
} | ||
@@ -25,0 +31,0 @@ } |
@@ -0,6 +1,10 @@ | ||
'use strict'; | ||
/* | ||
* Class for handling edge cases for Go code generation. Defines "emit" methods. | ||
*/ | ||
module.exports = (Visitor) => class Generator extends Visitor { | ||
constructor() { super(); } | ||
}; | ||
module.exports = (Visitor) => | ||
class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; |
@@ -0,6 +1,7 @@ | ||
'use strict'; | ||
/* eslint complexity: 0 */ | ||
const {doubleQuoteStringify, removeQuotes} = require('../../helper/format'); | ||
const { doubleQuoteStringify, removeQuotes } = require('../../helper/format'); | ||
const { | ||
BsonTranspilersRuntimeError, | ||
BsonTranspilersUnimplementedError | ||
BsonTranspilersUnimplementedError, | ||
} = require('../../helper/error'); | ||
@@ -11,672 +12,784 @@ | ||
*/ | ||
module.exports = (Visitor) => class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
// Operations that take the field name as an argument | ||
this.field_opts = [ | ||
'gt', 'lt', 'lte', 'gte', 'eq', 'ne', 'nin', 'in', 'not', 'exists', | ||
'type', 'all', 'size', 'elemMatch', 'mod', 'regex', | ||
'sum', 'avg', 'first', 'last', 'max', 'min', 'push', 'addToSet', | ||
'stdDevSamp', 'stdDevPop', | ||
'bitsAllSet', 'bitsAllClear', 'bitsAnySet', 'bitsAnyClear', | ||
'geoWithin', 'geoIntersects', 'near', 'nearSphere' | ||
]; | ||
// Operations that convert by {$op: value} => op(value) | ||
this.opts = [ | ||
'match', 'skip', 'limit', 'out', 'sortByCount', 'count', 'or', 'nor', | ||
'and' | ||
]; | ||
// Operations split by their import class | ||
this.builderImports = [ | ||
// Filter ops | ||
[ | ||
'all', 'and', 'bitsAllClear', 'bitsAllSet', 'bitsAnyClear', 'bitsAnySet', | ||
'elemMatch', 'eq', 'exists', 'expr', 'geoIntersects', 'geoWithin', | ||
'geoWithinBox', 'geoWithinCenter', 'geoWithinCenterSphere', 'geoWithinPolygon', | ||
'gt', 'gte', 'in', 'lt', 'lte', 'mod', 'ne', 'near', 'nearSphere', 'nin', | ||
'nor', 'not', 'or', 'regex', 'size', 'text', 'type', 'where', 'options' | ||
], | ||
// Agg ops | ||
[ | ||
'addFields', 'bucket', 'bucketAuto', 'count', 'facet', 'graphLookup', | ||
'group', 'limit', 'lookup', 'match', 'out', 'project', 'replaceRoot', | ||
'sample', 'skip', 'sort', 'sortByCount', 'unwind' | ||
], | ||
// Accumulator ops | ||
[ | ||
'addToSet', 'avg', 'first', 'last', 'max', 'min', 'push', | ||
'stdDevPop', 'stdDevSamp', 'sum' | ||
] | ||
].reduce((obj, list, index) => { | ||
list.forEach((op) => { | ||
obj[op] = index + 300; | ||
}); | ||
return obj; | ||
}, {}); | ||
} | ||
module.exports = (Visitor) => | ||
class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
// Operations that take the field name as an argument | ||
this.field_opts = [ | ||
'gt', | ||
'lt', | ||
'lte', | ||
'gte', | ||
'eq', | ||
'ne', | ||
'nin', | ||
'in', | ||
'not', | ||
'exists', | ||
'type', | ||
'all', | ||
'size', | ||
'elemMatch', | ||
'mod', | ||
'regex', | ||
'sum', | ||
'avg', | ||
'first', | ||
'last', | ||
'max', | ||
'min', | ||
'push', | ||
'addToSet', | ||
'stdDevSamp', | ||
'stdDevPop', | ||
'bitsAllSet', | ||
'bitsAllClear', | ||
'bitsAnySet', | ||
'bitsAnyClear', | ||
'geoWithin', | ||
'geoIntersects', | ||
'near', | ||
'nearSphere', | ||
]; | ||
// Operations that convert by {$op: value} => op(value) | ||
this.opts = [ | ||
'match', | ||
'skip', | ||
'limit', | ||
'out', | ||
'sortByCount', | ||
'count', | ||
'or', | ||
'nor', | ||
'and', | ||
]; | ||
// Operations split by their import class | ||
this.builderImports = [ | ||
// Filter ops | ||
[ | ||
'all', | ||
'and', | ||
'bitsAllClear', | ||
'bitsAllSet', | ||
'bitsAnyClear', | ||
'bitsAnySet', | ||
'elemMatch', | ||
'eq', | ||
'exists', | ||
'expr', | ||
'geoIntersects', | ||
'geoWithin', | ||
'geoWithinBox', | ||
'geoWithinCenter', | ||
'geoWithinCenterSphere', | ||
'geoWithinPolygon', | ||
'gt', | ||
'gte', | ||
'in', | ||
'lt', | ||
'lte', | ||
'mod', | ||
'ne', | ||
'near', | ||
'nearSphere', | ||
'nin', | ||
'nor', | ||
'not', | ||
'or', | ||
'regex', | ||
'size', | ||
'text', | ||
'type', | ||
'where', | ||
'options', | ||
], | ||
// Agg ops | ||
[ | ||
'addFields', | ||
'bucket', | ||
'bucketAuto', | ||
'count', | ||
'facet', | ||
'graphLookup', | ||
'group', | ||
'limit', | ||
'lookup', | ||
'match', | ||
'out', | ||
'project', | ||
'replaceRoot', | ||
'sample', | ||
'skip', | ||
'sort', | ||
'sortByCount', | ||
'unwind', | ||
], | ||
// Accumulator ops | ||
[ | ||
'addToSet', | ||
'avg', | ||
'first', | ||
'last', | ||
'max', | ||
'min', | ||
'push', | ||
'stdDevPop', | ||
'stdDevSamp', | ||
'sum', | ||
], | ||
].reduce((obj, list, index) => { | ||
list.forEach((op) => { | ||
obj[op] = index + 300; | ||
}); | ||
return obj; | ||
}, {}); | ||
} | ||
/** The rest of the functions in this file are for generating builders **/ | ||
/** The rest of the functions in this file are for generating builders **/ | ||
/** | ||
* Emit an "idiomatic" filter or aggregation, meaning use the builders | ||
* instead of a regular object if possible. | ||
* | ||
* @param {ObjectLiteralContext} ctx | ||
* @return {String} | ||
*/ | ||
emitIdiomaticObjectLiteral(ctx) { | ||
ctx.type = this.Types._object; | ||
ctx.indentDepth = this.findIndentDepth(ctx) + 1; | ||
let multiOps = false; | ||
let args = ''; | ||
const properties = this.getKeyValueList(ctx); | ||
if (properties.length) { | ||
args = properties.map((pair) => { | ||
const field = this.getKeyStr(pair); | ||
const value = this.getValue(pair); | ||
if (field.startsWith('$')) { | ||
const op = field.substr(1); | ||
if (this.builderImports[op]) { | ||
this.requiredImports[this.builderImports[op]].push(op); | ||
} | ||
if (op === 'regex') { | ||
multiOps = true; | ||
} | ||
if (`handle${op}` in this) { | ||
return this[`handle${op}`](this.getObjectChild(value), op, ctx); | ||
} | ||
if (this.field_opts.indexOf(op) !== -1) { | ||
// Assert that this isn't the top-level object | ||
if (!this.isSubObject(ctx)) { | ||
throw new BsonTranspilersRuntimeError(`$${op} cannot be top-level`); | ||
/** | ||
* Emit an "idiomatic" filter or aggregation, meaning use the builders | ||
* instead of a regular object if possible. | ||
* | ||
* @param {ObjectLiteralContext} ctx | ||
* @return {String} | ||
*/ | ||
emitIdiomaticObjectLiteral(ctx) { | ||
ctx.type = this.Types._object; | ||
ctx.indentDepth = this.findIndentDepth(ctx) + 1; | ||
let multiOps = false; | ||
let args = ''; | ||
const properties = this.getKeyValueList(ctx); | ||
if (properties.length) { | ||
args = properties.map((pair) => { | ||
const field = this.getKeyStr(pair); | ||
const value = this.getValue(pair); | ||
if (field.startsWith('$')) { | ||
const op = field.substr(1); | ||
if (this.builderImports[op]) { | ||
this.requiredImports[this.builderImports[op]].push(op); | ||
} | ||
return this.handleFieldOp(value, op, ctx); | ||
if (op === 'regex') { | ||
multiOps = true; | ||
} | ||
if (`handle${op}` in this) { | ||
return this[`handle${op}`](this.getObjectChild(value), op, ctx); | ||
} | ||
if (this.field_opts.indexOf(op) !== -1) { | ||
// Assert that this isn't the top-level object | ||
if (!this.isSubObject(ctx)) { | ||
throw new BsonTranspilersRuntimeError( | ||
`$${op} cannot be top-level` | ||
); | ||
} | ||
return this.handleFieldOp(value, op, ctx); | ||
} | ||
if (this.opts.indexOf(op) !== -1) { | ||
return `${field.substr(1)}(${this.visit(value)})`; | ||
} | ||
} | ||
if (this.opts.indexOf(op) !== -1) { | ||
return `${field.substr(1)}(${this.visit(value)})`; | ||
const valueStr = this.visit(value); | ||
// $-op filters need to rewind a level | ||
const child = this.getObjectChild(value); | ||
if (this.isFilter(child)) { | ||
return valueStr; | ||
} | ||
this.requiredImports[300].push('eq'); | ||
return `eq(${doubleQuoteStringify(field)}, ${valueStr})`; | ||
}); | ||
if (args.length > 1 && !multiOps) { | ||
this.requiredImports[300].push('and'); | ||
return `and(${args.join(', ')})`; | ||
} | ||
const valueStr = this.visit(value); | ||
// $-op filters need to rewind a level | ||
const child = this.getObjectChild(value); | ||
if (this.isFilter(child)) { | ||
return valueStr; | ||
return args[0]; | ||
} | ||
this.requiredImports[10] = true; | ||
return 'new Document()'; | ||
} | ||
/** | ||
* Generates idiomatic java for a $-operator that takes the field name | ||
* as the first argument. i.e. { field: { $op: value } } => op(field, value) | ||
* | ||
* @param {ObjectLiteralContext} ctx - The field of the $-op | ||
* @param {String} op - The $-op | ||
* @param {ObjectLiteralContext} parent - The parent object's ctx | ||
* @returns {String} | ||
*/ | ||
handleFieldOp(ctx, op, parent) { | ||
const parentField = this.getParentKeyStr(parent); | ||
return `${op}(${doubleQuoteStringify(parentField)}, ${this.visit(ctx)})`; | ||
} | ||
/** | ||
* Determines if an object has a subfield that is a $-op. | ||
* | ||
* @param {ObjectLiteralContext} ctx - The field of the $-op | ||
* @return {Boolean} | ||
*/ | ||
isFilter(ctx) { | ||
const properties = this.getKeyValueList(ctx); | ||
for (let i = 0; i < properties.length; i++) { | ||
const pair = properties[i]; | ||
const field = this.getKeyStr(pair); | ||
if (this.field_opts.indexOf(field.substr(1)) !== -1) { | ||
return true; | ||
} | ||
this.requiredImports[300].push('eq'); | ||
return `eq(${doubleQuoteStringify(field)}, ${valueStr})`; | ||
} | ||
return false; | ||
} | ||
/** | ||
* Generates idiomatic java for a $-operator that requires a document that has | ||
* a single subfield whose value gets set to the builder argument. | ||
* { $op: { $subfield: value } } => op(value) | ||
* | ||
* @param {ObjectLiteralContext} ctx - The field of the $-op | ||
* @param {String} op - The name of the $-op. | ||
* @param {String} subfield - The name of the subfield to require. | ||
* @param {Boolean} idiomatic - If the value should be generated as idiomatic. | ||
* @return {String} | ||
*/ | ||
handleSingleSubfield(ctx, op, subfield, idiomatic) { | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
let value = ''; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
if (field === subfield) { | ||
this.idiomatic = idiomatic; | ||
value = this.visit(this.getValue(pair)); | ||
this.idiomatic = true; | ||
} else { | ||
throw new BsonTranspilersRuntimeError( | ||
`Unrecognized option to $${op}: ${field}` | ||
); | ||
} | ||
}); | ||
if (args.length > 1 && !multiOps) { | ||
this.requiredImports[300].push('and'); | ||
return `and(${args.join(', ')})`; | ||
if (value === '') { | ||
throw new BsonTranspilersRuntimeError( | ||
`Missing option '${subfield}' in $${op}` | ||
); | ||
} | ||
return args[0]; | ||
return `${op}(${value})`; | ||
} | ||
this.requiredImports[10] = true; | ||
return 'new Document()'; | ||
} | ||
/** | ||
* Generates idiomatic java for a $-operator that takes the field name | ||
* as the first argument. i.e. { field: { $op: value } } => op(field, value) | ||
* | ||
* @param {ObjectLiteralContext} ctx - The field of the $-op | ||
* @param {String} op - The $-op | ||
* @param {ObjectLiteralContext} parent - The parent object's ctx | ||
* @returns {String} | ||
*/ | ||
handleFieldOp(ctx, op, parent) { | ||
const parentField = this.getParentKeyStr(parent); | ||
return `${op}(${doubleQuoteStringify(parentField)}, ${this.visit(ctx)})`; | ||
} | ||
/** | ||
* Generates idiomatic java for a $-operator that has some required options | ||
* and some options that get rolled into an Options object. | ||
* | ||
* { $op: { required: reqVal, optional: optionalVal } => | ||
* op(reqVal, new Options.optional()) | ||
* | ||
* @param {ObjectLiteralContext} ctx - The field of the $-op | ||
* @param {String} op - The name of the $-op. | ||
* @param {Array} reqOpts - The list of required options. | ||
* @param {Array} optionalOpts - The list of optional options. | ||
* @param {Object} transforms - An mapping of original name to transformed | ||
* name. Includes both optional options and the Options object. | ||
* @return {string} | ||
*/ | ||
handleOptionsObject(ctx, op, reqOpts, optionalOpts, transforms) { | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
const fields = {}; | ||
/** | ||
* Determines if an object has a subfield that is a $-op. | ||
* | ||
* @param {ObjectLiteralContext} ctx - The field of the $-op | ||
* @return {Boolean} | ||
*/ | ||
isFilter(ctx) { | ||
const properties = this.getKeyValueList(ctx); | ||
for (let i = 0; i < properties.length; i++) { | ||
const pair = properties[i]; | ||
const field = this.getKeyStr(pair); | ||
if (this.field_opts.indexOf(field.substr(1)) !== -1) { | ||
return true; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
if ( | ||
reqOpts.indexOf(field) !== -1 || | ||
optionalOpts.indexOf(field) !== -1 | ||
) { | ||
fields[field] = this.visit(this.getValue(pair)); | ||
} else { | ||
throw new BsonTranspilersRuntimeError( | ||
`Unrecognized option to $${op}: ${field}` | ||
); | ||
} | ||
}); | ||
reqOpts.map((f) => { | ||
if (!(f in fields)) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Missing option '${f}' in $${op}` | ||
); | ||
} | ||
}); | ||
let options = ''; | ||
if (Object.keys(fields).length > reqOpts.length) { | ||
this.requiredImports[306].push(transforms[op]); | ||
options = `, new ${transforms[op]}()${Object.keys(fields) | ||
.filter((f) => { | ||
return optionalOpts.indexOf(f) !== -1; | ||
}) | ||
.map((k) => { | ||
if (transforms !== undefined && k in transforms) { | ||
return transforms[k](fields[k]); | ||
} | ||
return `.${k}(${fields[k]})`; | ||
}) | ||
.join('')}`; | ||
} | ||
return `${op}(${reqOpts | ||
.map((f) => { | ||
return fields[f]; | ||
}) | ||
.join(', ')}${options})`; | ||
} | ||
return false; | ||
} | ||
/** | ||
* Generates idiomatic java for a $-operator that requires a document that has | ||
* a single subfield whose value gets set to the builder argument. | ||
* { $op: { $subfield: value } } => op(value) | ||
* | ||
* @param {ObjectLiteralContext} ctx - The field of the $-op | ||
* @param {String} op - The name of the $-op. | ||
* @param {String} subfield - The name of the subfield to require. | ||
* @param {Boolean} idiomatic - If the value should be generated as idiomatic. | ||
* @return {String} | ||
*/ | ||
handleSingleSubfield(ctx, op, subfield, idiomatic) { | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
let value = ''; | ||
/** | ||
* Generates idiomatic java for a $-operator that has some required options | ||
* and then multiple arbitrary fields. | ||
* | ||
* { $op: { required: reqVal, opt1: v1, opt2: v2...} } => op(reqVal, v1, v2...) | ||
* @param {ObjectLiteralContext} ctx - The field of the $-op | ||
* @param {String} op - The name of the $-op. | ||
* @param {Array} reqOpts - The list of required options. | ||
* @param {Function} transform - A function that takes in the option name and | ||
* the value, then returns a string with the correct formatting. | ||
* @param {Boolean} idiomatic - If the value should be generated as idiomatic. | ||
* @return {string} | ||
*/ | ||
handleMultipleSubfields(ctx, op, reqOpts, transform, idiomatic) { | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
const req = []; | ||
const fields = {}; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
if (field === subfield) { | ||
this.idiomatic = idiomatic; | ||
value = this.visit(this.getValue(pair)); | ||
this.idiomatic = true; | ||
} else { | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
if (reqOpts.indexOf(field) !== -1) { | ||
req.push(this.visit(this.getValue(pair))); | ||
} else { | ||
this.idiomatic = idiomatic; | ||
fields[field] = this.visit(this.getValue(pair)); | ||
this.idiomatic = true; | ||
} | ||
}); | ||
if (req.length !== reqOpts.length) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Unrecognized option to $${op}: ${field}` | ||
`Required option missing from ${op}` | ||
); | ||
} | ||
}); | ||
if (value === '') { | ||
throw new BsonTranspilersRuntimeError( | ||
`Missing option '${subfield}' in $${op}` | ||
const args = req.concat( | ||
Object.keys(fields).map((f) => { | ||
return transform(f, fields[f]); | ||
}) | ||
); | ||
return `${op}(${args.join(', ')})`; | ||
} | ||
return `${op}(${value})`; | ||
} | ||
/** | ||
* Generates idiomatic java for a $-operator that has some required options | ||
* and some options that get rolled into an Options object. | ||
* | ||
* { $op: { required: reqVal, optional: optionalVal } => | ||
* op(reqVal, new Options.optional()) | ||
* | ||
* @param {ObjectLiteralContext} ctx - The field of the $-op | ||
* @param {String} op - The name of the $-op. | ||
* @param {Array} reqOpts - The list of required options. | ||
* @param {Array} optionalOpts - The list of optional options. | ||
* @param {Object} transforms - An mapping of original name to transformed | ||
* name. Includes both optional options and the Options object. | ||
* @return {string} | ||
*/ | ||
handleOptionsObject(ctx, op, reqOpts, optionalOpts, transforms) { | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
const fields = {}; | ||
/** | ||
* Method for handling an idiomatic $project. | ||
* ctx must be a non-empty document. | ||
* | ||
* @param {ObjectLiteralContext} ctx | ||
* @return {String} | ||
*/ | ||
handleproject(ctx) { | ||
// Eventual todo: slice and elemMatch | ||
const properties = this.assertIsNonemptyObject(ctx, 'project'); | ||
const fields = {}; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
if (reqOpts.indexOf(field) !== -1 || optionalOpts.indexOf(field) !== -1) { | ||
fields[field] = this.visit(this.getValue(pair)); | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
const original = this.getValue(pair).getText(); | ||
if (original.toLowerCase() === 'true' || original === '1') { | ||
if (field !== '_id') { | ||
// Skip because ID is included by default | ||
fields.includes = !fields.includes | ||
? `include(${doubleQuoteStringify(field)}` | ||
: `${fields.includes}, ${doubleQuoteStringify(field)}`; | ||
this.requiredImports[303].push('include'); | ||
} | ||
} else if (original.toLowerCase() === 'false' || original === '0') { | ||
if (field !== '_id') { | ||
fields.excludes = !fields.excludes | ||
? `exclude(${doubleQuoteStringify(field)}` | ||
: `${fields.excludes}, ${doubleQuoteStringify(field)}`; | ||
this.requiredImports[303].push('exclude'); | ||
} else { | ||
fields.excludeId = 'excludeId()'; | ||
this.requiredImports[303].push('excludeId'); | ||
} | ||
} else { | ||
const value = this.visit(this.getValue(pair)); | ||
fields.computed = !fields.computed | ||
? `computed(${doubleQuoteStringify(field)}, ${value})` | ||
: `${fields.computed}, computed(${doubleQuoteStringify( | ||
field | ||
)}, ${value})`; | ||
this.requiredImports[303].push('computed'); | ||
} | ||
}); | ||
if (fields.includes) { | ||
fields.includes = `${fields.includes})`; | ||
} | ||
if (fields.excludes) { | ||
fields.excludes = `${fields.excludes})`; | ||
} | ||
const elements = Object.values(fields); | ||
let projectStr; | ||
if (elements.length === 1) { | ||
projectStr = elements[0]; | ||
} else { | ||
projectStr = `fields(${elements.join(', ')})`; | ||
this.requiredImports[303].push('fields'); | ||
} | ||
return `project(${projectStr})`; | ||
} | ||
/** | ||
* Method for handling an idiomatic $not. | ||
* | ||
* { field: { $not: {$op: value} } } => not(op(field, value)) | ||
* | ||
* ctx must be a non-empty document. | ||
* | ||
* @param {ObjectLiteralExpressionContext} ctx - the ctx of the value of the | ||
* $not field | ||
* @param {String} op - the operation, which in this case is "not" | ||
* @param {ObjectLiteralExpressionContext} parent - ctx of parent document. | ||
* @return {String} | ||
*/ | ||
handlenot(ctx, op, parent) { | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
const val = this.getValue(properties[0]); | ||
const innerop = this.getKeyStr(properties[0]).substr(1); | ||
this.requiredImports[300].push(innerop); | ||
const inner = this.handleFieldOp(val, innerop, parent); | ||
return `${op}(${inner})`; | ||
} | ||
/** | ||
* Method for handling an idiomatic $mod. | ||
* | ||
* { field: { $mod: [arr1, arr2] } } => mod(field, arr1, arr2) | ||
* | ||
* ctx must be an array of length 2. | ||
* | ||
* @param {ObjectLiteralExpressionContext} ctx - the ctx of the value of the | ||
* $mod field | ||
* @param {String} op - the operation, which in this case is "mod" | ||
* @param {ObjectLiteralExpressionContext} parent - ctx of parent document. | ||
* @return {String} | ||
*/ | ||
handlemod(ctx, op, parent) { | ||
const list = this.getList(ctx); | ||
if (list.length !== 2) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Unrecognized option to $${op}: ${field}` | ||
'$mod requires an array of 2-elements' | ||
); | ||
} | ||
}); | ||
reqOpts.map((f) => { | ||
if (!(f in fields)) { | ||
throw new BsonTranspilersRuntimeError(`Missing option '${f}' in $${op}`); | ||
} | ||
}); | ||
const parentField = this.getParentKeyStr(parent); | ||
const inner = list.map((f) => { | ||
return this.visit(f); | ||
}); | ||
return `${op}(${doubleQuoteStringify(parentField)}, ${inner.join(', ')})`; | ||
} | ||
let options = ''; | ||
if (Object.keys(fields).length > reqOpts.length) { | ||
this.requiredImports[306].push(transforms[op]); | ||
/** | ||
* Method for handling an idiomatic $regex. | ||
* | ||
* { field: { $regex: regexstr, $options?: optsstr } } => | ||
* regex(regexstr, optsstr?) | ||
* | ||
* ctx must be a string | ||
* | ||
* @param {ObjectLiteralExpressionContext} ctx - the ctx of the value of the | ||
* $regex field | ||
* @param {String} op - the operation, which in this case is "regex" | ||
* @param {ObjectLiteralExpressionContext} parent - ctx of parent document. | ||
* @return {String} | ||
*/ | ||
handleregex(ctx, op, parent) { | ||
const parentField = this.getParentKeyStr(parent); | ||
const regex = { r: '', o: '' }; | ||
options = `, new ${transforms[op]}()${Object.keys(fields).filter((f) => { | ||
return optionalOpts.indexOf(f) !== -1; | ||
}).map((k) => { | ||
if (transforms !== undefined && k in transforms) { | ||
return transforms[k](fields[k]); | ||
const properties = this.getKeyValueList(parent); | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
if (field === '$regex') { | ||
regex.r = this.visit(this.getValue(pair)); | ||
} | ||
return `.${k}(${fields[k]})`; | ||
}).join('')}`; | ||
if (field === '$options') { | ||
regex.o = `, ${this.visit(this.getValue(pair))}`; | ||
} | ||
}); | ||
return `${op}(${doubleQuoteStringify(parentField)}, ${regex.r}${ | ||
regex.o | ||
})`; | ||
} | ||
handleoptions() { | ||
return ''; | ||
} | ||
return `${op}(${reqOpts.map((f) => { | ||
return fields[f]; | ||
}).join(', ')}${options})`; | ||
} | ||
/** | ||
* Generates idiomatic java for a $-operator that has some required options | ||
* and then multiple arbitrary fields. | ||
* | ||
* { $op: { required: reqVal, opt1: v1, opt2: v2...} } => op(reqVal, v1, v2...) | ||
* @param {ObjectLiteralContext} ctx - The field of the $-op | ||
* @param {String} op - The name of the $-op. | ||
* @param {Array} reqOpts - The list of required options. | ||
* @param {Function} transform - A function that takes in the option name and | ||
* the value, then returns a string with the correct formatting. | ||
* @param {Boolean} idiomatic - If the value should be generated as idiomatic. | ||
* @return {string} | ||
*/ | ||
handleMultipleSubfields(ctx, op, reqOpts, transform, idiomatic) { | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
const req = []; | ||
const fields = {}; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
if (reqOpts.indexOf(field) !== -1) { | ||
req.push(this.visit(this.getValue(pair))); | ||
/** | ||
* Method for handling an idiomatic $where. | ||
* | ||
* { $where: <function def> } => where(<function as string>) | ||
* | ||
* @param {ObjectLiteralExpressionContext} ctx - the ctx of the value of the | ||
* $where field | ||
* @return {String} | ||
*/ | ||
handlewhere(ctx) { | ||
let text; | ||
if (!('getParent' in ctx)) { | ||
text = ctx.getText(); | ||
} else { | ||
this.idiomatic = idiomatic; | ||
fields[field] = this.visit(this.getValue(pair)); | ||
this.idiomatic = true; | ||
text = ctx.getParent().getText(); | ||
} | ||
}); | ||
if (req.length !== reqOpts.length) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Required option missing from ${op}` | ||
); | ||
return `where(${doubleQuoteStringify(text)})`; | ||
} | ||
const args = req.concat(Object.keys(fields).map((f) => { | ||
return transform(f, fields[f]); | ||
})); | ||
return `${op}(${args.join(', ')})`; | ||
} | ||
/** | ||
* Method for handling an idiomatic $sort. | ||
* | ||
* { $sort: { f1: 1, f2: -1, f3: { $meta: 'textScore' } } } => | ||
* sort(ascending(f1), descending(f2), metaTextScore(f3)) | ||
* | ||
* @param {ObjectLiteralExpressionContext} ctx - the ctx of the value of the | ||
* @return {string} | ||
*/ | ||
handlesort(ctx) { | ||
const properties = this.assertIsNonemptyObject(ctx, 'sort'); | ||
const fields = []; | ||
/** | ||
* Method for handling an idiomatic $project. | ||
* ctx must be a non-empty document. | ||
* | ||
* @param {ObjectLiteralContext} ctx | ||
* @return {String} | ||
*/ | ||
handleproject(ctx) { | ||
// Eventual todo: slice and elemMatch | ||
const properties = this.assertIsNonemptyObject(ctx, 'project'); | ||
const fields = {}; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
const original = this.getValue(pair).getText(); | ||
if (original.toLowerCase() === 'true' || original === '1') { | ||
if (field !== '_id') { | ||
// Skip because ID is included by default | ||
fields.includes = !fields.includes ? | ||
`include(${doubleQuoteStringify(field)}` : | ||
`${fields.includes}, ${doubleQuoteStringify(field)}`; | ||
this.requiredImports[303].push('include'); | ||
} | ||
} else if (original.toLowerCase() === 'false' || original === '0') { | ||
if (field !== '_id') { | ||
fields.excludes = !fields.excludes ? | ||
`exclude(${doubleQuoteStringify(field)}` : | ||
`${fields.excludes}, ${doubleQuoteStringify(field)}`; | ||
this.requiredImports[303].push('exclude'); | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
const original = this.getValue(pair).getText(); | ||
if (original === '1') { | ||
fields.push(`ascending(${doubleQuoteStringify(field)})`); | ||
this.requiredImports[304].push('ascending'); | ||
} else if (original === '-1') { | ||
fields.push(`descending(${doubleQuoteStringify(field)})`); | ||
this.requiredImports[304].push('descending'); | ||
} else if ( | ||
original.match( | ||
new RegExp(/{(?:'|")?\$meta(?:'|")?:(?:'|")textScore*(?:'|")}/) | ||
) | ||
) { | ||
fields.push(`metaTextScore(${doubleQuoteStringify(field)})`); | ||
this.requiredImports[304].push('metaTextScore'); | ||
} else { | ||
fields.excludeId = 'excludeId()'; | ||
this.requiredImports[303].push('excludeId'); | ||
throw new BsonTranspilersRuntimeError( | ||
'$sort key ordering must be specified using a number or ' + | ||
"{$meta: 'textScore'}" | ||
); | ||
} | ||
}); | ||
let sortStr; | ||
if (fields.length > 1) { | ||
sortStr = `orderBy(${fields.join(', ')})`; | ||
this.requiredImports[304].push('orderBy'); | ||
} else { | ||
const value = this.visit(this.getValue(pair)); | ||
fields.computed = !fields.computed ? | ||
`computed(${doubleQuoteStringify(field)}, ${value})` : | ||
`${fields.computed}, computed(${doubleQuoteStringify(field)}, ${value})`; | ||
this.requiredImports[303].push('computed'); | ||
sortStr = fields[0]; | ||
} | ||
}); | ||
if (fields.includes) { | ||
fields.includes = `${fields.includes})`; | ||
return `sort(${sortStr})`; | ||
} | ||
if (fields.excludes) { | ||
fields.excludes = `${fields.excludes})`; | ||
} | ||
const elements = Object.values(fields); | ||
let projectStr; | ||
if (elements.length === 1) { | ||
projectStr = elements[0]; | ||
} else { | ||
projectStr = `fields(${elements.join(', ')})`; | ||
this.requiredImports[303].push('fields'); | ||
} | ||
return `project(${projectStr})`; | ||
} | ||
/** | ||
* Method for handling an idiomatic $not. | ||
* | ||
* { field: { $not: {$op: value} } } => not(op(field, value)) | ||
* | ||
* ctx must be a non-empty document. | ||
* | ||
* @param {ObjectLiteralExpressionContext} ctx - the ctx of the value of the | ||
* $not field | ||
* @param {String} op - the operation, which in this case is "not" | ||
* @param {ObjectLiteralExpressionContext} parent - ctx of parent document. | ||
* @return {String} | ||
*/ | ||
handlenot(ctx, op, parent) { | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
const val = this.getValue(properties[0]); | ||
const innerop = this.getKeyStr(properties[0]).substr(1); | ||
this.requiredImports[300].push(innerop); | ||
const inner = this.handleFieldOp(val, innerop, parent); | ||
return `${op}(${inner})`; | ||
} | ||
/** | ||
* Method for handling an idiomatic $mod. | ||
* | ||
* { field: { $mod: [arr1, arr2] } } => mod(field, arr1, arr2) | ||
* | ||
* ctx must be an array of length 2. | ||
* | ||
* @param {ObjectLiteralExpressionContext} ctx - the ctx of the value of the | ||
* $mod field | ||
* @param {String} op - the operation, which in this case is "mod" | ||
* @param {ObjectLiteralExpressionContext} parent - ctx of parent document. | ||
* @return {String} | ||
*/ | ||
handlemod(ctx, op, parent) { | ||
const list = this.getList(ctx); | ||
if (list.length !== 2) { | ||
throw new BsonTranspilersRuntimeError( | ||
'$mod requires an array of 2-elements' | ||
handlegeoWithin(ctx, op, parent) { | ||
this.requiredImports[300].splice( | ||
this.requiredImports[300].indexOf('geoWithin'), | ||
1 | ||
); | ||
} | ||
const parentField = this.getParentKeyStr(parent); | ||
const inner = list.map((f) => { | ||
return this.visit(f); | ||
}); | ||
return `${op}(${doubleQuoteStringify(parentField)}, ${inner.join(', ')})`; | ||
} | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
const parentField = doubleQuoteStringify(this.getParentKeyStr(parent)); | ||
const fields = {}; | ||
/** | ||
* Method for handling an idiomatic $regex. | ||
* | ||
* { field: { $regex: regexstr, $options?: optsstr } } => | ||
* regex(regexstr, optsstr?) | ||
* | ||
* ctx must be a string | ||
* | ||
* @param {ObjectLiteralExpressionContext} ctx - the ctx of the value of the | ||
* $regex field | ||
* @param {String} op - the operation, which in this case is "regex" | ||
* @param {ObjectLiteralExpressionContext} parent - ctx of parent document. | ||
* @return {String} | ||
*/ | ||
handleregex(ctx, op, parent) { | ||
const parentField = this.getParentKeyStr(parent); | ||
const regex = {r: '', o: ''}; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
fields[field] = this.getValue(pair); | ||
}); | ||
const properties = this.getKeyValueList(parent); | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
if (field === '$regex') { | ||
regex.r = this.visit(this.getValue(pair)); | ||
if (Object.keys(fields).length !== 1) { | ||
throw new BsonTranspilersRuntimeError( | ||
'$geoWithin takes an object with only 1 field' | ||
); | ||
} | ||
if (field === '$options') { | ||
regex.o = `, ${this.visit(this.getValue(pair))}`; | ||
const key = Object.keys(fields)[0]; | ||
switch (key) { | ||
case '$geometry': { | ||
this.requiredImports[300].push('geoWithin'); | ||
return `geoWithin(${parentField}, ${this.handlegeometry( | ||
fields[key] | ||
)})`; | ||
} | ||
case '$box': { | ||
this.requiredImports[300].push('geoWithinBox'); | ||
return `geoWithinBox(${parentField}, ${this.combineCoordinates( | ||
fields[key], | ||
2, | ||
'', | ||
true, | ||
(p) => { | ||
return this.combineCoordinates(p, 2, '', true, (p2) => { | ||
return this.visit(p2); | ||
}); | ||
} | ||
)})`; | ||
} | ||
case '$polygon': { | ||
this.requiredImports[300].push('geoWithinPolygon'); | ||
return `geoWithinPolygon(${parentField}, ${this.visit(fields[key])})`; | ||
} | ||
case '$centerSphere': | ||
case '$center': { | ||
const array = this.assertIsNonemptyArray(fields[key]); | ||
if (array.length !== 2) { | ||
throw new BsonTranspilersRuntimeError( | ||
`${key} takes array of length 2` | ||
); | ||
} | ||
const coordinates = this.combineCoordinates( | ||
array[0], | ||
2, | ||
'', | ||
true, | ||
(p) => { | ||
return this.visit(p); | ||
} | ||
); | ||
const geoop = `geoWithin${key[1].toUpperCase()}${key.substr(2)}`; | ||
this.requiredImports[300].push(geoop); | ||
return `${geoop}(${parentField}, ${coordinates}, ${this.visit( | ||
array[1] | ||
)})`; | ||
} | ||
default: { | ||
throw new BsonTranspilersRuntimeError( | ||
`unrecognized option ${key} to $geoWithin` | ||
); | ||
} | ||
} | ||
}); | ||
return `${op}(${doubleQuoteStringify(parentField)}, ${regex.r}${regex.o})`; | ||
} | ||
handleoptions() { | ||
return ''; | ||
} | ||
/** | ||
* Method for handling an idiomatic $where. | ||
* | ||
* { $where: <function def> } => where(<function as string>) | ||
* | ||
* @param {ObjectLiteralExpressionContext} ctx - the ctx of the value of the | ||
* $where field | ||
* @return {String} | ||
*/ | ||
handlewhere(ctx) { | ||
let text; | ||
if (!('getParent' in ctx)) { | ||
text = ctx.getText(); | ||
} else { | ||
text = ctx.getParent().getText(); | ||
} | ||
return `where(${doubleQuoteStringify(text)})`; | ||
} | ||
/** | ||
* Method for handling an idiomatic $sort. | ||
* | ||
* { $sort: { f1: 1, f2: -1, f3: { $meta: 'textScore' } } } => | ||
* sort(ascending(f1), descending(f2), metaTextScore(f3)) | ||
* | ||
* @param {ObjectLiteralExpressionContext} ctx - the ctx of the value of the | ||
* @return {string} | ||
*/ | ||
handlesort(ctx) { | ||
const properties = this.assertIsNonemptyObject(ctx, 'sort'); | ||
const fields = []; | ||
handlenear(ctx, op, parent) { | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
const parentField = doubleQuoteStringify(this.getParentKeyStr(parent)); | ||
const fields = {}; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
const original = this.getValue(pair).getText(); | ||
if (original === '1') { | ||
fields.push(`ascending(${doubleQuoteStringify(field)})`); | ||
this.requiredImports[304].push('ascending'); | ||
} else if (original === '-1') { | ||
fields.push(`descending(${doubleQuoteStringify(field)})`); | ||
this.requiredImports[304].push('descending'); | ||
} else if (original.match( | ||
new RegExp(/{(?:'|")?\$meta(?:'|")?:(?:'|")textScore*(?:'|")}/) | ||
)) { | ||
fields.push(`metaTextScore(${doubleQuoteStringify(field)})`); | ||
this.requiredImports[304].push('metaTextScore'); | ||
} else { | ||
throw new BsonTranspilersRuntimeError( | ||
'$sort key ordering must be specified using a number or ' + | ||
'{$meta: \'textScore\'}' | ||
); | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
fields[field] = this.getValue(pair); | ||
}); | ||
['$geometry', '$minDistance', '$maxDistance'].map((k) => { | ||
if (!(k in fields)) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Missing required field ${k} in $${op}` | ||
); | ||
} | ||
}); | ||
if (Object.keys(fields).length !== 3) { | ||
throw new BsonTranspilersRuntimeError(`Too many fields to $${op}`); | ||
} | ||
}); | ||
let sortStr; | ||
if (fields.length > 1) { | ||
sortStr = `orderBy(${fields.join(', ')})`; | ||
this.requiredImports[304].push('orderBy'); | ||
} else { | ||
sortStr = fields[0]; | ||
return `${op}(${parentField}, ${this.handlegeometry( | ||
fields.$geometry | ||
)}, ${this.visit(fields.$maxDistance)}, ${this.visit( | ||
fields.$minDistance | ||
)})`; | ||
} | ||
return `sort(${sortStr})`; | ||
} | ||
handlegeoWithin(ctx, op, parent) { | ||
this.requiredImports[300].splice( | ||
this.requiredImports[300].indexOf('geoWithin'), 1 | ||
); | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
const parentField = doubleQuoteStringify( | ||
this.getParentKeyStr(parent) | ||
); | ||
const fields = {}; | ||
handlenearSphere(ctx, op, parent) { | ||
return this.handlenear(ctx, op, parent); | ||
} | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
fields[field] = this.getValue(pair); | ||
}); | ||
generateposition(ctx) { | ||
const coordinates = this.assertIsNonemptyArray(ctx, 'geometry'); | ||
if (coordinates.length !== 2) { | ||
throw new BsonTranspilersRuntimeError('Position must be 2 coordinates'); | ||
} | ||
this.requiredImports[305].push('Position'); | ||
return `new Position(${this.visit(coordinates[0])}, ${this.visit( | ||
coordinates[1] | ||
)})`; | ||
} | ||
if (Object.keys(fields).length !== 1) { | ||
throw new BsonTranspilersRuntimeError( | ||
'$geoWithin takes an object with only 1 field' | ||
); | ||
assertIsNonemptyArray(ctx, op) { | ||
const array = this.getArray(ctx); | ||
if (!array || this.getList(array).length === 0) { | ||
throw new BsonTranspilersRuntimeError( | ||
`$${op} requires a non-empty array` | ||
); | ||
} | ||
return this.getList(array); | ||
} | ||
const key = Object.keys(fields)[0]; | ||
switch (key) { | ||
case ('$geometry'): { | ||
this.requiredImports[300].push('geoWithin'); | ||
return `geoWithin(${parentField}, ${this.handlegeometry(fields[key])})`; | ||
assertIsNonemptyObject(ctx, op) { | ||
if (this.getObject(ctx)) { | ||
ctx = this.getObject(ctx); | ||
} | ||
case ('$box'): { | ||
this.requiredImports[300].push('geoWithinBox'); | ||
return `geoWithinBox(${parentField}, ${ | ||
this.combineCoordinates(fields[key], 2, '', true, (p) => { | ||
return this.combineCoordinates(p, 2, '', true, (p2) => { | ||
return this.visit(p2); | ||
}); | ||
})})`; | ||
} | ||
case ('$polygon'): { | ||
this.requiredImports[300].push('geoWithinPolygon'); | ||
return `geoWithinPolygon(${parentField}, ${this.visit(fields[key])})`; | ||
} | ||
case ('$centerSphere'): | ||
case ('$center'): { | ||
const array = this.assertIsNonemptyArray(fields[key]); | ||
if (array.length !== 2) { | ||
throw new BsonTranspilersRuntimeError(`${key} takes array of length 2`); | ||
} | ||
const coordinates = this.combineCoordinates( | ||
array[0], 2, '', true, (p) => { return this.visit(p); } | ||
); | ||
const geoop = `geoWithin${key[1].toUpperCase()}${ | ||
key.substr(2) | ||
}`; | ||
this.requiredImports[300].push(geoop); | ||
return `${geoop}(${parentField}, ${coordinates}, ${this.visit(array[1])})`; | ||
} | ||
default: { | ||
const kv = this.getKeyValueList(ctx); | ||
if (kv.length === 0) { | ||
throw new BsonTranspilersRuntimeError( | ||
`unrecognized option ${key} to $geoWithin` | ||
`$${op} requires a non-empty document` | ||
); | ||
} | ||
return kv; | ||
} | ||
} | ||
handlenear(ctx, op, parent) { | ||
const properties = this.assertIsNonemptyObject(ctx, op); | ||
const parentField = doubleQuoteStringify( | ||
this.getParentKeyStr(parent) | ||
); | ||
const fields = {}; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
fields[field] = this.getValue(pair); | ||
}); | ||
['$geometry', '$minDistance', '$maxDistance'].map((k) => { | ||
if (!(k in fields)) { | ||
combineCoordinates(ctx, length, className, noArray, innerFunc) { | ||
if (!noArray) { | ||
this.requiredImports[9] = true; | ||
} | ||
const points = this.assertIsNonemptyArray(ctx, 'geometry'); | ||
if (points.length < length) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Missing required field ${k} in $${op}` | ||
`${ | ||
className ? className : '$geometry inner array' | ||
} must have at least ${length} elements (has ${points.length})` | ||
); | ||
} | ||
}); | ||
if (Object.keys(fields).length !== 3) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Too many fields to $${op}` | ||
); | ||
let pointstr = points | ||
.map((p) => { | ||
if (!innerFunc) { | ||
return this.generateposition(p); | ||
} | ||
return innerFunc(p); | ||
}) | ||
.join(', '); | ||
pointstr = noArray ? pointstr : `Arrays.asList(${pointstr})`; | ||
if (!className) { | ||
return pointstr; | ||
} | ||
this.requiredImports[305].push(className); | ||
return `new ${className}(${pointstr})`; | ||
} | ||
return `${op}(${parentField}, ${ | ||
this.handlegeometry(fields.$geometry) | ||
}, ${this.visit(fields.$maxDistance)}, ${ | ||
this.visit(fields.$minDistance) | ||
})`; | ||
} | ||
handlenearSphere(ctx, op, parent) { | ||
return this.handlenear(ctx, op, parent); | ||
} | ||
generatepoint(ctx) { | ||
return `new Point(${this.generateposition(ctx)})`; | ||
} | ||
generateposition(ctx) { | ||
const coordinates = this.assertIsNonemptyArray(ctx, 'geometry'); | ||
if (coordinates.length !== 2) { | ||
throw new BsonTranspilersRuntimeError( | ||
'Position must be 2 coordinates' | ||
); | ||
generatemultipoint(ctx) { | ||
return this.combineCoordinates(ctx, 1, 'MultiPoint'); | ||
} | ||
this.requiredImports[305].push('Position'); | ||
return `new Position(${ | ||
this.visit(coordinates[0])}, ${this.visit(coordinates[1]) | ||
})`; | ||
} | ||
assertIsNonemptyArray(ctx, op) { | ||
const array = this.getArray(ctx); | ||
if (!array || this.getList(array).length === 0) { | ||
throw new BsonTranspilersRuntimeError( | ||
`$${op} requires a non-empty array` | ||
); | ||
generatelinestring(ctx) { | ||
return this.combineCoordinates(ctx, 2, 'LineString'); | ||
} | ||
return this.getList(array); | ||
} | ||
assertIsNonemptyObject(ctx, op) { | ||
if (this.getObject(ctx)) { | ||
ctx = this.getObject(ctx); | ||
generatemultilinestring(ctx) { | ||
return this.combineCoordinates(ctx, 1, 'MultiLineString', false, (p) => { | ||
return this.combineCoordinates(p, 2); | ||
}); | ||
} | ||
const kv = this.getKeyValueList(ctx); | ||
if (kv.length === 0) { | ||
throw new BsonTranspilersRuntimeError( | ||
`$${op} requires a non-empty document` | ||
); | ||
} | ||
return kv; | ||
} | ||
combineCoordinates(ctx, length, className, noArray, innerFunc) { | ||
if (!noArray) { | ||
this.requiredImports[9] = true; | ||
} | ||
const points = this.assertIsNonemptyArray(ctx, 'geometry'); | ||
if (points.length < length) { | ||
throw new BsonTranspilersRuntimeError( | ||
`${ | ||
className ? className : '$geometry inner array' | ||
} must have at least ${length} elements (has ${points.length})` | ||
generatepolygon(ctx) { | ||
const polyCoords = this.combineCoordinates( | ||
ctx, | ||
1, | ||
'PolygonCoordinates', | ||
true, | ||
(p) => { | ||
return this.combineCoordinates(p, 4); | ||
} | ||
); | ||
return `new Polygon(${polyCoords})`; | ||
} | ||
let pointstr = points.map((p) => { | ||
if (!innerFunc) { | ||
return this.generateposition(p); | ||
} | ||
return innerFunc(p); | ||
}).join(', '); | ||
pointstr = noArray ? pointstr : `Arrays.asList(${pointstr})`; | ||
if (!className) { | ||
return pointstr; | ||
} | ||
this.requiredImports[305].push(className); | ||
return `new ${className}(${pointstr})`; | ||
} | ||
generatepoint(ctx) { | ||
return `new Point(${this.generateposition(ctx)})`; | ||
} | ||
generatemultipoint(ctx) { | ||
return this.combineCoordinates(ctx, 1, 'MultiPoint'); | ||
} | ||
generatelinestring(ctx) { | ||
return this.combineCoordinates(ctx, 2, 'LineString'); | ||
} | ||
generatemultilinestring(ctx) { | ||
return this.combineCoordinates( | ||
ctx, | ||
1, | ||
'MultiLineString', | ||
false, | ||
(p) => { return this.combineCoordinates(p, 2); } | ||
); | ||
} | ||
generatepolygon(ctx) { | ||
const polyCoords = this.combineCoordinates( | ||
ctx, | ||
1, | ||
'PolygonCoordinates', | ||
true, | ||
(p) => { return this.combineCoordinates(p, 4); } | ||
); | ||
return `new Polygon(${polyCoords})`; | ||
} | ||
generatemultipolygon(ctx) { | ||
return this.combineCoordinates( | ||
ctx, | ||
1, | ||
'MultiPolygon', | ||
false, | ||
(p) => { | ||
generatemultipolygon(ctx) { | ||
return this.combineCoordinates(ctx, 1, 'MultiPolygon', false, (p) => { | ||
return this.combineCoordinates( | ||
@@ -687,159 +800,186 @@ p, | ||
true, | ||
(p2) => { return this.combineCoordinates(p2, 4); } | ||
(p2) => { | ||
return this.combineCoordinates(p2, 4); | ||
} | ||
); | ||
} | ||
); | ||
} | ||
}); | ||
} | ||
generategeometrycollection(ctx) { | ||
const geometries = this.assertIsNonemptyArray(ctx, 'geometry'); | ||
return `new GeometryCollection(Arrays.asList(${ | ||
geometries.map((g) => { | ||
const obj = this.getObject(g); | ||
if (!obj) { | ||
generategeometrycollection(ctx) { | ||
const geometries = this.assertIsNonemptyArray(ctx, 'geometry'); | ||
return `new GeometryCollection(Arrays.asList(${geometries | ||
.map((g) => { | ||
const obj = this.getObject(g); | ||
if (!obj) { | ||
throw new BsonTranspilersRuntimeError( | ||
'$GeometryCollection requires objects' | ||
); | ||
} | ||
return this.handlegeometry(obj); | ||
}) | ||
.join(', ')}))`; | ||
} | ||
handlegeometry(ctx) { | ||
const properties = this.assertIsNonemptyObject(ctx, 'geometry'); | ||
const fields = {}; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
if (field === 'type') { | ||
fields.type = removeQuotes(this.visit(this.getValue(pair))); | ||
} else if (field === 'coordinates') { | ||
fields.coordinates = this.getValue(pair); | ||
} else if (field === 'crs') { | ||
throw new BsonTranspilersUnimplementedError( | ||
'Coordinate reference systems not currently supported' | ||
); | ||
} else { | ||
throw new BsonTranspilersRuntimeError( | ||
'$GeometryCollection requires objects' | ||
`Unrecognized option to $geometry: ${field}` | ||
); | ||
} | ||
return this.handlegeometry(obj); | ||
}).join(', ') | ||
}))`; | ||
} | ||
handlegeometry(ctx) { | ||
const properties = this.assertIsNonemptyObject(ctx, 'geometry'); | ||
const fields = {}; | ||
properties.forEach((pair) => { | ||
const field = this.getKeyStr(pair); | ||
if (field === 'type') { | ||
fields.type = removeQuotes(this.visit(this.getValue(pair))); | ||
} else if (field === 'coordinates') { | ||
fields.coordinates = this.getValue(pair); | ||
} else if (field === 'crs') { | ||
throw new BsonTranspilersUnimplementedError( | ||
'Coordinate reference systems not currently supported' | ||
); | ||
} else { | ||
}); | ||
if (!fields.type || !fields.coordinates) { | ||
throw new BsonTranspilersRuntimeError('Missing option to $geometry'); | ||
} | ||
if ( | ||
!this.getArray(fields.coordinates) || | ||
this.getList(this.getArray(fields.coordinates)).length === 0 | ||
) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Unrecognized option to $geometry: ${field}` | ||
'Invalid coordinates option for $geometry' | ||
); | ||
} | ||
}); | ||
if (!fields.type || !fields.coordinates) { | ||
if (`generate${fields.type.toLowerCase()}` in this) { | ||
this.requiredImports[305].push(fields.type); | ||
return this[`generate${fields.type.toLowerCase()}`](fields.coordinates); | ||
} | ||
throw new BsonTranspilersRuntimeError( | ||
'Missing option to $geometry' | ||
`Unrecognized GeoJSON type "${fields.type}"` | ||
); | ||
} | ||
if (!this.getArray(fields.coordinates) || | ||
this.getList(this.getArray(fields.coordinates)).length === 0) { | ||
throw new BsonTranspilersRuntimeError( | ||
'Invalid coordinates option for $geometry' | ||
handlesample(ctx) { | ||
return this.handleSingleSubfield(ctx, 'sample', 'size', true); | ||
} | ||
handlereplaceRoot(ctx) { | ||
return this.handleSingleSubfield(ctx, 'replaceRoot', 'newRoot', false); | ||
} | ||
handlegraphLookup(ctx) { | ||
return this.handleOptionsObject( | ||
ctx, | ||
'graphLookup', | ||
['from', 'startWith', 'connectFromField', 'connectToField', 'as'], | ||
['maxDepth', 'depthField', 'restrictSearchWithMatch'], | ||
{ graphLookup: 'GraphLookupOptions' } | ||
); | ||
} | ||
if (`generate${fields.type.toLowerCase()}` in this) { | ||
this.requiredImports[305].push(fields.type); | ||
return this[`generate${fields.type.toLowerCase()}`](fields.coordinates); | ||
handlelookup(ctx) { | ||
return this.handleOptionsObject( | ||
ctx, | ||
'lookup', | ||
['from', 'localField', 'foreignField', 'as'], | ||
[], | ||
{ lookup: 'LookupOptions' } | ||
); | ||
} | ||
throw new BsonTranspilersRuntimeError( | ||
`Unrecognized GeoJSON type "${fields.type}"` | ||
); | ||
} | ||
handlesample(ctx) { | ||
return this.handleSingleSubfield(ctx, 'sample', 'size', true); | ||
} | ||
handlereplaceRoot(ctx) { | ||
return this.handleSingleSubfield(ctx, 'replaceRoot', 'newRoot', false); | ||
} | ||
handlegraphLookup(ctx) { | ||
return this.handleOptionsObject( | ||
ctx, | ||
'graphLookup', | ||
['from', 'startWith', 'connectFromField', 'connectToField', 'as'], | ||
['maxDepth', 'depthField', 'restrictSearchWithMatch'], | ||
{ graphLookup: 'GraphLookupOptions' } | ||
); | ||
} | ||
handlelookup(ctx) { | ||
return this.handleOptionsObject( | ||
ctx, | ||
'lookup', | ||
['from', 'localField', 'foreignField', 'as'], | ||
[], | ||
{ lookup: 'LookupOptions' } | ||
); | ||
} | ||
handlebucket(ctx) { | ||
return this.handleOptionsObject( | ||
ctx, | ||
'bucket', | ||
['groupBy', 'boundaries'], | ||
['default', 'output'], | ||
{ | ||
bucket: 'BucketOptions', | ||
default: (k) => { return `.defaultBucket(${k})`; } | ||
} | ||
); | ||
} | ||
handlebucketAuto(ctx) { | ||
return this.handleOptionsObject( | ||
ctx, | ||
'bucketAuto', | ||
['groupBy', 'buckets'], | ||
['granularity', 'output'], | ||
{ | ||
bucketAuto: 'BucketAutoOptions', | ||
granularity: (k) => { | ||
return `.granularity(BucketGranularity.fromString(${k}))`; | ||
handlebucket(ctx) { | ||
return this.handleOptionsObject( | ||
ctx, | ||
'bucket', | ||
['groupBy', 'boundaries'], | ||
['default', 'output'], | ||
{ | ||
bucket: 'BucketOptions', | ||
default: (k) => { | ||
return `.defaultBucket(${k})`; | ||
}, | ||
} | ||
); | ||
} | ||
handlebucketAuto(ctx) { | ||
return this.handleOptionsObject( | ||
ctx, | ||
'bucketAuto', | ||
['groupBy', 'buckets'], | ||
['granularity', 'output'], | ||
{ | ||
bucketAuto: 'BucketAutoOptions', | ||
granularity: (k) => { | ||
return `.granularity(BucketGranularity.fromString(${k}))`; | ||
}, | ||
} | ||
); | ||
} | ||
handletext(ctx) { | ||
return this.handleOptionsObject( | ||
ctx, | ||
'text', | ||
['$search'], | ||
['$language', '$caseSensitive', '$diacriticSensitive'], | ||
{ | ||
text: 'TextSearchOptions', | ||
$language: (k) => { | ||
return `.language(${k})`; | ||
}, | ||
$caseSensitive: (k) => { | ||
return `.caseSensitive(${k})`; | ||
}, | ||
$diacriticSensitive: (k) => { | ||
return `.diacriticSensitive(${k})`; | ||
}, | ||
} | ||
); | ||
} | ||
handleunwind(ctx) { | ||
const copy = this.deepCopyRequiredImports(); | ||
const value = this.visit(ctx.parentCtx); | ||
this.requiredImports = copy; | ||
if (this.findTypedNode(ctx.parentCtx).type.id === '_string') { | ||
return `unwind(${value})`; | ||
} | ||
); | ||
} | ||
handletext(ctx) { | ||
return this.handleOptionsObject( | ||
ctx, | ||
'text', | ||
['$search'], | ||
['$language', '$caseSensitive', '$diacriticSensitive'], | ||
{ | ||
text: 'TextSearchOptions', | ||
$language: (k) => { return `.language(${k})`; }, | ||
$caseSensitive: (k) => { return `.caseSensitive(${k})`; }, | ||
$diacriticSensitive: (k) => { return `.diacriticSensitive(${k})`; } | ||
} | ||
); | ||
} | ||
handleunwind(ctx) { | ||
const copy = this.deepCopyRequiredImports(); | ||
const value = this.visit(ctx.parentCtx); | ||
this.requiredImports = copy; | ||
if (this.findTypedNode(ctx.parentCtx).type.id === '_string') { | ||
return `unwind(${value})`; | ||
return this.handleOptionsObject( | ||
ctx, | ||
'unwind', | ||
['path'], | ||
['includeArrayIndex', 'preserveNullAndEmptyArrays'], | ||
{ unwind: 'UnwindOptions' } | ||
); | ||
} | ||
return this.handleOptionsObject( | ||
ctx, | ||
'unwind', | ||
['path'], | ||
['includeArrayIndex', 'preserveNullAndEmptyArrays'], | ||
{ unwind: 'UnwindOptions' } | ||
); | ||
} | ||
handlegroup(ctx) { | ||
return this.handleMultipleSubfields(ctx, 'group', ['_id'], (f, v) => { | ||
return v; | ||
}, true); | ||
} | ||
handlefacet(ctx) { | ||
this.requiredImports[306].push('Facet'); | ||
return this.handleMultipleSubfields(ctx, 'facet', [], (f, v) => { | ||
return `new Facet(${doubleQuoteStringify(f)}, ${v})`; | ||
}, true); | ||
} | ||
handleaddFields(ctx) { | ||
this.requiredImports[306].push('Field'); | ||
return this.handleMultipleSubfields(ctx, 'addFields', [], (f, v) => { | ||
return `new Field(${doubleQuoteStringify(f)}, ${v})`; | ||
}, false); | ||
} | ||
}; | ||
handlegroup(ctx) { | ||
return this.handleMultipleSubfields( | ||
ctx, | ||
'group', | ||
['_id'], | ||
(f, v) => { | ||
return v; | ||
}, | ||
true | ||
); | ||
} | ||
handlefacet(ctx) { | ||
this.requiredImports[306].push('Facet'); | ||
return this.handleMultipleSubfields( | ||
ctx, | ||
'facet', | ||
[], | ||
(f, v) => { | ||
return `new Facet(${doubleQuoteStringify(f)}, ${v})`; | ||
}, | ||
true | ||
); | ||
} | ||
handleaddFields(ctx) { | ||
this.requiredImports[306].push('Field'); | ||
return this.handleMultipleSubfields( | ||
ctx, | ||
'addFields', | ||
[], | ||
(f, v) => { | ||
return `new Field(${doubleQuoteStringify(f)}, ${v})`; | ||
}, | ||
false | ||
); | ||
} | ||
}; |
@@ -0,15 +1,17 @@ | ||
'use strict'; | ||
/* | ||
* Class for handling edge cases for node code generation. Defines "emit" methods. | ||
*/ | ||
module.exports = (Visitor) => class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
module.exports = (Visitor) => | ||
class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
generateFuncDefExpression(ctx) { | ||
const source = ctx.start.source[1].strdata; | ||
const startIndex = ctx.start.start; | ||
const stopIndex = ctx.stop.stop; | ||
return source.slice(startIndex, stopIndex + 1); | ||
} | ||
}; | ||
generateFuncDefExpression(ctx) { | ||
const source = ctx.start.source[1].strdata; | ||
const startIndex = ctx.start.start; | ||
const stopIndex = ctx.stop.stop; | ||
return source.slice(startIndex, stopIndex + 1); | ||
} | ||
}; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/* eslint complexity: 0 */ | ||
@@ -7,7 +8,6 @@ const vm = require('vm'); | ||
BsonTranspilersRuntimeError, | ||
BsonTranspilersUnimplementedError | ||
BsonTranspilersUnimplementedError, | ||
} = require('../../helper/error'); | ||
const { removeQuotes } = require('../../helper/format'); | ||
/** | ||
@@ -20,47 +20,66 @@ * This is a Visitor that visits the tree generated by the ECMAScript.g4 grammar. | ||
*/ | ||
module.exports = (CodeGenerationVisitor) => class Visitor extends CodeGenerationVisitor { | ||
constructor() { | ||
super(); | ||
this.startRule = 'program'; // Name of the ANTLR rule to start | ||
module.exports = (CodeGenerationVisitor) => | ||
class Visitor extends CodeGenerationVisitor { | ||
constructor() { | ||
super(); | ||
this.startRule = 'program'; // Name of the ANTLR rule to start | ||
// Throw UnimplementedError for nodes with expressions that we don't support | ||
this.visitThisExpression = | ||
this.visitDeleteExpression = | ||
this.visitVoidExpression = | ||
this.visitTypeofExpression = | ||
this.visitInExpression = | ||
this.visitInstanceofExpression = | ||
this.visitAssignmentExpression = | ||
this.visitAssignmentOperatorExpression = | ||
this.visitMemberIndexExpression = | ||
this.visitTernaryExpression = | ||
this.visitFunctionDeclaration = | ||
this.visitVariableStatement = | ||
this.visitIfStatement = | ||
this.visitDoWhileStatement = | ||
this.visitWhileStatement = | ||
this.visitForStatement = | ||
this.visitForVarStatement = | ||
this.visitForInStatement = | ||
this.visitForVarInStatement = | ||
this.visitContinueStatement = | ||
this.visitBreakStatement = | ||
this.visitReturnStatement = | ||
this.visitWithStatement = | ||
this.visitLabelledStatement = | ||
this.visitSwitchStatement = | ||
this.visitThrowStatement = | ||
this.visitTryStatement = | ||
this.visitDebuggerStatement = | ||
this.unimplemented; | ||
} | ||
// Throw UnimplementedError for nodes with expressions that we don't support | ||
this.visitThisExpression = | ||
this.visitDeleteExpression = | ||
this.visitVoidExpression = | ||
this.visitTypeofExpression = | ||
this.visitInExpression = | ||
this.visitInstanceofExpression = | ||
this.visitAssignmentExpression = | ||
this.visitAssignmentOperatorExpression = | ||
this.visitMemberIndexExpression = | ||
this.visitTernaryExpression = | ||
this.visitFunctionDeclaration = | ||
this.visitVariableStatement = | ||
this.visitIfStatement = | ||
this.visitDoWhileStatement = | ||
this.visitWhileStatement = | ||
this.visitForStatement = | ||
this.visitForVarStatement = | ||
this.visitForInStatement = | ||
this.visitForVarInStatement = | ||
this.visitContinueStatement = | ||
this.visitBreakStatement = | ||
this.visitReturnStatement = | ||
this.visitWithStatement = | ||
this.visitLabelledStatement = | ||
this.visitSwitchStatement = | ||
this.visitThrowStatement = | ||
this.visitTryStatement = | ||
this.visitDebuggerStatement = | ||
this.unimplemented; | ||
} | ||
/* | ||
* | ||
* Visit Methods | ||
* | ||
*/ | ||
/* | ||
* | ||
* Visit Methods | ||
* | ||
*/ | ||
visitProgram(ctx) { | ||
if (ctx.getChildCount() < 2) { | ||
visitProgram(ctx) { | ||
if (ctx.getChildCount() < 2) { | ||
throw new BsonTranspilersRuntimeError( | ||
'Expression contains 0 statements. Input should be a single statement' | ||
); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitSourceElements(ctx) { | ||
if (ctx.sourceElement().length !== 1) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Expression contains ${ | ||
ctx.sourceElement().length | ||
} statements. Input should be a single statement` | ||
); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitEmptyStatement() { | ||
throw new BsonTranspilersRuntimeError( | ||
@@ -70,639 +89,665 @@ 'Expression contains 0 statements. Input should be a single statement' | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitSourceElements(ctx) { | ||
if (ctx.sourceElement().length !== 1) { | ||
throw new BsonTranspilersRuntimeError(`Expression contains ${ | ||
ctx.sourceElement().length} statements. Input should be a single statement`); | ||
visitFuncCallExpression(ctx) { | ||
return this.generateFunctionCall(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitEmptyStatement() { | ||
throw new BsonTranspilersRuntimeError( | ||
'Expression contains 0 statements. Input should be a single statement' | ||
); | ||
} | ||
visitIdentifierExpression(ctx) { | ||
return this.generateIdentifier(ctx); | ||
} | ||
visitFuncCallExpression(ctx) { | ||
return this.generateFunctionCall(ctx); | ||
} | ||
visitGetAttributeExpression(ctx) { | ||
return this.generateAttributeAccess(ctx); | ||
} | ||
visitIdentifierExpression(ctx) { | ||
return this.generateIdentifier(ctx); | ||
} | ||
visitObjectLiteral(ctx) { | ||
return this.generateObjectLiteral(ctx); | ||
} | ||
visitGetAttributeExpression(ctx) { | ||
return this.generateAttributeAccess(ctx); | ||
} | ||
visitArrayLiteral(ctx) { | ||
return this.generateArrayLiteral(ctx); | ||
} | ||
visitObjectLiteral(ctx) { | ||
return this.generateObjectLiteral(ctx); | ||
} | ||
visitNullLiteral(ctx) { | ||
return this.leafHelper(this.Types._null, ctx); | ||
} | ||
visitArrayLiteral(ctx) { | ||
return this.generateArrayLiteral(ctx); | ||
} | ||
visitUndefinedLiteral(ctx) { | ||
return this.leafHelper(this.Types._undefined, ctx); | ||
} | ||
visitNullLiteral(ctx) { | ||
return this.leafHelper(this.Types._null, ctx); | ||
} | ||
visitBooleanLiteral(ctx) { | ||
return this.leafHelper(this.Types._bool, ctx); | ||
} | ||
visitUndefinedLiteral(ctx) { | ||
return this.leafHelper(this.Types._undefined, ctx); | ||
} | ||
visitStringLiteral(ctx) { | ||
return this.leafHelper(this.Types._string, ctx); | ||
} | ||
visitBooleanLiteral(ctx) { | ||
return this.leafHelper(this.Types._bool, ctx); | ||
} | ||
visitRegularExpressionLiteral(ctx) { | ||
return this.leafHelper(this.Types._regex, ctx); | ||
} | ||
visitStringLiteral(ctx) { | ||
return this.leafHelper(this.Types._string, ctx); | ||
} | ||
visitIntegerLiteral(ctx) { | ||
return this.leafHelper(this.Types._long, ctx); | ||
} | ||
visitRegularExpressionLiteral(ctx) { | ||
return this.leafHelper(this.Types._regex, ctx); | ||
} | ||
visitDecimalLiteral(ctx) { | ||
return this.leafHelper(this.Types._decimal, ctx); | ||
} | ||
visitIntegerLiteral(ctx) { | ||
return this.leafHelper(this.Types._long, ctx); | ||
} | ||
visitHexIntegerLiteral(ctx) { | ||
return this.leafHelper(this.Types._hex, ctx); | ||
} | ||
visitDecimalLiteral(ctx) { | ||
return this.leafHelper(this.Types._decimal, ctx); | ||
} | ||
visitOctalIntegerLiteral(ctx) { | ||
return this.leafHelper(this.Types._octal, ctx); | ||
} | ||
visitHexIntegerLiteral(ctx) { | ||
return this.leafHelper(this.Types._hex, ctx); | ||
} | ||
visitElision(ctx) { | ||
ctx.type = this.Types._undefined; | ||
if (ctx.type.template) { | ||
return ctx.type.template(); | ||
} | ||
return 'null'; | ||
} | ||
visitOctalIntegerLiteral(ctx) { | ||
return this.leafHelper(this.Types._octal, ctx); | ||
} | ||
visitElision(ctx) { | ||
ctx.type = this.Types._undefined; | ||
if (ctx.type.template) { | ||
return ctx.type.template(); | ||
visitNewExpression(ctx) { | ||
// Skip new because already included in function calls for constructors. | ||
ctx.singleExpression().wasNew = true; // for dates only | ||
const res = this.visit(ctx.singleExpression()); | ||
ctx.type = this.findTypedNode(ctx.singleExpression()).type; | ||
return res; | ||
} | ||
return 'null'; | ||
} | ||
visitNewExpression(ctx) { | ||
// Skip new because already included in function calls for constructors. | ||
ctx.singleExpression().wasNew = true; // for dates only | ||
const res = this.visit(ctx.singleExpression()); | ||
ctx.type = this.findTypedNode(ctx.singleExpression()).type; | ||
return res; | ||
} | ||
visitRelationalExpression(ctx) { | ||
ctx.type = this.Types._boolean; | ||
const lhs = this.visit(ctx.singleExpression()[0]); | ||
const rhs = this.visit(ctx.singleExpression()[1]); | ||
const op = this.visit(ctx.children[1]); | ||
if (this.Syntax.equality) { | ||
return this.Syntax.equality.template(lhs, op, rhs); | ||
visitRelationalExpression(ctx) { | ||
ctx.type = this.Types._boolean; | ||
const lhs = this.visit(ctx.singleExpression()[0]); | ||
const rhs = this.visit(ctx.singleExpression()[1]); | ||
const op = this.visit(ctx.children[1]); | ||
if (this.Syntax.equality) { | ||
return this.Syntax.equality.template(lhs, op, rhs); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitEqualityExpression(ctx) { | ||
ctx.type = this.Types._boolean; | ||
const lhs = this.visit(ctx.singleExpression()[0]); | ||
const rhs = this.visit(ctx.singleExpression()[1]); | ||
const op = this.visit(ctx.children[1]); | ||
if (this.Syntax.equality) { | ||
return this.Syntax.equality.template(lhs, op, rhs); | ||
visitEqualityExpression(ctx) { | ||
ctx.type = this.Types._boolean; | ||
const lhs = this.visit(ctx.singleExpression()[0]); | ||
const rhs = this.visit(ctx.singleExpression()[1]); | ||
const op = this.visit(ctx.children[1]); | ||
if (this.Syntax.equality) { | ||
return this.Syntax.equality.template(lhs, op, rhs); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitLogicalAndExpression(ctx) { | ||
if (this.Syntax.and) { | ||
return this.Syntax.and.template( | ||
ctx.singleExpression().map((t) => (this.visit(t))) | ||
); | ||
visitLogicalAndExpression(ctx) { | ||
if (this.Syntax.and) { | ||
return this.Syntax.and.template( | ||
ctx.singleExpression().map((t) => this.visit(t)) | ||
); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitLogicalOrExpression(ctx) { | ||
if (this.Syntax.or) { | ||
return this.Syntax.or.template( | ||
ctx.singleExpression().map((t) => ( this.visit(t) )) | ||
); | ||
visitLogicalOrExpression(ctx) { | ||
if (this.Syntax.or) { | ||
return this.Syntax.or.template( | ||
ctx.singleExpression().map((t) => this.visit(t)) | ||
); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitNotExpression(ctx) { | ||
if (this.Syntax.not) { | ||
return this.Syntax.not.template( | ||
this.visit(ctx.singleExpression()) | ||
); | ||
visitNotExpression(ctx) { | ||
if (this.Syntax.not) { | ||
return this.Syntax.not.template(this.visit(ctx.singleExpression())); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitBitAndExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map(m => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
visitBitAndExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map((m) => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitBitXOrExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map(m => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
visitBitXOrExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map((m) => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitBitOrExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map(m => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
visitBitOrExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map((m) => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitBitNotExpression(ctx) { | ||
if (this.Syntax.unary.template) { | ||
return this.Syntax.unary.template( | ||
'~', | ||
this.visit(ctx.singleExpression()) | ||
); | ||
visitBitNotExpression(ctx) { | ||
if (this.Syntax.unary.template) { | ||
return this.Syntax.unary.template( | ||
'~', | ||
this.visit(ctx.singleExpression()) | ||
); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitUnaryPlusExpression(ctx) { | ||
if (this.Syntax.unary.template) { | ||
return this.Syntax.unary.template( | ||
'+', | ||
this.visit(ctx.singleExpression()) | ||
); | ||
visitUnaryPlusExpression(ctx) { | ||
if (this.Syntax.unary.template) { | ||
return this.Syntax.unary.template( | ||
'+', | ||
this.visit(ctx.singleExpression()) | ||
); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitUnaryMinusExpression(ctx) { | ||
if (this.Syntax.unary.template) { | ||
return this.Syntax.unary.template( | ||
'-', | ||
this.visit(ctx.singleExpression()) | ||
); | ||
visitUnaryMinusExpression(ctx) { | ||
if (this.Syntax.unary.template) { | ||
return this.Syntax.unary.template( | ||
'-', | ||
this.visit(ctx.singleExpression()) | ||
); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitAdditiveExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map(m => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
visitAdditiveExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map((m) => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitMultiplicativeExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map(m => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
visitMultiplicativeExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map((m) => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitBitShiftExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map(m => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
visitBitShiftExpression(ctx) { | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map((m) => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitParenthesizedExpression(ctx) { | ||
if (this.Syntax.parens.template) { | ||
const kids = this.visit(ctx.expressionSequence()); | ||
return this.Syntax.parens.template(kids); | ||
visitParenthesizedExpression(ctx) { | ||
if (this.Syntax.parens.template) { | ||
const kids = this.visit(ctx.expressionSequence()); | ||
return this.Syntax.parens.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitFuncDefExpression(ctx) { | ||
return this.generateFuncDefExpression(ctx); | ||
} | ||
visitFuncDefExpression(ctx) { | ||
return this.generateFuncDefExpression(ctx); | ||
} | ||
/* | ||
* | ||
* Process Methods | ||
* | ||
*/ | ||
/* | ||
* | ||
* Process Methods | ||
* | ||
*/ | ||
/* Numerical process methods */ | ||
processNumber(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
/* Numerical process methods */ | ||
processNumber(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
processInt32(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
processInt32(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
processDouble(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
processDouble(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
/** | ||
* Check arguments then execute in the same way as regex literals. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processRegExp(ctx) { | ||
this.checkArguments( | ||
this.Symbols.RegExp.args, this.getArguments(ctx), 'RegExp' | ||
); | ||
return this.process_regex(ctx); | ||
} | ||
/** | ||
* This looks like non-camelcase because the name of the basic type is "_regex" | ||
* and the process methods are constructed with "Process" + <type name>. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
process_regex(ctx) { // eslint-disable-line camelcase | ||
ctx.type = this.Types._regex; | ||
let pattern; | ||
let flags; | ||
try { | ||
const regexobj = this.executeJavascript(ctx.getText()); | ||
pattern = regexobj.source; | ||
flags = regexobj.flags; | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
/** | ||
* Check arguments then execute in the same way as regex literals. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processRegExp(ctx) { | ||
this.checkArguments( | ||
this.Symbols.RegExp.args, | ||
this.getArguments(ctx), | ||
'RegExp' | ||
); | ||
return this.process_regex(ctx); | ||
} | ||
let targetflags = flags.replace(/[imuyg]/g, m => this.Syntax.regexFlags[m]); | ||
targetflags = targetflags === '' ? | ||
'' : | ||
`${targetflags.split('').sort().join('')}`; | ||
/** | ||
* This looks like non-camelcase because the name of the basic type is "_regex" | ||
* and the process methods are constructed with "Process" + <type name>. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
process_regex(ctx) { | ||
// eslint-disable-line camelcase | ||
ctx.type = this.Types._regex; | ||
let pattern; | ||
let flags; | ||
return this.generateLiteral(ctx, ctx.type, [pattern, targetflags], 'RegExp'); | ||
} | ||
try { | ||
const regexobj = this.executeJavascript(ctx.getText()); | ||
pattern = regexobj.source; | ||
flags = regexobj.flags; | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
} | ||
/** | ||
* Process BSON regexps because we need to verify the flags are valid. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {string} | ||
*/ | ||
processBSONRegExp(ctx) { | ||
return this.generateBSONRegex( | ||
ctx, this.Types.BSONRegExpType, this.Symbols.BSONRegExp | ||
); | ||
} | ||
let targetflags = flags.replace( | ||
/[imuyg]/g, | ||
(m) => this.Syntax.regexFlags[m] | ||
); | ||
targetflags = | ||
targetflags === '' ? '' : `${targetflags.split('').sort().join('')}`; | ||
/** | ||
* The arguments to Code can be either a string or actual javascript code. | ||
* Manually check arguments here because first argument can be any JS, and we | ||
* don't want to ever visit that node. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processCodeFromJS(ctx) { | ||
return this.generateBSONCode(ctx, this.Types.Code, this.Symbols.Code, false); | ||
} | ||
/** | ||
* ObjectId needs preprocessing because it needs to be executed. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processObjectId(ctx) { | ||
ctx.type = this.Types.ObjectId; | ||
const symbolType = this.Symbols.ObjectId; | ||
const argsList = this.getArguments(ctx); | ||
this.checkArguments(symbolType.args, argsList, 'ObjectId'); | ||
let hexstr; | ||
try { | ||
hexstr = this.executeJavascript(`new ${ctx.getText()}`).toHexString(); | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
return this.generateLiteral( | ||
ctx, | ||
ctx.type, | ||
[pattern, targetflags], | ||
'RegExp' | ||
); | ||
} | ||
const args = argsList.length === 0 ? [] : [hexstr]; | ||
return this.generateCall( | ||
ctx, symbolType, args, 'ObjectId', `(${hexstr})` | ||
); | ||
} | ||
/** | ||
* Long needs preprocessing because it needs to be executed. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processLong(ctx) { | ||
ctx.type = this.Types.Long; | ||
const symbolType = this.Symbols.Long; | ||
let longstr; | ||
this.checkArguments(symbolType.args, this.getArguments(ctx), 'Long'); | ||
try { | ||
longstr = this.executeJavascript(`new ${ctx.getText()}`).toString(); | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
/** | ||
* Process BSON regexps because we need to verify the flags are valid. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {string} | ||
*/ | ||
processBSONRegExp(ctx) { | ||
return this.generateBSONRegex( | ||
ctx, | ||
this.Types.BSONRegExpType, | ||
this.Symbols.BSONRegExp | ||
); | ||
} | ||
return this.generateCall( | ||
ctx, symbolType, [longstr, '_long'], 'Long', `(${longstr})` | ||
); | ||
} | ||
processLongfromBits(ctx) { | ||
if ('emitLongfromBits' in this) { | ||
return this.emitLongfromBits(ctx); | ||
/** | ||
* The arguments to Code can be either a string or actual javascript code. | ||
* Manually check arguments here because first argument can be any JS, and we | ||
* don't want to ever visit that node. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processCodeFromJS(ctx) { | ||
return this.generateBSONCode( | ||
ctx, | ||
this.Types.Code, | ||
this.Symbols.Code, | ||
false | ||
); | ||
} | ||
return this.processLong(ctx); | ||
} | ||
/** | ||
* Decimal128 needs preprocessing because it needs to be executed. Check | ||
* argument length manually because 'Buffer' not supported. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processDecimal128(ctx) { | ||
ctx.type = this.Types.Decimal128; | ||
const symbolType = this.Symbols.Decimal128; | ||
let decstr; | ||
const argList = this.getArguments(ctx); | ||
/** | ||
* ObjectId needs preprocessing because it needs to be executed. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processObjectId(ctx) { | ||
ctx.type = this.Types.ObjectId; | ||
const symbolType = this.Symbols.ObjectId; | ||
const argsList = this.getArguments(ctx); | ||
if (argList.length !== 1) { | ||
throw new BsonTranspilersArgumentError( | ||
'Argument count mismatch: Decimal128 requires one argument' | ||
this.checkArguments(symbolType.args, argsList, 'ObjectId'); | ||
let hexstr; | ||
try { | ||
hexstr = this.executeJavascript(`new ${ctx.getText()}`).toHexString(); | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
} | ||
const args = argsList.length === 0 ? [] : [hexstr]; | ||
return this.generateCall( | ||
ctx, | ||
symbolType, | ||
args, | ||
'ObjectId', | ||
`(${hexstr})` | ||
); | ||
} | ||
try { | ||
decstr = this.executeJavascript(`new ${ctx.getText()}`).toString(); | ||
} catch (error) { | ||
// TODO: this isn't quite right because it catches all type errors. | ||
if (error.name === 'TypeError' || error.code === 'ERR_INVALID_ARG_TYPE') { | ||
throw new BsonTranspilersArgumentError(error.message); | ||
/** | ||
* Long needs preprocessing because it needs to be executed. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processLong(ctx) { | ||
ctx.type = this.Types.Long; | ||
const symbolType = this.Symbols.Long; | ||
let longstr; | ||
this.checkArguments(symbolType.args, this.getArguments(ctx), 'Long'); | ||
try { | ||
longstr = this.executeJavascript(`new ${ctx.getText()}`).toString(); | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
} | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
return this.generateCall( | ||
ctx, | ||
symbolType, | ||
[longstr, '_long'], | ||
'Long', | ||
`(${longstr})` | ||
); | ||
} | ||
return this.generateCall( | ||
ctx, symbolType, [decstr], 'Decimal128', `(${decstr})` | ||
); | ||
} | ||
/** | ||
* This is a bit weird because we can just convert to string directly. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processLongtoString(ctx) { | ||
ctx.type = this.Types._string; | ||
const long = ctx.singleExpression().singleExpression(); | ||
let longstr; | ||
this.checkArguments( | ||
[[this.Types._numeric, null]], this.getArguments(ctx), 'Long toString' | ||
); | ||
try { | ||
longstr = this.executeJavascript(`new ${long.getText()}`).toString(); | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
processLongfromBits(ctx) { | ||
if ('emitLongfromBits' in this) { | ||
return this.emitLongfromBits(ctx); | ||
} | ||
return this.processLong(ctx); | ||
} | ||
return ctx.type.template ? ctx.type.template(longstr) : `'${longstr}'`; | ||
} | ||
/** | ||
* Preprocessed because different target languages need different info out | ||
* of the constructed date, so we want to execute it. Passes a constructed | ||
* date object to the template or generator. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processDate(ctx) { | ||
const isStr = !(ctx.getText().includes('ISODate') || ctx.wasNew); | ||
const symbolType = this.Symbols.Date; | ||
/** | ||
* Decimal128 needs preprocessing because it needs to be executed. Check | ||
* argument length manually because 'Buffer' not supported. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processDecimal128(ctx) { | ||
ctx.type = this.Types.Decimal128; | ||
const symbolType = this.Symbols.Decimal128; | ||
let decstr; | ||
const argList = this.getArguments(ctx); | ||
ctx.type = this.Types.Date; | ||
if (isStr) { | ||
ctx.type = this.Types._string; | ||
this.requiredImports[201] = true; | ||
} | ||
const argsList = this.getArguments(ctx); | ||
let date = null; | ||
if (argsList.length !== 0) { | ||
try { | ||
this.checkArguments(this.Symbols.Date.args, argsList, 'Date'); | ||
} catch (e) { | ||
if (argList.length !== 1) { | ||
throw new BsonTranspilersArgumentError( | ||
'Invalid argument to Date: requires no args, one string/number, or up to 7 numbers' | ||
'Argument count mismatch: Decimal128 requires one argument' | ||
); | ||
} | ||
let text = ctx.getText(); | ||
text = text.startsWith('new ') ? text : `new ${text}`; | ||
try { | ||
date = this.executeJavascript(text); | ||
decstr = this.executeJavascript(`new ${ctx.getText()}`).toString(); | ||
} catch (error) { | ||
// TODO: this isn't quite right because it catches all type errors. | ||
if ( | ||
error.name === 'TypeError' || | ||
error.code === 'ERR_INVALID_ARG_TYPE' | ||
) { | ||
throw new BsonTranspilersArgumentError(error.message); | ||
} | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
} | ||
return this.generateCall( | ||
ctx, | ||
symbolType, | ||
[decstr], | ||
'Decimal128', | ||
`(${decstr})` | ||
); | ||
} | ||
const dargs = `Date(${date | ||
? this.Types._string.template(date.toUTCString()) | ||
: ''})`; | ||
return this.generateCall( | ||
ctx, symbolType, [date, isStr], '', dargs, isStr, true | ||
); | ||
} | ||
processObjectIdCreateFromTime(ctx) { | ||
return this.generateObjectIdFromTime(ctx); | ||
} | ||
/** | ||
* This is a bit weird because we can just convert to string directly. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processLongtoString(ctx) { | ||
ctx.type = this.Types._string; | ||
const long = ctx.singleExpression().singleExpression(); | ||
let longstr; | ||
this.checkArguments( | ||
[[this.Types._numeric, null]], | ||
this.getArguments(ctx), | ||
'Long toString' | ||
); | ||
processBinary() { | ||
throw new BsonTranspilersUnimplementedError('Binary type not supported'); | ||
} | ||
try { | ||
longstr = this.executeJavascript(`new ${long.getText()}`).toString(); | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
} | ||
return ctx.type.template ? ctx.type.template(longstr) : `'${longstr}'`; | ||
} | ||
/* | ||
* | ||
* Helper Methods | ||
* | ||
*/ | ||
/** | ||
* Preprocessed because different target languages need different info out | ||
* of the constructed date, so we want to execute it. Passes a constructed | ||
* date object to the template or generator. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processDate(ctx) { | ||
const isStr = !(ctx.getText().includes('ISODate') || ctx.wasNew); | ||
const symbolType = this.Symbols.Date; | ||
/** | ||
* Takes in the constructor name of a node and returns a human-readable | ||
* node name. Used for error reporting, must be defined by all visitors. | ||
* | ||
* @param {String} name | ||
* @return {String} | ||
*/ | ||
renameNode(name) { | ||
return name ? name.replace('_stmt', '') : 'Expression'; | ||
} | ||
ctx.type = this.Types.Date; | ||
if (isStr) { | ||
ctx.type = this.Types._string; | ||
this.requiredImports[201] = true; | ||
} | ||
/** | ||
* There are no named arguments in javascript, so we can just return directly. | ||
* @param {Array} expected | ||
* @param {ParserRuleContext} node | ||
* @return {Array} | ||
*/ | ||
checkNamedArgs(expected, node) { | ||
return [expected, node]; | ||
} | ||
const argsList = this.getArguments(ctx); | ||
let date = null; | ||
/** | ||
* Execute javascript in a sandbox. | ||
* | ||
* @param {String} input | ||
* @return {*} result of execution | ||
*/ | ||
executeJavascript(input) { | ||
const sandbox = { | ||
RegExp: RegExp, | ||
BSONRegExp: bson.BSONRegExp, | ||
// Binary: bson.Binary, | ||
DBRef: bson.DBRef, | ||
Decimal128: bson.Decimal128, | ||
Double: bson.Double, | ||
Int32: bson.Int32, | ||
Long: bson.Long, | ||
Int64: bson.Long, | ||
Map: bson.Map, | ||
MaxKey: bson.MaxKey, | ||
MinKey: bson.MinKey, | ||
ObjectID: bson.ObjectID, | ||
ObjectId: bson.ObjectID, | ||
BSONSymbol: bson.BSONSymbol, | ||
Timestamp: bson.Timestamp, | ||
Code: function(c, s) { | ||
return new bson.Code(c, s); | ||
}, | ||
Date: function(s) { | ||
const args = Array.from(arguments); | ||
if (argsList.length !== 0) { | ||
try { | ||
this.checkArguments(this.Symbols.Date.args, argsList, 'Date'); | ||
} catch (e) { | ||
throw new BsonTranspilersArgumentError( | ||
'Invalid argument to Date: requires no args, one string/number, or up to 7 numbers' | ||
); | ||
} | ||
if (args.length === 1) { | ||
return new Date(s); | ||
let text = ctx.getText(); | ||
text = text.startsWith('new ') ? text : `new ${text}`; | ||
try { | ||
date = this.executeJavascript(text); | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
} | ||
} | ||
const dargs = `Date(${ | ||
date ? this.Types._string.template(date.toUTCString()) : '' | ||
})`; | ||
return this.generateCall( | ||
ctx, | ||
symbolType, | ||
[date, isStr], | ||
'', | ||
dargs, | ||
isStr, | ||
true | ||
); | ||
} | ||
return new Date(Date.UTC(...args)); | ||
}, | ||
Buffer: Buffer, | ||
__result: {} | ||
}; | ||
const res = vm.runInContext('__result = ' + input, vm.createContext(sandbox)); | ||
return res; | ||
} | ||
processObjectIdCreateFromTime(ctx) { | ||
return this.generateObjectIdFromTime(ctx); | ||
} | ||
/* | ||
* Accessor Functions. | ||
* | ||
* These MUST be defined by every visitor. Each function is a wrapper around | ||
* a tree node. They are required so that the CodeGenerationVisitor and the | ||
* Generators can access tree elements without needing to know which tree they | ||
* are visiting or the ANTLR name of the node. | ||
*/ | ||
processBinary() { | ||
throw new BsonTranspilersUnimplementedError('Binary type not supported'); | ||
} | ||
getArguments(ctx) { | ||
if (!('arguments' in ctx) || | ||
/* | ||
* | ||
* Helper Methods | ||
* | ||
*/ | ||
/** | ||
* Takes in the constructor name of a node and returns a human-readable | ||
* node name. Used for error reporting, must be defined by all visitors. | ||
* | ||
* @param {String} name | ||
* @return {String} | ||
*/ | ||
renameNode(name) { | ||
return name ? name.replace('_stmt', '') : 'Expression'; | ||
} | ||
/** | ||
* There are no named arguments in javascript, so we can just return directly. | ||
* @param {Array} expected | ||
* @param {ParserRuleContext} node | ||
* @return {Array} | ||
*/ | ||
checkNamedArgs(expected, node) { | ||
return [expected, node]; | ||
} | ||
/** | ||
* Execute javascript in a sandbox. | ||
* | ||
* @param {String} input | ||
* @return {*} result of execution | ||
*/ | ||
executeJavascript(input) { | ||
const sandbox = { | ||
RegExp: RegExp, | ||
BSONRegExp: bson.BSONRegExp, | ||
// Binary: bson.Binary, | ||
DBRef: bson.DBRef, | ||
Decimal128: bson.Decimal128, | ||
Double: bson.Double, | ||
Int32: bson.Int32, | ||
Long: bson.Long, | ||
Int64: bson.Long, | ||
Map: bson.Map, | ||
MaxKey: bson.MaxKey, | ||
MinKey: bson.MinKey, | ||
ObjectID: bson.ObjectId, | ||
ObjectId: bson.ObjectId, | ||
BSONSymbol: bson.BSONSymbol, | ||
Timestamp: bson.Timestamp, | ||
Code: function (c, s) { | ||
return new bson.Code(c, s); | ||
}, | ||
Date: function (s) { | ||
const args = Array.from(arguments); | ||
if (args.length === 1) { | ||
return new Date(s); | ||
} | ||
return new Date(Date.UTC(...args)); | ||
}, | ||
Buffer: Buffer, | ||
__result: {}, | ||
}; | ||
const res = vm.runInContext( | ||
'__result = ' + input, | ||
vm.createContext(sandbox) | ||
); | ||
return res; | ||
} | ||
/* | ||
* Accessor Functions. | ||
* | ||
* These MUST be defined by every visitor. Each function is a wrapper around | ||
* a tree node. They are required so that the CodeGenerationVisitor and the | ||
* Generators can access tree elements without needing to know which tree they | ||
* are visiting or the ANTLR name of the node. | ||
*/ | ||
getArguments(ctx) { | ||
if ( | ||
!('arguments' in ctx) || | ||
!('argumentList' in ctx.arguments()) || | ||
!ctx.arguments().argumentList()) { | ||
return []; | ||
!ctx.arguments().argumentList() | ||
) { | ||
return []; | ||
} | ||
return ctx.arguments().argumentList().singleExpression(); | ||
} | ||
return ctx.arguments().argumentList().singleExpression(); | ||
} | ||
getArgumentAt(ctx, i) { | ||
return this.getArguments(ctx)[i]; | ||
} | ||
getArgumentAt(ctx, i) { | ||
return this.getArguments(ctx)[i]; | ||
} | ||
getFunctionCallName(ctx) { | ||
return ctx.singleExpression(); | ||
} | ||
getIfIdentifier(ctx) { | ||
if ('identifierName' in ctx) { | ||
getFunctionCallName(ctx) { | ||
return ctx.singleExpression(); | ||
} | ||
return ctx; | ||
} | ||
getAttributeLHS(ctx) { | ||
return ctx.singleExpression(); | ||
} | ||
getIfIdentifier(ctx) { | ||
if ('identifierName' in ctx) { | ||
return ctx.singleExpression(); | ||
} | ||
return ctx; | ||
} | ||
getAttributeRHS(ctx) { | ||
return ctx.identifierName(); | ||
} | ||
getAttributeLHS(ctx) { | ||
return ctx.singleExpression(); | ||
} | ||
getList(ctx) { | ||
if (!('elementList' in ctx) || !ctx.elementList()) { | ||
return []; | ||
getAttributeRHS(ctx) { | ||
return ctx.identifierName(); | ||
} | ||
const elisions = ctx.elementList().elision(); | ||
const elements = ctx.elementList().singleExpression(); | ||
return ctx.elementList().children.filter((c) => { | ||
return elisions.indexOf(c) !== -1 || elements.indexOf(c) !== -1; | ||
}); | ||
} | ||
getArray(ctx) { | ||
if (!('arrayLiteral' in ctx)) { | ||
return false; | ||
getList(ctx) { | ||
if (!('elementList' in ctx) || !ctx.elementList()) { | ||
return []; | ||
} | ||
const elisions = ctx.elementList().elision(); | ||
const elements = ctx.elementList().singleExpression(); | ||
return ctx.elementList().children.filter((c) => { | ||
return elisions.indexOf(c) !== -1 || elements.indexOf(c) !== -1; | ||
}); | ||
} | ||
return ctx.arrayLiteral(); | ||
} | ||
getObject(ctx) { | ||
if (!('objectLiteral' in ctx)) { | ||
return false; | ||
getArray(ctx) { | ||
if (!('arrayLiteral' in ctx)) { | ||
return false; | ||
} | ||
return ctx.arrayLiteral(); | ||
} | ||
return ctx.objectLiteral(); | ||
} | ||
getKeyValueList(ctx) { | ||
if ('propertyNameAndValueList' in ctx && ctx.propertyNameAndValueList()) { | ||
return ctx.propertyNameAndValueList().propertyAssignment(); | ||
getObject(ctx) { | ||
if (!('objectLiteral' in ctx)) { | ||
return false; | ||
} | ||
return ctx.objectLiteral(); | ||
} | ||
return []; | ||
} | ||
getKeyStr(ctx) { | ||
return removeQuotes(this.visit(ctx.propertyName())); | ||
} | ||
getKeyValueList(ctx) { | ||
if ('propertyNameAndValueList' in ctx && ctx.propertyNameAndValueList()) { | ||
return ctx.propertyNameAndValueList().propertyAssignment(); | ||
} | ||
return []; | ||
} | ||
getValue(ctx) { | ||
return ctx.singleExpression(); | ||
} | ||
getKeyStr(ctx) { | ||
return removeQuotes(this.visit(ctx.propertyName())); | ||
} | ||
isSubObject(ctx) { | ||
return 'propertyName' in ctx.parentCtx.parentCtx; | ||
} | ||
getValue(ctx) { | ||
return ctx.singleExpression(); | ||
} | ||
getParentKeyStr(ctx) { | ||
// For a given sub document, get its key. | ||
return this.getKeyStr(ctx.parentCtx.parentCtx); | ||
} | ||
isSubObject(ctx) { | ||
return 'propertyName' in ctx.parentCtx.parentCtx; | ||
} | ||
getObjectChild(ctx) { | ||
return ctx.getChild(0); | ||
} | ||
}; | ||
getParentKeyStr(ctx) { | ||
// For a given sub document, get its key. | ||
return this.getKeyStr(ctx.parentCtx.parentCtx); | ||
} | ||
getObjectChild(ctx) { | ||
return ctx.getChild(0); | ||
} | ||
}; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/* eslint new-cap: 0 camelcase: 0 */ | ||
@@ -6,3 +7,3 @@ const bson = require('bson'); | ||
BsonTranspilersTypeError, | ||
BsonTranspilersRuntimeError | ||
BsonTranspilersRuntimeError, | ||
} = require('../../helper/error'); | ||
@@ -14,225 +15,256 @@ const { removeQuotes } = require('../../helper/format'); | ||
*/ | ||
module.exports = (Visitor) => class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
this.IGNORE = 'a unique thing'; | ||
} | ||
module.exports = (Visitor) => | ||
class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
this.IGNORE = 'a unique thing'; | ||
} | ||
start(ctx) { | ||
return this.returnResult(ctx); | ||
} | ||
/** | ||
* Overrides the helper function to instantiate the object instead of | ||
* concatenating the strings. | ||
* | ||
* @param {ParserRuleContext} ctx - The function call node | ||
* @param {Object} lhsType - The type | ||
* @param {Array} args - Arguments to the template | ||
* | ||
* @return {String} | ||
*/ | ||
generateCall(ctx, lhsType, args) { | ||
if (`emit${lhsType.id}` in this) { | ||
return this[`emit${lhsType.id}`](ctx, ...args); | ||
start(ctx) { | ||
return this.returnResult(ctx); | ||
} | ||
const lhs = this.visit(this.getFunctionCallName(ctx)); | ||
return this.returnFunctionCallLhsRhs(lhs, args, lhsType); | ||
} | ||
/** | ||
* Don't concatenate child nodes, return them as array. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {Object} options | ||
* @return {Array} | ||
*/ | ||
visitChildren(ctx, options) { | ||
const opts = { | ||
start: 0, step: 1, separator: '', ignore: [], children: ctx.children | ||
}; | ||
Object.assign(opts, options ? options : {}); | ||
opts.end = ('end' in opts) ? opts.end : opts.children.length - 1; | ||
const code = []; | ||
for (let i = opts.start; i <= opts.end; i += opts.step) { | ||
if (opts.ignore.indexOf(i) === -1) { | ||
code.push(this.visit( | ||
opts.children[i] | ||
)); | ||
/** | ||
* Overrides the helper function to instantiate the object instead of | ||
* concatenating the strings. | ||
* | ||
* @param {ParserRuleContext} ctx - The function call node | ||
* @param {Object} lhsType - The type | ||
* @param {Array} args - Arguments to the template | ||
* | ||
* @return {String} | ||
*/ | ||
generateCall(ctx, lhsType, args) { | ||
if (`emit${lhsType.id}` in this) { | ||
return this[`emit${lhsType.id}`](ctx, ...args); | ||
} | ||
const lhs = this.visit(this.getFunctionCallName(ctx)); | ||
return this.returnFunctionCallLhsRhs(lhs, args, lhsType); | ||
} | ||
const result = code.filter((c) => c !== this.IGNORE); | ||
if (result.length === 1) { | ||
return result[0]; | ||
} | ||
return result; | ||
} | ||
returnFunctionCallRhs(rhs) { | ||
return rhs; | ||
} | ||
/** | ||
* Don't concatenate child nodes, return them as array. | ||
* | ||
* @param {ParserRuleContext} ctx | ||
* @param {Object} options | ||
* @return {Array} | ||
*/ | ||
visitChildren(ctx, options) { | ||
const opts = { | ||
start: 0, | ||
step: 1, | ||
separator: '', | ||
ignore: [], | ||
children: ctx.children, | ||
}; | ||
Object.assign(opts, options ? options : {}); | ||
opts.end = 'end' in opts ? opts.end : opts.children.length - 1; | ||
returnFunctionCallLhs(code, name) { | ||
const types = { | ||
100: bson.Code, 101: bson.ObjectId, 102: bson.Binary, 103: bson.DBRef, | ||
104: bson.Double, 105: bson.Int32, 106: bson.Long, 107: bson.MinKey, | ||
108: bson.MaxKey, 109: bson.BSONRegExp, 110: bson.Timestamp, | ||
111: bson.BSONSymbol, 112: bson.Decimal128, 200: Date, 8: RegExp, 2: Number, | ||
10: Object | ||
}; | ||
const result = types[code]; | ||
if (result === undefined) { | ||
throw new BsonTranspilersReferenceError(`Cannot instantiate ${name} with code=${code}`); | ||
const code = []; | ||
for (let i = opts.start; i <= opts.end; i += opts.step) { | ||
if (opts.ignore.indexOf(i) === -1) { | ||
code.push(this.visit(opts.children[i])); | ||
} | ||
} | ||
const result = code.filter((c) => c !== this.IGNORE); | ||
if (result.length === 1) { | ||
return result[0]; | ||
} | ||
return result; | ||
} | ||
return result; | ||
} | ||
returnFunctionCallLhsRhs(lhs, args, lhsType) { | ||
if (args.length === 1 && args[0] === undefined) { | ||
args = []; | ||
returnFunctionCallRhs(rhs) { | ||
return rhs; | ||
} | ||
if (lhsType && lhsType.argsTemplate) { | ||
return lhsType.argsTemplate.bind(this.getState())(lhs, ...args); | ||
returnFunctionCallLhs(code, name) { | ||
const types = { | ||
100: bson.Code, | ||
101: bson.ObjectId, | ||
102: bson.Binary, | ||
103: bson.DBRef, | ||
104: bson.Double, | ||
105: bson.Int32, | ||
106: bson.Long, | ||
107: bson.MinKey, | ||
108: bson.MaxKey, | ||
109: bson.BSONRegExp, | ||
110: bson.Timestamp, | ||
111: bson.BSONSymbol, | ||
112: bson.Decimal128, | ||
200: Date, | ||
8: RegExp, | ||
2: Number, | ||
10: Object, | ||
}; | ||
const result = types[code]; | ||
if (result === undefined) { | ||
throw new BsonTranspilersReferenceError( | ||
`Cannot instantiate ${name} with code=${code}` | ||
); | ||
} | ||
return result; | ||
} | ||
let expr; | ||
try { | ||
if (lhsType.callable === this.SYMBOL_TYPE.CONSTRUCTOR) { | ||
expr = new lhs(...args); | ||
} else { | ||
expr = lhs(...args); | ||
returnFunctionCallLhsRhs(lhs, args, lhsType) { | ||
if (args.length === 1 && args[0] === undefined) { | ||
args = []; | ||
} | ||
} catch (e) { | ||
if (e.message.includes('constructor')) { | ||
try { | ||
if (lhsType && lhsType.argsTemplate) { | ||
return lhsType.argsTemplate.bind(this.getState())(lhs, ...args); | ||
} | ||
let expr; | ||
try { | ||
if (lhsType.callable === this.SYMBOL_TYPE.CONSTRUCTOR) { | ||
expr = new lhs(...args); | ||
} else { | ||
expr = lhs(...args); | ||
} catch (e2) { | ||
e2.message = `Error constructing type: ${e2.message}`; | ||
throw e2; | ||
} | ||
} else { | ||
e.message = `Error constructing type: ${e.message}`; | ||
throw e; | ||
} catch (e) { | ||
if (e.message.includes('constructor')) { | ||
try { | ||
expr = lhs(...args); | ||
} catch (e2) { | ||
e2.message = `Error constructing type: ${e2.message}`; | ||
throw e2; | ||
} | ||
} else { | ||
e.message = `Error constructing type: ${e.message}`; | ||
throw e; | ||
} | ||
} | ||
return expr; | ||
} | ||
return expr; | ||
} | ||
returnAttributeAccess(lhs, rhs, type) { | ||
if (type === null) { | ||
throw new BsonTranspilersTypeError(`Error: ${rhs} is undefined and cannot be called`); | ||
} | ||
let expr = lhs[rhs]; | ||
if (type.attr[rhs].template) { | ||
expr = type.attr[rhs].template(lhs, rhs); | ||
returnAttributeAccess(lhs, rhs, type) { | ||
if (type === null) { | ||
throw new BsonTranspilersTypeError( | ||
`Error: ${rhs} is undefined and cannot be called` | ||
); | ||
} | ||
let expr = lhs[rhs]; | ||
if (type.attr[rhs].template) { | ||
expr = type.attr[rhs].template(lhs, rhs); | ||
if (typeof expr === 'function') { | ||
return function () { | ||
return expr(...arguments); | ||
}; | ||
} | ||
} | ||
if (typeof expr === 'function') { | ||
return function() { | ||
return expr(...arguments); | ||
return function () { | ||
return lhs[rhs](...arguments); | ||
}; | ||
} | ||
return expr; | ||
} | ||
if (typeof expr === 'function') { | ||
return function() { | ||
return lhs[rhs](...arguments); | ||
}; | ||
returnParenthesis(expr) { | ||
return expr; | ||
} | ||
return expr; | ||
} | ||
returnParenthesis(expr) { | ||
return expr; | ||
} | ||
returnSet(args) { | ||
return args; | ||
} | ||
returnSet(args) { | ||
return args; | ||
} | ||
returnComparison(ctx) { | ||
return ctx.children.reduce((s, node, i, arr) => { | ||
if (i === arr.length - 1) { | ||
// Always visit the last element | ||
return s; | ||
} | ||
if (i % 2 === 0) { | ||
// Only ops | ||
return s; | ||
} | ||
const op = this.visit(node); | ||
if ( | ||
typeof op === 'object' && | ||
op.length === 2 && | ||
op.every((k) => ['in', 'is', 'not'].indexOf(k) !== -1) | ||
) { | ||
return this.Syntax.equality.template(s, '!=', this.visit(arr[i + 1])); | ||
} | ||
if (['>', '<', '<=', '>=', '<>', '==', '!=', 'is'].indexOf(op) !== -1) { | ||
return this.Syntax.equality.template(s, op, this.visit(arr[i + 1])); | ||
} | ||
if (op === 'in' || op === 'notin') { | ||
return this.Syntax.in.template.bind(this.state)( | ||
s, | ||
op, | ||
this.visit(arr[i + 1]) | ||
); | ||
} | ||
throw new BsonTranspilersRuntimeError(`Unrecognized operation ${op}`); | ||
}, this.visit(ctx.children[0])); | ||
} | ||
returnComparison(ctx) { | ||
return ctx.children.reduce((s, node, i, arr) => { | ||
if (i === arr.length - 1) { // Always visit the last element | ||
return s; | ||
} | ||
if (i % 2 === 0) { // Only ops | ||
return s; | ||
} | ||
const op = this.visit(node); | ||
if (typeof op === 'object' && op.length === 2 && op.every((k) => (['in', 'is', 'not'].indexOf(k) !== -1))) { | ||
return this.Syntax.equality.template(s, '!=', this.visit(arr[i + 1])); | ||
} | ||
if (['>', '<', '<=', '>=', '<>', '==', '!=', 'is'].indexOf(op) !== -1) { | ||
return this.Syntax.equality.template(s, op, this.visit(arr[i + 1])); | ||
} | ||
if (op === 'in' || op === 'notin') { | ||
return this.Syntax.in.template.bind(this.state)(s, op, this.visit(arr[i + 1])); | ||
} | ||
throw new BsonTranspilersRuntimeError(`Unrecognized operation ${op}`); | ||
}, this.visit(ctx.children[0])); | ||
} | ||
emitLongfromBits(ctx) { | ||
ctx.type = this.Types.Long; | ||
const symbolType = this.Symbols.Long.attr.fromBits; | ||
const rhs = this.checkArguments( | ||
symbolType.args, | ||
this.getArguments(ctx), | ||
'Long.fromBits' | ||
); | ||
return bson.Long.fromBits(...rhs); | ||
} | ||
emitLongfromBits(ctx) { | ||
ctx.type = this.Types.Long; | ||
const symbolType = this.Symbols.Long.attr.fromBits; | ||
const rhs = this.checkArguments( | ||
symbolType.args, this.getArguments(ctx), 'Long.fromBits' | ||
); | ||
return bson.Long.fromBits(...rhs); | ||
} | ||
emitRegex(ctx, pattern, flags) { | ||
return new bson.BSONRegExp(pattern, flags); | ||
} | ||
emitRegex(ctx, pattern, flags) { | ||
return new bson.BSONRegExp(pattern, flags); | ||
} | ||
emit_array(ctx) { | ||
ctx.type = this.Types._array; | ||
this.requiredImports[9] = true; | ||
return this.getList(ctx).map((child) => this.visit(child)); | ||
} | ||
emit_array(ctx) { | ||
ctx.type = this.Types._array; | ||
this.requiredImports[9] = true; | ||
return this.getList(ctx).map((child) => ( this.visit(child) )); | ||
} | ||
emit_object(ctx) { | ||
ctx.type = this.Types._object; | ||
this.requiredImports[10] = true; | ||
const object = {}; | ||
this.getKeyValueList(ctx).map((k) => { | ||
const key = this.getKeyStr(k); | ||
if (key === '$where') { | ||
object[key] = removeQuotes(this.getValue(k).getText()); | ||
} else { | ||
object[key] = this.visit(this.getValue(k)); | ||
} | ||
}); | ||
return object; | ||
} | ||
emit_object(ctx) { | ||
ctx.type = this.Types._object; | ||
this.requiredImports[10] = true; | ||
const object = {}; | ||
this.getKeyValueList(ctx).map((k) => { | ||
const key = this.getKeyStr(k); | ||
if (key === '$where') { | ||
object[key] = removeQuotes(this.getValue(k).getText()); | ||
} else { | ||
object[key] = this.visit(this.getValue(k)); | ||
emitdatetime(ctx, date, isString) { | ||
if (date === null && isString) { | ||
return Date(); | ||
} else if (date === null) { | ||
return new Date(); | ||
} | ||
}); | ||
return object; | ||
} | ||
emitdatetime(ctx, date, isString) { | ||
if (date === null && isString) { | ||
return Date(); | ||
} else if (date === null) { | ||
return new Date(); | ||
return date; | ||
} | ||
return date; | ||
} | ||
emitDate(ctx, date, isString) { | ||
if (date === null && isString) { | ||
return Date(); | ||
} else if (date === null) { | ||
return new Date(); | ||
emitDate(ctx, date, isString) { | ||
if (date === null && isString) { | ||
return Date(); | ||
} else if (date === null) { | ||
return new Date(); | ||
} | ||
return date; | ||
} | ||
return date; | ||
} | ||
/* Numbers need emit methods because they also take type args */ | ||
/* Numbers need emit methods because they also take type args */ | ||
emitNumber(ctx, arg) { | ||
return Number(arg); | ||
} | ||
emitNumber(ctx, arg) { | ||
return Number(arg); | ||
} | ||
emitint(ctx, arg) { | ||
return new bson.Int32(arg); | ||
} | ||
emitint(ctx, arg) { | ||
return new bson.Int32(arg); | ||
} | ||
emitfloat(ctx, arg) { | ||
return new bson.Double(arg); | ||
} | ||
}; | ||
emitfloat(ctx, arg) { | ||
return new bson.Double(arg); | ||
} | ||
}; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/* | ||
@@ -5,9 +6,10 @@ * Class for handling edge cases for php code generation. Defines "emit" methods. | ||
const PHPUtils = require('./PHPUtils'); | ||
module.exports = (Visitor) => class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
module.exports = (Visitor) => | ||
class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
// Common functions used by templates | ||
this.state.utils = new PHPUtils(); | ||
} | ||
}; | ||
// Common functions used by templates | ||
this.state.utils = new PHPUtils(); | ||
} | ||
}; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/** | ||
@@ -7,4 +8,3 @@ * Common functions to use in PHP templates | ||
class PHPUtils { | ||
constructor() { | ||
} | ||
constructor() {} | ||
@@ -57,3 +57,3 @@ /** | ||
if ( | ||
(str.charAt(0) === '\'' && str.charAt(str.length - 1) === '\'') || | ||
(str.charAt(0) === "'" && str.charAt(str.length - 1) === "'") || | ||
(str.charAt(0) === '"' && str.charAt(str.length - 1) === '"') | ||
@@ -60,0 +60,0 @@ ) { |
@@ -0,8 +1,10 @@ | ||
'use strict'; | ||
/* | ||
* Class for handling edge cases for python code generation. Defines "emit" methods. | ||
*/ | ||
module.exports = (Visitor) => class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; | ||
module.exports = (Visitor) => | ||
class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/* eslint camelcase: 0 complexity: 0*/ | ||
@@ -7,3 +8,3 @@ const vm = require('vm'); | ||
BsonTranspilersInternalError, | ||
BsonTranspilersUnimplementedError | ||
BsonTranspilersUnimplementedError, | ||
} = require('../../helper/error'); | ||
@@ -19,734 +20,805 @@ const { removeQuotes } = require('../../helper/format'); | ||
*/ | ||
module.exports = (CodeGenerationVisitor) => class Visitor extends CodeGenerationVisitor { | ||
constructor() { | ||
super(); | ||
this.startRule = 'file_input'; // Name of the ANTLR rule to start | ||
module.exports = (CodeGenerationVisitor) => | ||
class Visitor extends CodeGenerationVisitor { | ||
constructor() { | ||
super(); | ||
this.startRule = 'file_input'; // Name of the ANTLR rule to start | ||
// Throw UnimplementedError for nodes with expressions that we don't support | ||
this.visitDel_stmt = | ||
this.visitPass_stmt = | ||
this.visitFlow_stmt = | ||
this.visitImport_stmt = | ||
this.visitGlobal_stmt = | ||
this.visitNonlocal_stmt = | ||
this.visitAssert_stmt = | ||
this.visitIf_stmt = | ||
this.visitWhile_stmt = | ||
this.visitFor_stmt = | ||
this.visitTry_stmt = | ||
this.visitWith_stmt = | ||
this.visitFuncdef = | ||
this.visitClassdef = | ||
this.visitDecorated = | ||
this.visitAsync_stmt = | ||
this.visitComp_iter = | ||
this.visitStar_expr = | ||
this.visitInline_if = | ||
this.visitAssign_stmt = | ||
this.visitEllipsesAtom = | ||
this.visitAugassign = | ||
this.visitImag_literal = | ||
this.unimplemented; | ||
} | ||
// Throw UnimplementedError for nodes with expressions that we don't support | ||
this.visitDel_stmt = | ||
this.visitPass_stmt = | ||
this.visitFlow_stmt = | ||
this.visitImport_stmt = | ||
this.visitGlobal_stmt = | ||
this.visitNonlocal_stmt = | ||
this.visitAssert_stmt = | ||
this.visitIf_stmt = | ||
this.visitWhile_stmt = | ||
this.visitFor_stmt = | ||
this.visitTry_stmt = | ||
this.visitWith_stmt = | ||
this.visitFuncdef = | ||
this.visitClassdef = | ||
this.visitDecorated = | ||
this.visitAsync_stmt = | ||
this.visitComp_iter = | ||
this.visitStar_expr = | ||
this.visitInline_if = | ||
this.visitAssign_stmt = | ||
this.visitEllipsesAtom = | ||
this.visitAugassign = | ||
this.visitImag_literal = | ||
this.unimplemented; | ||
} | ||
/* | ||
* | ||
* Visit Methods | ||
* | ||
*/ | ||
/* | ||
* | ||
* Visit Methods | ||
* | ||
*/ | ||
visitFile_input(ctx) { | ||
if (ctx.stmt().length !== 1) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Expression contains ${ | ||
ctx.stmt().length | ||
} statements. Input should be a single statement` | ||
); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitFile_input(ctx) { | ||
if (ctx.stmt().length !== 1) { | ||
throw new BsonTranspilersRuntimeError(`Expression contains ${ | ||
ctx.stmt().length} statements. Input should be a single statement`); | ||
visitFunctionCall(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
return this.generateFunctionCall(ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitFunctionCall(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
visitIdentifier(ctx) { | ||
return this.generateIdentifier(ctx); | ||
} | ||
return this.generateFunctionCall(ctx); | ||
} | ||
visitIdentifier(ctx) { | ||
return this.generateIdentifier(ctx); | ||
} | ||
visitAttributeAccess(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
return this.generateAttributeAccess(ctx); | ||
} | ||
visitAttributeAccess(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
visitObject_literal(ctx) { | ||
this.testForComprehension(ctx.dictorsetmaker()); | ||
return this.generateObjectLiteral(ctx); | ||
} | ||
return this.generateAttributeAccess(ctx); | ||
} | ||
visitObject_literal(ctx) { | ||
this.testForComprehension(ctx.dictorsetmaker()); | ||
return this.generateObjectLiteral(ctx); | ||
} | ||
visitArray_literal(ctx) { | ||
this.testForComprehension(ctx.testlist_comp()); | ||
return this.generateArrayLiteral(ctx); | ||
} | ||
visitArray_literal(ctx) { | ||
this.testForComprehension(ctx.testlist_comp()); | ||
return this.generateArrayLiteral(ctx); | ||
} | ||
visitExpr(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
visitExpr(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map((m) => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map(m => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitXor_expr(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
visitXor_expr(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map((m) => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map(m => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitAnd_expr(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
visitAnd_expr(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map((m) => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
if (this.Syntax.binary.template) { | ||
const kids = ctx.children.map(m => this.visit(m)); | ||
return this.Syntax.binary.template(kids); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitShift_expr(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
visitShift_expr(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
const args = ctx.children.map((n) => this.visit(n)); | ||
if (this.Syntax.binary.template) { | ||
return this.Syntax.binary.template(args); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
const args = ctx.children.map((n) => this.visit(n)); | ||
if (this.Syntax.binary.template) { | ||
return this.Syntax.binary.template(args); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitArith_expr(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
visitArith_expr(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
const args = ctx.children.map((n) => this.visit(n)); | ||
if (this.Syntax.binary.template) { | ||
return this.Syntax.binary.template(args); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
const args = ctx.children.map((n) => this.visit(n)); | ||
if (this.Syntax.binary.template) { | ||
return this.Syntax.binary.template(args); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
/* So far, this only exists in Python so it hasn't been moved to | ||
* CodeGenerationVisitor. However, if another input or output language has a | ||
* set implementation, should move this to the shared visitor. */ | ||
visitSet_literal(ctx) { | ||
ctx.type = this.Types._array; | ||
ctx.indentDepth = this.findIndentDepth(ctx) + 1; | ||
this.requiredImports[9] = true; | ||
let args = []; | ||
const list = ctx.testlist_comp(); | ||
this.testForComprehension(list); | ||
let join; | ||
if (list) { | ||
// Sets of 1 item is the same as the item itself, but keep parens for math | ||
if (list.children.length === 1) { | ||
return this.returnParenthesis(this.visit(list.children[0])); | ||
} | ||
const visitedChildren = list.children.map((child) => { | ||
return this.visit(child); | ||
}); | ||
const visitedElements = visitedChildren.filter((arg) => { | ||
return arg !== ','; | ||
}); | ||
if (ctx.type.argsTemplate) { // NOTE: not currently being used anywhere. | ||
args = visitedElements.map((arg, index) => { | ||
const last = !visitedElements[index + 1]; | ||
return ctx.type.argsTemplate.bind(this.getState())(arg, ctx.indentDepth, last); | ||
/* So far, this only exists in Python so it hasn't been moved to | ||
* CodeGenerationVisitor. However, if another input or output language has a | ||
* set implementation, should move this to the shared visitor. */ | ||
visitSet_literal(ctx) { | ||
ctx.type = this.Types._array; | ||
ctx.indentDepth = this.findIndentDepth(ctx) + 1; | ||
this.requiredImports[9] = true; | ||
let args = []; | ||
const list = ctx.testlist_comp(); | ||
this.testForComprehension(list); | ||
let join; | ||
if (list) { | ||
// Sets of 1 item is the same as the item itself, but keep parens for math | ||
if (list.children.length === 1) { | ||
return this.returnParenthesis(this.visit(list.children[0])); | ||
} | ||
const visitedChildren = list.children.map((child) => { | ||
return this.visit(child); | ||
}); | ||
join = ''; | ||
} else { | ||
args = visitedElements; | ||
join = ', '; | ||
const visitedElements = visitedChildren.filter((arg) => { | ||
return arg !== ','; | ||
}); | ||
if (ctx.type.argsTemplate) { | ||
// NOTE: not currently being used anywhere. | ||
args = visitedElements.map((arg, index) => { | ||
const last = !visitedElements[index + 1]; | ||
return ctx.type.argsTemplate.bind(this.getState())( | ||
arg, | ||
ctx.indentDepth, | ||
last | ||
); | ||
}); | ||
join = ''; | ||
} else { | ||
args = visitedElements; | ||
join = ', '; | ||
} | ||
} | ||
if (ctx.type.template) { | ||
return ctx.type.template(args.join(join), ctx.indentDepth); | ||
} | ||
return this.returnSet(args, ctx); | ||
} | ||
if (ctx.type.template) { | ||
return ctx.type.template(args.join(join), ctx.indentDepth); | ||
} | ||
return this.returnSet(args, ctx); | ||
} | ||
visitStringAtom(ctx) { | ||
ctx.type = this.Types._string; | ||
this.requiredImports[ctx.type.code] = true; | ||
// Pass the original argument type to the template, not the casted type. | ||
const type = ctx.originalType === undefined ? ctx.type : ctx.originalType; | ||
visitStringAtom(ctx) { | ||
ctx.type = this.Types._string; | ||
this.requiredImports[ctx.type.code] = true; | ||
// Pass the original argument type to the template, not the casted type. | ||
const type = ctx.originalType === undefined ? ctx.type : ctx.originalType; | ||
let result = this.visitChildren(ctx); | ||
result = result.replace(/^([rubf]?[rubf]["']|'''|"""|'|")/gi, ''); | ||
result = result.replace(/(["]{3}|["]|[']{3}|['])$/, ''); | ||
return this.generateLiteral( | ||
ctx, ctx.type, [result, type.id], `'${result}'`, true | ||
); | ||
} | ||
visitInteger_literal(ctx) { | ||
return this.leafHelper(this.Types._long, ctx); | ||
} | ||
visitOct_literal(ctx) { | ||
return this.leafHelper(this.Types._octal, ctx); | ||
} | ||
visitHex_literal(ctx) { | ||
return this.leafHelper(this.Types._hex, ctx); | ||
} | ||
visitBin_literal(ctx) { | ||
return this.leafHelper(this.Types._bin, ctx); | ||
} | ||
visitFloat_literal(ctx) { | ||
return this.leafHelper(this.Types._decimal, ctx); | ||
} | ||
visitBoolean_literal(ctx) { | ||
return this.leafHelper(this.Types._bool, ctx); | ||
} | ||
visitNone_literal(ctx) { | ||
return this.leafHelper(this.Types._null, ctx); | ||
} | ||
visitExpr_stmt(ctx) { | ||
if ( | ||
('assign_stmt' in ctx && ctx.assign_stmt() !== null) || | ||
('augassign' in ctx && ctx.augassign() !== null) || | ||
('annassign' in ctx && ctx.annassign() !== null) | ||
) { | ||
throw new BsonTranspilersUnimplementedError( | ||
'Assignment not yet implemented' | ||
let result = this.visitChildren(ctx); | ||
result = result.replace(/^([rubf]?[rubf]["']|'''|"""|'|")/gi, ''); | ||
result = result.replace(/(["]{3}|["]|[']{3}|['])$/, ''); | ||
return this.generateLiteral( | ||
ctx, | ||
ctx.type, | ||
[result, type.id], | ||
`'${result}'`, | ||
true | ||
); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitFactor(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
visitInteger_literal(ctx) { | ||
return this.leafHelper(this.Types._long, ctx); | ||
} | ||
// For the expression "+1", set the type to the child's type. | ||
const op = this.visit(ctx.children[0]); | ||
const factor = this.visit(ctx.factor()); | ||
ctx.type = this.findTypedNode(ctx.factor()).type; | ||
if (this.Syntax.unary.template) { | ||
return this.Syntax.unary.template( | ||
op, | ||
factor | ||
); | ||
visitOct_literal(ctx) { | ||
return this.leafHelper(this.Types._octal, ctx); | ||
} | ||
return `${op}${factor}`; | ||
} | ||
visitTerm(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
visitHex_literal(ctx) { | ||
return this.leafHelper(this.Types._hex, ctx); | ||
} | ||
const args = ctx.children.map((n) => this.visit(n)); | ||
if (this.Syntax.binary.template) { | ||
return this.Syntax.binary.template(args); | ||
visitBin_literal(ctx) { | ||
return this.leafHelper(this.Types._bin, ctx); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
visitPower(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
visitFloat_literal(ctx) { | ||
return this.leafHelper(this.Types._decimal, ctx); | ||
} | ||
const lhs = this.visit(ctx.atom()); | ||
const rhs = this.visit(ctx.factor()); | ||
if (this.Syntax.binary.template) { | ||
return this.Syntax.binary.template([lhs, '**', rhs]); | ||
visitBoolean_literal(ctx) { | ||
return this.leafHelper(this.Types._bool, ctx); | ||
} | ||
return `${lhs} ** ${rhs}`; | ||
} | ||
visitAnd_test(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
visitNone_literal(ctx) { | ||
return this.leafHelper(this.Types._null, ctx); | ||
} | ||
const children = ctx.not_test().map((t) => ( this.visit(t) )); | ||
if (this.Syntax.and) { | ||
return this.Syntax.and.template(children); | ||
} | ||
return children.join(' and '); | ||
} | ||
visitOr_test(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
visitExpr_stmt(ctx) { | ||
if ( | ||
('assign_stmt' in ctx && ctx.assign_stmt() !== null) || | ||
('augassign' in ctx && ctx.augassign() !== null) || | ||
('annassign' in ctx && ctx.annassign() !== null) | ||
) { | ||
throw new BsonTranspilersUnimplementedError( | ||
'Assignment not yet implemented' | ||
); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
const children = ctx.and_test().map((t) => (this.visit(t))); | ||
if (this.Syntax.or) { | ||
return this.Syntax.or.template(children); | ||
visitFactor(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
// For the expression "+1", set the type to the child's type. | ||
const op = this.visit(ctx.children[0]); | ||
const factor = this.visit(ctx.factor()); | ||
ctx.type = this.findTypedNode(ctx.factor()).type; | ||
if (this.Syntax.unary.template) { | ||
return this.Syntax.unary.template(op, factor); | ||
} | ||
return `${op}${factor}`; | ||
} | ||
return children.join(' or '); | ||
} | ||
visitNot_test(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
visitTerm(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
const args = ctx.children.map((n) => this.visit(n)); | ||
if (this.Syntax.binary.template) { | ||
return this.Syntax.binary.template(args); | ||
} | ||
return this.visitChildren(ctx); | ||
} | ||
const child = this.visit(ctx.children[1]); | ||
if (this.Syntax.not) { | ||
return this.Syntax.not.template(child); | ||
visitPower(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
const lhs = this.visit(ctx.atom()); | ||
const rhs = this.visit(ctx.factor()); | ||
if (this.Syntax.binary.template) { | ||
return this.Syntax.binary.template([lhs, '**', rhs]); | ||
} | ||
return `${lhs} ** ${rhs}`; | ||
} | ||
} | ||
returnComparison(ctx) { | ||
let skip = false; | ||
return ctx.children.reduce((str, e, i, arr) => { | ||
if (skip) { // Skip for 'in' statements because swallows rhs | ||
skip = false; | ||
return str; | ||
visitAnd_test(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
if (i === arr.length - 1) { // Always visit the last element | ||
return `${str}${this.visit(e)}`; | ||
const children = ctx.not_test().map((t) => this.visit(t)); | ||
if (this.Syntax.and) { | ||
return this.Syntax.and.template(children); | ||
} | ||
if (i % 2 === 0) { // Only ops | ||
return str; | ||
return children.join(' and '); | ||
} | ||
visitOr_test(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
const op = this.visit(e); | ||
if (op === '==' || op === '!=' || op === 'is' || op === 'isnot') { | ||
skip = true; | ||
if (this.Syntax.equality) { | ||
return `${str}${this.Syntax.equality.template( | ||
this.visit(arr[i - 1]), op, this.visit(arr[i + 1]))}`; | ||
} | ||
return `${str} === ${this.visit(arr[i - 1])} ${op} ${this.visit(arr[i + 1])}`; | ||
const children = ctx.and_test().map((t) => this.visit(t)); | ||
if (this.Syntax.or) { | ||
return this.Syntax.or.template(children); | ||
} | ||
if (op === 'in' || op === 'notin') { | ||
skip = true; | ||
if (this.Syntax.in) { | ||
return `${str}${this.Syntax.in.template.bind(this.state)( | ||
this.visit(arr[i - 1]), op, this.visit(arr[i + 1]))}`; | ||
} | ||
return `${str} ${this.visit(arr[i - 1])} ${op} ${this.visit(arr[i + 1])}`; | ||
return children.join(' or '); | ||
} | ||
visitNot_test(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
return `${str}${this.visit(arr[i - 1])} ${op} `; | ||
}, ''); | ||
} | ||
const child = this.visit(ctx.children[1]); | ||
if (this.Syntax.not) { | ||
return this.Syntax.not.template(child); | ||
} | ||
} | ||
visitComparison(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
returnComparison(ctx) { | ||
let skip = false; | ||
return ctx.children.reduce((str, e, i, arr) => { | ||
if (skip) { | ||
// Skip for 'in' statements because swallows rhs | ||
skip = false; | ||
return str; | ||
} | ||
if (i === arr.length - 1) { | ||
// Always visit the last element | ||
return `${str}${this.visit(e)}`; | ||
} | ||
if (i % 2 === 0) { | ||
// Only ops | ||
return str; | ||
} | ||
const op = this.visit(e); | ||
if (op === '==' || op === '!=' || op === 'is' || op === 'isnot') { | ||
skip = true; | ||
if (this.Syntax.equality) { | ||
return `${str}${this.Syntax.equality.template( | ||
this.visit(arr[i - 1]), | ||
op, | ||
this.visit(arr[i + 1]) | ||
)}`; | ||
} | ||
return `${str} === ${this.visit(arr[i - 1])} ${op} ${this.visit( | ||
arr[i + 1] | ||
)}`; | ||
} | ||
if (op === 'in' || op === 'notin') { | ||
skip = true; | ||
if (this.Syntax.in) { | ||
return `${str}${this.Syntax.in.template.bind(this.state)( | ||
this.visit(arr[i - 1]), | ||
op, | ||
this.visit(arr[i + 1]) | ||
)}`; | ||
} | ||
return `${str} ${this.visit(arr[i - 1])} ${op} ${this.visit( | ||
arr[i + 1] | ||
)}`; | ||
} | ||
return `${str}${this.visit(arr[i - 1])} ${op} `; | ||
}, ''); | ||
} | ||
return this.returnComparison(ctx); | ||
} | ||
visitIndexAccess(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
visitComparison(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
return this.returnComparison(ctx); | ||
} | ||
throw new BsonTranspilersUnimplementedError('Indexing not currently supported'); | ||
} | ||
/* | ||
* | ||
* Process Methods | ||
* | ||
*/ | ||
visitIndexAccess(ctx) { | ||
if (ctx.getChildCount() === 1) { | ||
return this.visitChildren(ctx); | ||
} | ||
throw new BsonTranspilersUnimplementedError( | ||
'Indexing not currently supported' | ||
); | ||
} | ||
processint(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
/* | ||
* | ||
* Process Methods | ||
* | ||
*/ | ||
processfloat(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
processint(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
processInt64(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
processfloat(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
processfrom_native(ctx) { | ||
ctx.type = this.Types.BSONRegExp; | ||
const symbolType = this.Symbols.Regex; | ||
const argList = this.getArguments(ctx); | ||
if (argList.length !== 1) { | ||
throw new BsonTranspilersArgumentError('RegExp.from_native requires one argument'); | ||
processInt64(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
const pythonFlags = { | ||
256: '', 2: 'i', 128: '', 4: 'l', 8: 'm', 16: 's', 64: 'x' | ||
}; | ||
const native = this.skipFakeNodesDown(this.getArgumentAt(ctx, 0)); | ||
const args = this.findPatternAndFlags(native, pythonFlags, this.Syntax.bsonRegexFlags); | ||
return this.generateCall( | ||
ctx, symbolType, args, 'Regex', | ||
`(${args[0]}${args[1] ? ', ' + args[1] : ''})` | ||
); | ||
} | ||
processfrom_native(ctx) { | ||
ctx.type = this.Types.BSONRegExp; | ||
const symbolType = this.Symbols.Regex; | ||
processcompile(ctx) { | ||
ctx.type = this.Types._regex; | ||
const pythonFlags = { | ||
256: '', 2: 'i', 128: '', 4: '', 8: 'm', 16: '', 64: '' | ||
}; | ||
const args = this.findPatternAndFlags(ctx, pythonFlags, this.Syntax.regexFlags); | ||
return this.generateLiteral(ctx, ctx.type, args, 'RegExp'); | ||
} | ||
const argList = this.getArguments(ctx); | ||
if (argList.length !== 1) { | ||
throw new BsonTranspilersArgumentError( | ||
'RegExp.from_native requires one argument' | ||
); | ||
} | ||
const pythonFlags = { | ||
256: '', | ||
2: 'i', | ||
128: '', | ||
4: 'l', | ||
8: 'm', | ||
16: 's', | ||
64: 'x', | ||
}; | ||
const native = this.skipFakeNodesDown(this.getArgumentAt(ctx, 0)); | ||
const args = this.findPatternAndFlags( | ||
native, | ||
pythonFlags, | ||
this.Syntax.bsonRegexFlags | ||
); | ||
processRegex(ctx) { | ||
return this.generateBSONRegex(ctx, this.Types.Regex, this.Symbols.Regex); | ||
} | ||
return this.generateCall( | ||
ctx, | ||
symbolType, | ||
args, | ||
'Regex', | ||
`(${args[0]}${args[1] ? ', ' + args[1] : ''})` | ||
); | ||
} | ||
processCode(ctx) { | ||
return this.generateBSONCode(ctx, this.Types.Code, this.Symbols.Code, true); | ||
} | ||
processcompile(ctx) { | ||
ctx.type = this.Types._regex; | ||
const pythonFlags = { | ||
256: '', | ||
2: 'i', | ||
128: '', | ||
4: '', | ||
8: 'm', | ||
16: '', | ||
64: '', | ||
}; | ||
const args = this.findPatternAndFlags( | ||
ctx, | ||
pythonFlags, | ||
this.Syntax.regexFlags | ||
); | ||
return this.generateLiteral(ctx, ctx.type, args, 'RegExp'); | ||
} | ||
processdatetime(ctx) { | ||
ctx.type = this.Types.Date; | ||
ctx.wasNew = true; // Always true for non-js | ||
const symbolType = this.Symbols.datetime; | ||
let date = null; | ||
processRegex(ctx) { | ||
return this.generateBSONRegex(ctx, this.Types.Regex, this.Symbols.Regex); | ||
} | ||
const argsList = this.getArguments(ctx); | ||
if (argsList.length !== 0) { | ||
if (argsList.length < 3) { | ||
throw new BsonTranspilersArgumentError( | ||
`Wrong number of arguments to datetime: needs at at least 3, got ${ | ||
argsList.length}` | ||
); | ||
} | ||
processCode(ctx) { | ||
return this.generateBSONCode( | ||
ctx, | ||
this.Types.Code, | ||
this.Symbols.Code, | ||
true | ||
); | ||
} | ||
try { | ||
this.checkArguments(symbolType.args, argsList, 'datetime'); | ||
} catch (e) { | ||
throw new BsonTranspilersArgumentError( | ||
`Invalid argument to datetime: requires no args or up to 7 numbers. ${ | ||
e.message}` | ||
); | ||
} | ||
processdatetime(ctx) { | ||
ctx.type = this.Types.Date; | ||
ctx.wasNew = true; // Always true for non-js | ||
const symbolType = this.Symbols.datetime; | ||
let date = null; | ||
const argvals = argsList.map((k) => { | ||
let v; | ||
const argsList = this.getArguments(ctx); | ||
if (argsList.length !== 0) { | ||
if (argsList.length < 3) { | ||
throw new BsonTranspilersArgumentError( | ||
`Wrong number of arguments to datetime: needs at at least 3, got ${argsList.length}` | ||
); | ||
} | ||
try { | ||
v = parseInt(k.getText(), 10); | ||
this.checkArguments(symbolType.args, argsList, 'datetime'); | ||
} catch (e) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Unable to convert datetime argument to integer: ${k.getText()}` | ||
throw new BsonTranspilersArgumentError( | ||
`Invalid argument to datetime: requires no args or up to 7 numbers. ${e.message}` | ||
); | ||
} | ||
if (isNaN(v)) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Unable to convert datetime argument to integer: ${k.getText()}` | ||
const argvals = argsList.map((k) => { | ||
let v; | ||
try { | ||
v = parseInt(k.getText(), 10); | ||
} catch (e) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Unable to convert datetime argument to integer: ${k.getText()}` | ||
); | ||
} | ||
if (isNaN(v)) { | ||
throw new BsonTranspilersRuntimeError( | ||
`Unable to convert datetime argument to integer: ${k.getText()}` | ||
); | ||
} | ||
return v; | ||
}); | ||
/* month is 0-based in JS, 1-based in everything else (afaict) */ | ||
argvals[1]--; | ||
/* date is 1900-based in JS, 0-based in python */ | ||
argvals[0] -= 1900; | ||
try { | ||
date = new Date(Date.UTC(...argvals)); | ||
} catch (e) { | ||
throw new BsonTranspilersInternalError( | ||
`Unable to construct date from arguments: ${e.message}` | ||
); | ||
} | ||
return v; | ||
}); | ||
/* month is 0-based in JS, 1-based in everything else (afaict) */ | ||
argvals[1]--; | ||
/* date is 1900-based in JS, 0-based in python */ | ||
argvals[0] -= 1900; | ||
try { | ||
date = new Date(Date.UTC(...argvals)); | ||
} catch (e) { | ||
throw new BsonTranspilersInternalError( | ||
`Unable to construct date from arguments: ${e.message}` | ||
); | ||
} | ||
const dargs = `Date(${ | ||
date ? this.Types._string.template(date.toUTCString()) : '' | ||
})`; | ||
return this.generateCall( | ||
ctx, | ||
symbolType, | ||
[date, false], | ||
'', | ||
dargs, | ||
false, | ||
true | ||
); | ||
} | ||
const dargs = `Date(${date | ||
? this.Types._string.template(date.toUTCString()) | ||
: ''})`; | ||
return this.generateCall( | ||
ctx, symbolType, [date, false], '', dargs, false, true | ||
); | ||
} | ||
processObjectIdfrom_datetime(ctx) { | ||
return this.generateObjectIdFromTime(ctx); | ||
} | ||
processObjectIdfrom_datetime(ctx) { | ||
return this.generateObjectIdFromTime(ctx); | ||
} | ||
processBinary() { | ||
throw new BsonTranspilersUnimplementedError('Binary type not supported'); | ||
} | ||
processBinary() { | ||
throw new BsonTranspilersUnimplementedError('Binary type not supported'); | ||
} | ||
/* | ||
* | ||
* Helper Methods | ||
* | ||
*/ | ||
/* | ||
* | ||
* Helper Methods | ||
* | ||
*/ | ||
findPatternAndFlags(ctx, pythonFlags, targetFlags) { | ||
let pattern; | ||
findPatternAndFlags(ctx, pythonFlags, targetFlags) { | ||
let pattern; | ||
const symbolType = this.Symbols.re.attr.compile; | ||
const argList = this.getArguments(ctx); | ||
const args = this.checkArguments(symbolType.args, argList, symbolType.id, symbolType.namedArgs); | ||
const symbolType = this.Symbols.re.attr.compile; | ||
const argList = this.getArguments(ctx); | ||
const args = this.checkArguments( | ||
symbolType.args, | ||
argList, | ||
symbolType.id, | ||
symbolType.namedArgs | ||
); | ||
// Compile regex without flags | ||
const raw = this.getArgumentAt(ctx, 0).getText(); | ||
let str = raw.replace(/^([rubf]?[rubf]["']|'''|"""|'|")/gi, ''); | ||
str = str.replace(/(["]{3}|["]|[']{3}|['])$/, ''); | ||
const input = `new RegExp(${raw.substr(-1)}${str}${raw.substr(-1)})`; | ||
try { | ||
const sandbox = { | ||
RegExp: RegExp | ||
}; | ||
const regexobj = vm.runInContext('__result = ' + input, vm.createContext(sandbox)); | ||
pattern = regexobj.source; | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
} | ||
// Compile regex without flags | ||
const raw = this.getArgumentAt(ctx, 0).getText(); | ||
let str = raw.replace(/^([rubf]?[rubf]["']|'''|"""|'|")/gi, ''); | ||
str = str.replace(/(["]{3}|["]|[']{3}|['])$/, ''); | ||
const input = `new RegExp(${raw.substr(-1)}${str}${raw.substr(-1)})`; | ||
try { | ||
const sandbox = { | ||
RegExp: RegExp, | ||
}; | ||
const regexobj = vm.runInContext( | ||
'__result = ' + input, | ||
vm.createContext(sandbox) | ||
); | ||
pattern = regexobj.source; | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
} | ||
// Convert flags | ||
if (args.length === 1) { | ||
return [pattern, targetFlags.u]; | ||
} | ||
// Convert flags | ||
if (args.length === 1) { | ||
return [pattern, targetFlags.u]; | ||
} | ||
let flagsArg = argList[1]; | ||
flagsArg = this.skipFakeNodesDown(this.checkNamedArgs( | ||
[this.Types._integer], flagsArg, symbolType.namedArgs | ||
)[1]); | ||
let visited; | ||
if ('expr' in flagsArg.parentCtx) { // combine bitwise flags | ||
visited = flagsArg.xor_expr().map(f => this.visit(f)); | ||
} else { | ||
visited = [this.visit(flagsArg)]; | ||
} | ||
let flagsArg = argList[1]; | ||
flagsArg = this.skipFakeNodesDown( | ||
this.checkNamedArgs( | ||
[this.Types._integer], | ||
flagsArg, | ||
symbolType.namedArgs | ||
)[1] | ||
); | ||
let visited; | ||
if ('expr' in flagsArg.parentCtx) { | ||
// combine bitwise flags | ||
visited = flagsArg.xor_expr().map((f) => this.visit(f)); | ||
} else { | ||
visited = [this.visit(flagsArg)]; | ||
} | ||
const translated = visited | ||
.map(f => pythonFlags[f]) | ||
.filter(f => f !== undefined); | ||
const translated = visited | ||
.map((f) => pythonFlags[f]) | ||
.filter((f) => f !== undefined); | ||
if (visited.indexOf('256') === -1) { // default is unicode without re.A | ||
translated.push('u'); | ||
} | ||
if (visited.indexOf('256') === -1) { | ||
// default is unicode without re.A | ||
translated.push('u'); | ||
} | ||
const target = translated | ||
.map(m => targetFlags[m]) | ||
.filter(f => f !== undefined); | ||
const target = translated | ||
.map((m) => targetFlags[m]) | ||
.filter((f) => f !== undefined); | ||
const flags = target.sort().join(''); | ||
return [pattern, flags]; | ||
} | ||
const flags = target.sort().join(''); | ||
return [pattern, flags]; | ||
} | ||
/** | ||
* Want to throw unimplemented for comprehensions instead of reference errors. | ||
* @param {ParserRuleContext} ctx | ||
*/ | ||
testForComprehension(ctx) { | ||
if (ctx === null || ctx === undefined) { | ||
return; | ||
} | ||
if ( | ||
('comp_for' in ctx && ctx.comp_for() !== null) || | ||
/** | ||
* Want to throw unimplemented for comprehensions instead of reference errors. | ||
* @param {ParserRuleContext} ctx | ||
*/ | ||
testForComprehension(ctx) { | ||
if (ctx === null || ctx === undefined) { | ||
return; | ||
} | ||
if ( | ||
('comp_for' in ctx && ctx.comp_for() !== null) || | ||
('comp_if' in ctx && ctx.comp_if() !== null) | ||
) { | ||
throw new BsonTranspilersUnimplementedError( | ||
'Comprehensions not yet implemented' | ||
); | ||
) { | ||
throw new BsonTranspilersUnimplementedError( | ||
'Comprehensions not yet implemented' | ||
); | ||
} | ||
} | ||
} | ||
getParentUntil(ctx, name, steps) { | ||
steps = steps === undefined ? 0 : steps; | ||
let res = ctx; | ||
let found = false; | ||
const stack = []; | ||
while (res !== undefined && res !== null && !found) { | ||
if (name in res) { | ||
const goal = res[name](); | ||
if (goal === stack[stack.length - 1]) { | ||
found = true; | ||
getParentUntil(ctx, name, steps) { | ||
steps = steps === undefined ? 0 : steps; | ||
let res = ctx; | ||
let found = false; | ||
const stack = []; | ||
while (res !== undefined && res !== null && !found) { | ||
if (name in res) { | ||
const goal = res[name](); | ||
if (goal === stack[stack.length - 1]) { | ||
found = true; | ||
break; | ||
} | ||
} | ||
stack.push(res); | ||
res = res.parentCtx; | ||
} | ||
return found ? stack[stack.length - 1 - steps] : false; | ||
} | ||
skipFakeNodesDown(ctx, goal) { | ||
let res = ctx; | ||
while (res.children !== undefined && res.children.length === 1) { | ||
res = res.children[0]; | ||
if (goal && goal in res) { | ||
res = res[goal](); | ||
break; | ||
} | ||
} | ||
stack.push(res); | ||
res = res.parentCtx; | ||
if (res.children === undefined) { | ||
return res.parentCtx; | ||
} | ||
return res; | ||
} | ||
return found ? stack[stack.length - 1 - steps] : false; | ||
} | ||
skipFakeNodesDown(ctx, goal) { | ||
let res = ctx; | ||
while (res.children !== undefined && res.children.length === 1) { | ||
res = res.children[0]; | ||
if (goal && goal in res) { | ||
res = res[goal](); | ||
break; | ||
skipFakeNodesUp(ctx, goal) { | ||
let res = ctx.parentCtx; | ||
while ( | ||
res !== undefined && | ||
res !== null && | ||
res.children !== undefined && | ||
res.children.length === 1 | ||
) { | ||
if (goal && goal in res) { | ||
res = res[goal](); | ||
break; | ||
} | ||
res = res.parentCtx; | ||
} | ||
return res; | ||
} | ||
if (res.children === undefined) { | ||
return res.parentCtx; | ||
/** | ||
* Takes in the constructor name of a node and returns a human-readable | ||
* node name. Used for error reporting, must be defined by all visitors. | ||
* | ||
* @param {String} name | ||
* @return {String} | ||
*/ | ||
renameNode(name) { | ||
return name ? name.replace('_stmt', '') : 'Expression'; | ||
} | ||
return res; | ||
} | ||
skipFakeNodesUp(ctx, goal) { | ||
let res = ctx.parentCtx; | ||
while (res !== undefined && res !== null && res.children !== undefined && | ||
res.children.length === 1) { | ||
if (goal && goal in res) { | ||
res = res[goal](); | ||
break; | ||
/** | ||
* If a named argument is passed in, then check against the 'namedArgs' array | ||
* instead of positionally. | ||
* | ||
* @param {Array} expected | ||
* @param {ParserRuleContext} node | ||
* @param {Object} namedArgs | ||
* @return {Array} | ||
*/ | ||
checkNamedArgs(expected, node, namedArgs) { | ||
const child = this.skipFakeNodesDown(node); | ||
if (namedArgs && 'test' in child && child.test().length > 1) { | ||
const name = child.test()[0].getText(); | ||
const value = child.test()[1]; | ||
const expectedType = namedArgs[name]; | ||
if (expectedType === undefined) { | ||
throw new BsonTranspilersArgumentError( | ||
`Unknown named argument '${name}'` | ||
); | ||
} | ||
return [expectedType.type, value]; | ||
} | ||
res = res.parentCtx; | ||
return [expected, node]; | ||
} | ||
return res; | ||
} | ||
/** | ||
* Takes in the constructor name of a node and returns a human-readable | ||
* node name. Used for error reporting, must be defined by all visitors. | ||
* | ||
* @param {String} name | ||
* @return {String} | ||
*/ | ||
renameNode(name) { | ||
return name ? name.replace('_stmt', '') : 'Expression'; | ||
} | ||
/* | ||
* | ||
* Accessor Functions. | ||
* | ||
* These MUST be defined by every visitor. Each function is a wrapper around | ||
* a tree node. They are required so that the CodeGenerationVisitor and the | ||
* Generators can access tree elements without needing to know which tree they | ||
* are visiting or the ANTLR name of the node. | ||
* | ||
*/ | ||
/** | ||
* If a named argument is passed in, then check against the 'namedArgs' array | ||
* instead of positionally. | ||
* | ||
* @param {Array} expected | ||
* @param {ParserRuleContext} node | ||
* @param {Object} namedArgs | ||
* @return {Array} | ||
*/ | ||
checkNamedArgs(expected, node, namedArgs) { | ||
const child = this.skipFakeNodesDown(node); | ||
if (namedArgs && 'test' in child && child.test().length > 1) { | ||
const name = child.test()[0].getText(); | ||
const value = child.test()[1]; | ||
const expectedType = namedArgs[name]; | ||
if (expectedType === undefined) { | ||
throw new BsonTranspilersArgumentError( | ||
`Unknown named argument '${name}'` | ||
); | ||
getArguments(ctx) { | ||
const trailer = ctx.paren_trailer(); | ||
if (!('arglist' in trailer) || trailer.arglist() === null) { | ||
return []; | ||
} | ||
return [expectedType.type, value]; | ||
return trailer.arglist().argument(); | ||
} | ||
return [expected, node]; | ||
} | ||
/* | ||
* | ||
* Accessor Functions. | ||
* | ||
* These MUST be defined by every visitor. Each function is a wrapper around | ||
* a tree node. They are required so that the CodeGenerationVisitor and the | ||
* Generators can access tree elements without needing to know which tree they | ||
* are visiting or the ANTLR name of the node. | ||
* | ||
*/ | ||
getArgumentAt(ctx, i) { | ||
return this.getArguments(ctx)[i]; | ||
} | ||
getArguments(ctx) { | ||
const trailer = ctx.paren_trailer(); | ||
if (!('arglist' in trailer) || trailer.arglist() === null) { | ||
return []; | ||
getFunctionCallName(ctx) { | ||
return ctx.atom(); | ||
} | ||
return trailer.arglist().argument(); | ||
} | ||
getArgumentAt(ctx, i) { | ||
return this.getArguments(ctx)[i]; | ||
} | ||
getIfIdentifier(ctx) { | ||
if ('identifier' in ctx) { | ||
return ctx.identifier(); | ||
} | ||
return ctx; | ||
} | ||
getFunctionCallName(ctx) { | ||
return ctx.atom(); | ||
} | ||
getAttributeLHS(ctx) { | ||
return ctx.atom(); | ||
} | ||
getIfIdentifier(ctx) { | ||
if ('identifier' in ctx) { | ||
return ctx.identifier(); | ||
getAttributeRHS(ctx) { | ||
return ctx.dot_trailer().identifier(); | ||
} | ||
return ctx; | ||
} | ||
getAttributeLHS(ctx) { | ||
return ctx.atom(); | ||
} | ||
getList(ctx) { | ||
if (!('testlist_comp' in ctx) || !ctx.testlist_comp()) { | ||
return []; | ||
} | ||
return ctx.testlist_comp().test(); | ||
} | ||
getAttributeRHS(ctx) { | ||
return ctx.dot_trailer().identifier(); | ||
} | ||
getArray(ctx) { | ||
return this.skipFakeNodesDown(ctx, 'array_literal'); | ||
} | ||
getList(ctx) { | ||
if (!('testlist_comp' in ctx) || !ctx.testlist_comp()) { | ||
getObject(ctx) { | ||
return this.skipFakeNodesDown(ctx, 'object_literal'); | ||
} | ||
getKeyValueList(ctx) { | ||
if ('dictorsetmaker' in ctx && ctx.dictorsetmaker()) { | ||
const properties = ctx.dictorsetmaker().test(); | ||
return properties | ||
.map((key, i) => { | ||
if (i % 2 === 0) { | ||
return [key, properties[i + 1]]; | ||
} | ||
return null; | ||
}) | ||
.filter((k) => k !== null); | ||
} | ||
return []; | ||
} | ||
return ctx.testlist_comp().test(); | ||
} | ||
getArray(ctx) { | ||
return this.skipFakeNodesDown(ctx, 'array_literal'); | ||
} | ||
getKeyStr(k) { | ||
return removeQuotes(this.visit(k[0])); | ||
} | ||
getObject(ctx) { | ||
return this.skipFakeNodesDown(ctx, 'object_literal'); | ||
} | ||
getValue(k) { | ||
return k[1]; | ||
} | ||
getKeyValueList(ctx) { | ||
if ('dictorsetmaker' in ctx && ctx.dictorsetmaker()) { | ||
const properties = ctx.dictorsetmaker().test(); | ||
return properties | ||
.map((key, i) => { | ||
if (i % 2 === 0) { | ||
return [ | ||
key, | ||
properties[i + 1] | ||
]; | ||
} | ||
return null; | ||
}) | ||
.filter((k) => (k !== null)); | ||
isSubObject(ctx) { | ||
return this.getParentUntil(ctx.parentCtx, 'dictorsetmaker', 1); | ||
} | ||
return []; | ||
} | ||
getKeyStr(k) { | ||
return removeQuotes(this.visit(k[0])); | ||
} | ||
getParentKeyStr(ctx) { | ||
// TODO: fix for long list | ||
// For a given sub document, get its key. | ||
const topNode = this.getParentUntil(ctx.parentCtx, 'dictorsetmaker', 1); | ||
const objNode = topNode.parentCtx; | ||
const index = objNode.test().indexOf(topNode); | ||
const keyNode = objNode.test()[index - 1]; | ||
const key = this.visit(keyNode); | ||
return removeQuotes(key); | ||
} | ||
getValue(k) { | ||
return k[1]; | ||
} | ||
isSubObject(ctx) { | ||
return this.getParentUntil(ctx.parentCtx, 'dictorsetmaker', 1); | ||
} | ||
getParentKeyStr(ctx) { // TODO: fix for long list | ||
// For a given sub document, get its key. | ||
const topNode = this.getParentUntil(ctx.parentCtx, 'dictorsetmaker', 1); | ||
const objNode = topNode.parentCtx; | ||
const index = objNode.test().indexOf(topNode); | ||
const keyNode = objNode.test()[index - 1]; | ||
const key = this.visit(keyNode); | ||
return removeQuotes(key); | ||
} | ||
getObjectChild(ctx) { | ||
return this.skipFakeNodesDown(ctx); | ||
} | ||
}; | ||
getObjectChild(ctx) { | ||
return this.skipFakeNodesDown(ctx); | ||
} | ||
}; |
@@ -0,8 +1,10 @@ | ||
'use strict'; | ||
/* | ||
* Class for handling edge cases for ruby code generation. Defines "emit" methods. | ||
*/ | ||
module.exports = (Visitor) => class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; | ||
module.exports = (Visitor) => | ||
class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; |
@@ -0,8 +1,10 @@ | ||
'use strict'; | ||
/* | ||
* Class for handling edge cases for rust code generation. Defines "emit" methods. | ||
*/ | ||
module.exports = (Visitor) => class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; | ||
module.exports = (Visitor) => | ||
class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; |
@@ -0,8 +1,10 @@ | ||
'use strict'; | ||
/* | ||
* Class for handling edge cases for shell code generation. Defines "emit" methods. | ||
*/ | ||
module.exports = (Visitor) => class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; | ||
module.exports = (Visitor) => | ||
class Generator extends Visitor { | ||
constructor() { | ||
super(); | ||
} | ||
}; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/* eslint complexity: 0 */ | ||
@@ -6,3 +7,3 @@ const vm = require('vm'); | ||
BsonTranspilersRuntimeError, | ||
BsonTranspilersUnimplementedError | ||
BsonTranspilersUnimplementedError, | ||
} = require('../../helper/error'); | ||
@@ -18,131 +19,138 @@ | ||
*/ | ||
module.exports = (JavascriptVisitor) => class Visitor extends JavascriptVisitor { | ||
constructor() { | ||
super(); | ||
} | ||
module.exports = (JavascriptVisitor) => | ||
class Visitor extends JavascriptVisitor { | ||
constructor() { | ||
super(); | ||
} | ||
processNumberLong(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
executeJavascript(input) { | ||
const sandbox = { | ||
RegExp: RegExp, | ||
DBRef: bson.DBRef, | ||
Map: bson.Map, | ||
MaxKey: bson.MaxKey, | ||
MinKey: bson.MinKey, | ||
ObjectId: bson.ObjectID, | ||
BSONSymbol: bson.BSONSymbol, | ||
Timestamp: bson.Timestamp, | ||
Code: function(c, s) { | ||
return new bson.Code(c, s); | ||
}, | ||
NumberDecimal: function(s) { | ||
if (s === undefined) { | ||
s = '0'; | ||
} | ||
return bson.Decimal128.fromString(s.toString()); | ||
}, | ||
NumberInt: function(s) { | ||
return parseInt(s, 10); | ||
}, | ||
NumberLong: function(v) { | ||
if (v === undefined) { | ||
v = 0; | ||
} | ||
return bson.Long.fromNumber(v); | ||
}, | ||
ISODate: function(s) { | ||
return new Date(s); | ||
}, | ||
Date: function(s) { | ||
const args = Array.from(arguments); | ||
if (args.length === 1) { | ||
processNumberLong(ctx) { | ||
return this.generateNumericClass(ctx); | ||
} | ||
executeJavascript(input) { | ||
const sandbox = { | ||
RegExp: RegExp, | ||
DBRef: bson.DBRef, | ||
Map: bson.Map, | ||
MaxKey: bson.MaxKey, | ||
MinKey: bson.MinKey, | ||
ObjectId: bson.ObjectId, | ||
BSONSymbol: bson.BSONSymbol, | ||
Timestamp: bson.Timestamp, | ||
Decimal128: bson.Decimal128, | ||
Long: bson.Long, | ||
Int32: bson.Int32, | ||
Double: bson.Double, | ||
Code: function (c, s) { | ||
return new bson.Code(c, s); | ||
}, | ||
NumberDecimal: function (s) { | ||
if (s === undefined) { | ||
s = '0'; | ||
} | ||
return bson.Decimal128.fromString(s.toString()); | ||
}, | ||
NumberInt: function (s) { | ||
return parseInt(s, 10); | ||
}, | ||
NumberLong: function (v) { | ||
if (v === undefined) { | ||
v = 0; | ||
} | ||
return bson.Long.fromNumber(v); | ||
}, | ||
ISODate: function (s) { | ||
return new Date(s); | ||
} | ||
}, | ||
Date: function (s) { | ||
const args = Array.from(arguments); | ||
return new Date(Date.UTC(...args)); | ||
}, | ||
Buffer: Buffer, | ||
__result: {} | ||
}; | ||
const res = vm.runInContext('__result = ' + input, vm.createContext(sandbox)); | ||
return res; | ||
} | ||
if (args.length === 1) { | ||
return new Date(s); | ||
} | ||
/** | ||
* BinData needs extra processing because we need to check that the arg is | ||
* valid base64. | ||
* | ||
* TODO: figure out if it ever makes sense to support Binary. | ||
*/ | ||
processBinData() { | ||
throw new BsonTranspilersUnimplementedError('BinData type not supported'); | ||
} | ||
return new Date(Date.UTC(...args)); | ||
}, | ||
Buffer: Buffer, | ||
__result: {}, | ||
}; | ||
const res = vm.runInContext( | ||
'__result = ' + input, | ||
vm.createContext(sandbox) | ||
); | ||
return res; | ||
} | ||
/** | ||
* Needs preprocessing because must be executed in javascript. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processNumberDecimal(ctx) { | ||
ctx.type = this.Types.NumberDecimal; | ||
const symbolType = this.Symbols.NumberDecimal; | ||
let decstr; | ||
try { | ||
decstr = this.executeJavascript(`new ${ctx.getText()}`).toString(); | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
/** | ||
* BinData needs extra processing because we need to check that the arg is | ||
* valid base64. | ||
* | ||
* TODO: figure out if it ever makes sense to support Binary. | ||
*/ | ||
processBinData() { | ||
throw new BsonTranspilersUnimplementedError('BinData type not supported'); | ||
} | ||
if ('emitNumberDecimal' in this) { | ||
return this.emitNumberDecimal(ctx, decstr); | ||
/** | ||
* Needs preprocessing because must be executed in javascript. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processNumberDecimal(ctx) { | ||
ctx.type = this.Types.NumberDecimal; | ||
const symbolType = this.Symbols.NumberDecimal; | ||
let decstr; | ||
try { | ||
decstr = this.executeJavascript(`new ${ctx.getText()}`).toString(); | ||
} catch (error) { | ||
throw new BsonTranspilersRuntimeError(error.message); | ||
} | ||
if ('emitNumberDecimal' in this) { | ||
return this.emitNumberDecimal(ctx, decstr); | ||
} | ||
const lhs = symbolType.template | ||
? symbolType.template() | ||
: this.returnFunctionCallLhs(symbolType.code, 'NumberDecimal'); | ||
const res = this.returnFunctionCallLhsRhs(lhs, [decstr], symbolType, lhs); | ||
return this.Syntax.new.template | ||
? this.Syntax.new.template(res, false, ctx.type.code) | ||
: this.returnFunctionCallLhsRhs(lhs, [decstr], symbolType, lhs); | ||
} | ||
const lhs = symbolType.template | ||
? symbolType.template() | ||
: this.returnFunctionCallLhs(symbolType.code, 'NumberDecimal'); | ||
const res = this.returnFunctionCallLhsRhs(lhs, [decstr], symbolType, lhs); | ||
/** | ||
* Needs preprocessing because ISODate is treated exactly like Date, but always | ||
* is invoked as an object. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processISODate(ctx) { | ||
ctx.wasNew = true; | ||
return this.processDate(ctx); | ||
} | ||
return this.Syntax.new.template | ||
? this.Syntax.new.template(res, false, ctx.type.code) | ||
: this.returnFunctionCallLhsRhs(lhs, [decstr], symbolType, lhs); | ||
} | ||
/** | ||
* Also accepts no arguments. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processCode(ctx) { | ||
ctx.type = this.Types.Code; | ||
const symbolType = this.Symbols.Code; | ||
const lhs = symbolType.template | ||
? symbolType.template() | ||
: this.returnFunctionCallLhs(symbolType.code, 'Code'); | ||
/** | ||
* Needs preprocessing because ISODate is treated exactly like Date, but always | ||
* is invoked as an object. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processISODate(ctx) { | ||
ctx.wasNew = true; | ||
return this.processDate(ctx); | ||
} | ||
if (this.getArguments(ctx).length === 0) { | ||
const code = this.returnFunctionCallLhsRhs(lhs, [], symbolType, lhs); | ||
return this.Syntax.new.template | ||
? this.Syntax.new.template(code, false, ctx.type.code) | ||
: code; | ||
} | ||
/** | ||
* Also accepts no arguments. | ||
* | ||
* @param {FuncCallExpressionContext} ctx | ||
* @return {String} | ||
*/ | ||
processCode(ctx) { | ||
ctx.type = this.Types.Code; | ||
const symbolType = this.Symbols.Code; | ||
const lhs = symbolType.template | ||
? symbolType.template() | ||
: this.returnFunctionCallLhs(symbolType.code, 'Code'); | ||
if (this.getArguments(ctx).length === 0) { | ||
const code = this.returnFunctionCallLhsRhs(lhs, [], symbolType, lhs); | ||
return this.Syntax.new.template | ||
? this.Syntax.new.template(code, false, ctx.type.code) | ||
: code; | ||
return this.generateBSONCode(ctx, ctx.type, symbolType, true); | ||
} | ||
return this.generateBSONCode(ctx, ctx.type, symbolType, true); | ||
} | ||
}; | ||
}; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/* eslint-disable no-sync */ | ||
@@ -47,3 +48,3 @@ const path = require('path'); | ||
path.join(inputLang, 'types.yaml'), | ||
path.join(inputLang, 'symbols.yaml') | ||
path.join(inputLang, 'symbols.yaml'), | ||
]; | ||
@@ -62,4 +63,15 @@ const contents = files.reduce((str, file) => { | ||
const dir = path.join(__dirname, 'lib', 'symbol-table'); | ||
const inputLangs = ['javascript', 'shell', 'python']; | ||
const outputLangs = ['java', 'shell', 'python', 'csharp', 'javascript', 'object', 'ruby', 'go', 'rust', 'php']; | ||
const inputLangs = ['shell']; | ||
const outputLangs = [ | ||
'java', | ||
'shell', | ||
'python', | ||
'csharp', | ||
'javascript', | ||
'object', | ||
'ruby', | ||
'go', | ||
'rust', | ||
'php', | ||
]; | ||
if (!fs.existsSync(dir)) { | ||
@@ -66,0 +78,0 @@ fs.mkdirSync(dir); |
@@ -29,2 +29,2 @@ { | ||
} | ||
} | ||
} |
# Contributing to bson-transpilers | ||
## Setting up your environment | ||
The `bson-transpilers` package uses | ||
@@ -10,2 +11,3 @@ [ANTLR4](https://github.com/antlr/antlr4/blob/master/doc/javascript-target.md) | ||
Make sure you have Java installed: | ||
```shell | ||
@@ -16,7 +18,8 @@ $ brew cask install java | ||
_I strongly suggest using an IDE that will help you visualize ANTLR trees (JetBrains has a good plugin). | ||
Otherwise you can use the java version of the grammar and compile it with | ||
`javac <Language>*.java && grun <Language> <StartRule> -gui`. | ||
[This might be helpful](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md)._ | ||
Otherwise you can use the java version of the grammar and compile it with | ||
`javac <Language>*.java && grun <Language> <StartRule> -gui`. | ||
[This might be helpful](https://github.com/antlr/antlr4/blob/master/doc/getting-started.md)._ | ||
Make sure you have run the following from the root directory: | ||
```shell | ||
@@ -27,2 +30,3 @@ $ npm run bootstrap | ||
Then compile and run tests locally with: | ||
```shell | ||
@@ -34,6 +38,7 @@ $ npm run compile && npm run test | ||
output and input languages. If none are provided, everything will run. | ||
- __INPUT=:__ comma-separated input languages you want to test | ||
- __OUTPUT=:__ comma-separated output languages you want to test. Also called "target" language. | ||
- __MODE=:__ comma-separated names of the test files (without .yaml) that you want to run | ||
- **INPUT=:** comma-separated input languages you want to test | ||
- **OUTPUT=:** comma-separated output languages you want to test. Also called "target" language. | ||
- **MODE=:** comma-separated names of the test files (without .yaml) that you want to run | ||
```shell | ||
@@ -46,3 +51,5 @@ OUTPUT=csharp INPUT=shell MODE=native,bson npm run test | ||
See also the original presentation: https://drive.google.com/file/d/1jvwtR3k9oBUzIjL4z_VtpHvdWahfcjTK/view | ||
## Compilation Stages | ||
Similar to how many transpilers work, this package parses the input | ||
@@ -53,2 +60,3 @@ string into a tree and then generates code from the tree using the [Visitor | ||
### Step 1: Parsing | ||
Parsing and tree generation is handled by ANTLR4. | ||
@@ -69,4 +77,4 @@ The grammar files are located in the `grammars` folder, and the javascript | ||
### Step 2: Visitor | ||
### Step 2: Visitor | ||
<img alt="visiting-tree" width="60%" align="right" src="/img-docs/visiting-tree.png"/> | ||
@@ -101,4 +109,4 @@ | ||
### Step 3: Generator | ||
### Step 3: Generator | ||
The other half of the tree visitation stage. Each ouput language will | ||
@@ -109,7 +117,8 @@ have a Generator class defined in `codegeneration/<ouput language>/Generator.js`. | ||
So for example, translating between JS and Python, the order of inheritance will be: | ||
1. `lib/antlr/ECMAScriptVisitor.js` ["empty" superclass, specific to the tree built by ANTLR] | ||
2. `codegeneration/CodeGenerationVisitor.js` ["generic" visitor, shared between all languages] | ||
3. `codegeneration/javascript/Visitor.js` [specific to input language] | ||
4. `codegeneration/python/Generator.js` [specific to output language] | ||
1. `lib/antlr/ECMAScriptVisitor.js` ["empty" superclass, specific to the tree built by ANTLR] | ||
2. `codegeneration/CodeGenerationVisitor.js` ["generic" visitor, shared between all languages] | ||
3. `codegeneration/javascript/Visitor.js` [specific to input language] | ||
4. `codegeneration/python/Generator.js` [specific to output language] | ||
For nodes that cannot be translated using | ||
@@ -127,2 +136,3 @@ templates, the Generator class will define a method called `emit<type>` which | ||
### Symbols | ||
Each input language has it's own set of symbols that are part of the | ||
@@ -136,2 +146,3 @@ language. The majority of symbols supported in the input languages are BSON types | ||
#### Symbol Metadata | ||
The visitor uses the symbol table to determine if a symbol is undefined, but the | ||
@@ -142,3 +153,2 @@ symbol table also stores some metadata so the visitor can do type and other validity checks. The symbols | ||
```yml | ||
@@ -164,16 +174,17 @@ Decimal128: | ||
``` | ||
<br> | ||
| Field | Data | | ||
| ----------|:-------------| | ||
| id | The name of the attribute. Mostly used for error reporting and the `emit` or `process` method names. | | ||
| callable | Used for determining if the symbol can be part of a function call. There are three types of symbols: <br><br>`*func`: a function call. If the symbol is found as the "left-hand-side" of a function call, it is valid. <br><br>`*constructor`: also a function call, but may require a `new` keyword if the output language requires it. <br><br>`*var`: a variable. Indicates to the transpiler that the symbol cannot be invoked, i.e. `<symbol>()` is invalid.| | ||
| args | Used for type checking. If the symbol is callable, i.e. a `*func` or `*constructor`, then the expected arguments are defined here as an array. So for example, if the function takes in a string as the first arg, and an optional second arg that can be a object or array, args will look like <br>`[ [*StringType], [*ObjectType, *ArrayType, null] ]`. Null indicates optional.| | ||
| type | The type that the symbol evaluates to. If it is a variable, it will be the type of the variable. If it is a function, it will be the return type. See the [Types](#types) section.| | ||
| attr | Used for determining if attribute access is valid. This field is also a symbol table, but a namespace-prefixed one. So for the example above, `Decimal128.fromString` is a valid attribute, so we need to define the symbol `fromString` in the same way we defined the `Decimal128` symbol.| | ||
| template | Used for code generation. See the [Templates](#templates) section.| | ||
| argsTemplate | Used for code generation. See the [Templates](#templates) section.| | ||
| Field | Data | | ||
| ------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| id | The name of the attribute. Mostly used for error reporting and the `emit` or `process` method names. | | ||
| callable | Used for determining if the symbol can be part of a function call. There are three types of symbols: <br><br>`*func`: a function call. If the symbol is found as the "left-hand-side" of a function call, it is valid. <br><br>`*constructor`: also a function call, but may require a `new` keyword if the output language requires it. <br><br>`*var`: a variable. Indicates to the transpiler that the symbol cannot be invoked, i.e. `<symbol>()` is invalid. | | ||
| args | Used for type checking. If the symbol is callable, i.e. a `*func` or `*constructor`, then the expected arguments are defined here as an array. So for example, if the function takes in a string as the first arg, and an optional second arg that can be a object or array, args will look like <br>`[ [*StringType], [*ObjectType, *ArrayType, null] ]`. Null indicates optional. | | ||
| type | The type that the symbol evaluates to. If it is a variable, it will be the type of the variable. If it is a function, it will be the return type. See the [Types](#types) section. | | ||
| attr | Used for determining if attribute access is valid. This field is also a symbol table, but a namespace-prefixed one. So for the example above, `Decimal128.fromString` is a valid attribute, so we need to define the symbol `fromString` in the same way we defined the `Decimal128` symbol. | | ||
| template | Used for code generation. See the [Templates](#templates) section. | | ||
| argsTemplate | Used for code generation. See the [Templates](#templates) section. | | ||
### Types | ||
### Types | ||
Each input language also has a set of types that are part of the language. | ||
@@ -184,4 +195,3 @@ The set of types that are universal for all languages (i.e. "primitives", | ||
Types that are specific to the input language are defined in `symbols/<input | ||
language>/types.yaml`. These include BSON types, i.e. classes like `ObjectId`, and | ||
Types that are specific to the input language are defined in `symbols/<input language>/types.yaml`. These include BSON types, i.e. classes like `ObjectId`, and | ||
language-specific types like `RegExp` and `Date`. The types are defined in the same | ||
@@ -195,3 +205,3 @@ pattern as the symbols and contain the same metadata as the symbols. | ||
and is a constructor, so `ObjectId()` is valid. The **type** `ObjectId` has | ||
attributes like `ObjectId().toString()` and is *a variable*, so `ObjectId()()` | ||
attributes like `ObjectId().toString()` and is _a variable_, so `ObjectId()()` | ||
is not valid and will error with `ObjectId() is not callable` or similar error. | ||
@@ -203,2 +213,3 @@ You can kind of think of types as instantiated symbols, if that's helpful. | ||
## Templates | ||
The symbol table includes an additional piece of metadata, called a `template`. | ||
@@ -216,2 +227,3 @@ These are functions that accept strings and return strings, and are responsible for | ||
## Project Structure | ||
<img alt="indexjs" width="60%" align="right" src="/img-docs/indexjs.jpg"/> | ||
@@ -225,2 +237,3 @@ | ||
To construct a transpiler, `index.js` needs 4 components: | ||
- `lib/antlr/<ANTLR tree visitor` The ANTLR-generated visitor for the generated parse tree. | ||
@@ -231,13 +244,13 @@ - `codegeneration/CodeGenerationVisitor.js` The "generic" visitor for all input languages. | ||
- `lib/symbol-table/<input language>to<ouput language>.js` - The symbol table for | ||
the input+output combination. | ||
the input+output combination. | ||
#### TL;DR | ||
- __CodeGenerationVisitor:__ place to store repeated code between all visitors. | ||
- __Visitor:__ visits nodes; processes input language via | ||
`processs` methods and sends information to either output language's template found in the `Symbol | ||
Template` or an `emit` method in the Generator`. | ||
- __Generator:__ processes output language via `emit` methods, which take in tree nodes and return strings. | ||
- __Symbol Table:__ a directory of the defined symbols, types and their metadata, including templates. | ||
- __Symbol Template:__ does string manipulation to provide output. | ||
- **CodeGenerationVisitor:** place to store repeated code between all visitors. | ||
- **Visitor:** visits nodes; processes input language via | ||
`processs` methods and sends information to either output language's template found in the `Symbol Template` or an `emit` method in the Generator`. | ||
- **Generator:** processes output language via `emit` methods, which take in tree nodes and return strings. | ||
- **Symbol Table:** a directory of the defined symbols, types and their metadata, including templates. | ||
- **Symbol Template:** does string manipulation to provide output. | ||
The class hierarchy of any transpiler is | ||
@@ -247,12 +260,14 @@ ANTLRVisitor <-- CodeGenerationVisitor <-- [input-language-specific] Visitor <-- [output-language-specific] Generator. | ||
## A primer on the different types of methods | ||
| Method name | Summary | | ||
|--------------|-----------| | ||
| `visit<*>` | Always auto-generated by ANTLR, overridden by language-specific visitors. Controls the flow of the tree visitation. | | ||
| `get<*>` | Wrapper methods around nodes, defined by language-specific visitors. They exist because different grammars call equivalent nodes different names. | | ||
| `generate<*>` | Shared logic between all input languages. Defined in `CodeGenerationVisitor` and called from language-specific visitor methods. | | ||
| `return<*>` | Separates string generation from object generation. Defined in `CodeGenerationVisitor` or `object/Generator`. | | ||
| `process<*>` | Special case for entire input language. Defined in visitors, called programmatically within the visitor. | | ||
| `emit<*>` | Special case for entire output language. Defined in generators, called programmatically by the visitors. | | ||
| Method name | Summary | | ||
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `visit<*>` | Always auto-generated by ANTLR, overridden by language-specific visitors. Controls the flow of the tree visitation. | | ||
| `get<*>` | Wrapper methods around nodes, defined by language-specific visitors. They exist because different grammars call equivalent nodes different names. | | ||
| `generate<*>` | Shared logic between all input languages. Defined in `CodeGenerationVisitor` and called from language-specific visitor methods. | | ||
| `return<*>` | Separates string generation from object generation. Defined in `CodeGenerationVisitor` or `object/Generator`. | | ||
| `process<*>` | Special case for entire input language. Defined in visitors, called programmatically within the visitor. | | ||
| `emit<*>` | Special case for entire output language. Defined in generators, called programmatically by the visitors. | | ||
### Tests | ||
Tests are written in YAML. Each yaml file requires two keys, first 'runner' which is a | ||
@@ -273,19 +288,33 @@ function that runs each individual test. The function signature is always `(it, expect, input, output, transpiler, test)` | ||
1. Create a directory in `symbols` directory for your output language: | ||
```shell | ||
mkdir symbols/<output lang> | ||
``` | ||
2. Create a `templates.yaml` file to store your language's templates. Inside | ||
you'll probably want to copy the contents from the `symbols/sample_templates.yaml` file. | ||
That file also includes comments on which template functions require unusual arguments. | ||
```shell | ||
cp symbols/sample_template.yaml symbols/<output lang>/templates.yaml | ||
``` | ||
3. Add your new language to the `compile-symbol-table.js` file: | ||
```js | ||
const outputLangs = ['java', 'shell', 'python', 'csharp', 'javascript', 'mylanguage']; | ||
const outputLangs = [ | ||
'java', | ||
'shell', | ||
'python', | ||
'csharp', | ||
'javascript', | ||
'mylanguage', | ||
]; | ||
``` | ||
4. You should now run `npm run compile` to generate a complete symbol table. | ||
This will be generated in `lib/symbol-table/javascriptto<output lang>` and | ||
`lib/symbol-table/shellto<output lang>`. | ||
`lib/symbol-table/shellto<output lang>`. | ||
5. You will have to require the generated symbol tables in `index.js`: | ||
```js | ||
@@ -309,18 +338,24 @@ const javascript<output lang>symbols = require('lib/symbol-table/javascriptto<output lang>') | ||
``` | ||
6. We still don't have a `Generator.js` file required above, so that won't | ||
quite work yet. So next, create a new directory in `codegeneration` for your | ||
output language: | ||
output language: | ||
```shell | ||
mkidr codegeneration/<output lang> | ||
``` | ||
7. And create a generator file: | ||
```shell | ||
touch codegeneration/<output lang>/Generator.js | ||
``` | ||
8. Most of the Generators are empty nowadays because the work has been moved into | ||
the templates. I would expect that 90% of the time, what you're trying to do can | ||
be done in the templates without changing the template signature. However, if you | ||
really can't do it in the templates, you can copy any of the generators that exist | ||
and fill in any emit methods you require. The class should be created with a super | ||
class that is passed to the function, like so: | ||
the templates. I would expect that 90% of the time, what you're trying to do can | ||
be done in the templates without changing the template signature. However, if you | ||
really can't do it in the templates, you can copy any of the generators that exist | ||
and fill in any emit methods you require. The class should be created with a super | ||
class that is passed to the function, like so: | ||
```js | ||
@@ -340,21 +375,26 @@ /* | ||
``` | ||
9. Next thing is tests! You must go through each test file and add the results of | ||
compiling each input into your output language under the `output` field. | ||
compiling each input into your output language under the `output` field. | ||
```yaml | ||
Document: | ||
- input: | ||
javascript: "{x: '1'}" | ||
shell: "{x: '1'}" | ||
python: "{'x': '1'}" | ||
output: | ||
javascript: "{\n 'x': '1'\n}" | ||
python: "{\n 'x': '1'\n}" | ||
java: "eq(\"x\", \"1\")" | ||
csharp: "new BsonDocument(\"x\", \"1\")" | ||
shell: "{\n 'x': '1'\n}" | ||
<your output language>: ... | ||
Document: | ||
- input: | ||
javascript: "{x: '1'}" | ||
shell: "{x: '1'}" | ||
python: "{'x': '1'}" | ||
output: | ||
javascript: "{\n 'x': '1'\n}" | ||
python: "{\n 'x': '1'\n}" | ||
java: 'eq("x", "1")' | ||
csharp: 'new BsonDocument("x", "1")' | ||
shell: "{\n 'x': '1'\n}" | ||
<your output language>: ... | ||
``` | ||
Make sure to add your output language in the outputLanguages array at the beginning | ||
of `run-yaml.test.js`, and to the list near the end of `functions.test.js`. | ||
## Adding an Input Language | ||
TODO! |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/* eslint-disable no-console */ | ||
@@ -18,2 +19,4 @@ /* eslint-disable no-sync */ | ||
https.get(downloadUrl, (response) => response.pipe(fs.createWriteStream(outputFile))); | ||
https.get(downloadUrl, (response) => | ||
response.pipe(fs.createWriteStream(outputFile)) | ||
); |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
const config = require('../config/error.json'); | ||
@@ -2,0 +3,0 @@ const errors = {}; |
@@ -0,1 +1,2 @@ | ||
'use strict'; | ||
/** | ||
@@ -7,9 +8,7 @@ * Takes in an identifier that may or may not be a string and returns a string | ||
*/ | ||
const doubleQuoteStringify = function(str) { | ||
const doubleQuoteStringify = function (str) { | ||
let newStr = str.toString(); | ||
if ( | ||
( | ||
newStr.charAt(0) === '\'' && newStr.charAt(newStr.length - 1) === '\'' | ||
) || | ||
(newStr.charAt(0) === "'" && newStr.charAt(newStr.length - 1) === "'") || | ||
(newStr.charAt(0) === '"' && newStr.charAt(newStr.length - 1) === '"') | ||
@@ -29,9 +28,7 @@ ) { | ||
*/ | ||
const singleQuoteStringify = function(str) { | ||
const singleQuoteStringify = function (str) { | ||
let newStr = str.toString(); | ||
if ( | ||
( | ||
newStr.charAt(0) === '\'' && newStr.charAt(newStr.length - 1) === '\'' | ||
) || | ||
(newStr.charAt(0) === "'" && newStr.charAt(newStr.length - 1) === "'") || | ||
(newStr.charAt(0) === '"' && newStr.charAt(newStr.length - 1) === '"') | ||
@@ -51,3 +48,3 @@ ) { | ||
*/ | ||
const removeQuotes = function(str) { | ||
const removeQuotes = function (str) { | ||
let newStr = str.toString(); | ||
@@ -57,3 +54,3 @@ | ||
(newStr.charAt(0) === '"' && newStr.charAt(newStr.length - 1) === '"') || | ||
(newStr.charAt(0) === '\'' && newStr.charAt(newStr.length - 1) === '\'') | ||
(newStr.charAt(0) === "'" && newStr.charAt(newStr.length - 1) === "'") | ||
) { | ||
@@ -69,3 +66,3 @@ newStr = newStr.substr(1, newStr.length - 2); | ||
singleQuoteStringify, | ||
removeQuotes | ||
removeQuotes, | ||
}; |
245
index.js
@@ -0,9 +1,8 @@ | ||
'use strict'; | ||
const antlr4 = require('antlr4'); | ||
const ECMAScriptLexer = require('./lib/antlr/ECMAScriptLexer.js'); | ||
const ECMAScriptParser = require('./lib/antlr/ECMAScriptParser.js'); | ||
const Python3Lexer = require('./lib/antlr/Python3Lexer.js'); | ||
const Python3Parser = require('./lib/antlr/Python3Parser'); | ||
const JavascriptANTLRVisitor = require('./lib/antlr/ECMAScriptVisitor').ECMAScriptVisitor; | ||
const PythonANTLRVisitor = require('./lib/antlr/Python3Visitor').Python3Visitor; | ||
const JavascriptANTLRVisitor = | ||
require('./lib/antlr/ECMAScriptVisitor').ECMAScriptVisitor; | ||
@@ -13,3 +12,3 @@ const ErrorListener = require('./codegeneration/ErrorListener.js'); | ||
BsonTranspilersInternalError, | ||
BsonTranspilersUnimplementedError | ||
BsonTranspilersUnimplementedError, | ||
} = require('./helper/error'); | ||
@@ -22,8 +21,5 @@ | ||
const getShellVisitor = require('./codegeneration/shell/Visitor'); | ||
const getPythonVisitor = require('./codegeneration/python/Visitor'); | ||
const getJavaGenerator = require('./codegeneration/java/Generator'); | ||
const getPythonGenerator = require('./codegeneration/python/Generator'); | ||
const getCsharpGenerator = require('./codegeneration/csharp/Generator'); | ||
const getShellGenerator = require('./codegeneration/shell/Generator'); | ||
const getJavascriptGenerator = require('./codegeneration/javascript/Generator'); | ||
@@ -36,12 +32,2 @@ const getObjectGenerator = require('./codegeneration/object/Generator'); | ||
const javascriptjavasymbols = require('./lib/symbol-table/javascripttojava'); | ||
const javascriptpythonsymbols = require('./lib/symbol-table/javascripttopython'); | ||
const javascriptcsharpsymbols = require('./lib/symbol-table/javascripttocsharp'); | ||
const javascriptshellsymbols = require('./lib/symbol-table/javascripttoshell'); | ||
const javascriptobjectsymbols = require('./lib/symbol-table/javascripttoobject'); | ||
const javascriptrubysymbols = require('./lib/symbol-table/javascripttoruby'); | ||
const javascriptgosymbols = require('./lib/symbol-table/javascripttogo'); | ||
const javascriptrustsymbols = require('./lib/symbol-table/javascripttorust'); | ||
const javascriptphpsymbols = require('./lib/symbol-table/javascripttophp'); | ||
const shelljavasymbols = require('./lib/symbol-table/shelltojava'); | ||
@@ -57,12 +43,2 @@ const shellpythonsymbols = require('./lib/symbol-table/shelltopython'); | ||
const pythonjavasymbols = require('./lib/symbol-table/pythontojava'); | ||
const pythonshellsymbols = require('./lib/symbol-table/pythontoshell'); | ||
const pythoncsharpsymbols = require('./lib/symbol-table/pythontocsharp'); | ||
const pythonjavascriptsymbols = require('./lib/symbol-table/pythontojavascript'); | ||
const pythonobjectsymbols = require('./lib/symbol-table/pythontoobject'); | ||
const pythonrubysymbols = require('./lib/symbol-table/pythontoruby'); | ||
const pythongosymbols = require('./lib/symbol-table/pythontogo'); | ||
const pythonrustsymbols = require('./lib/symbol-table/pythontorust'); | ||
const pythonphpsymbols = require('./lib/symbol-table/pythontophp'); | ||
/** | ||
@@ -92,25 +68,2 @@ * Constructs the parse tree from the JS or Shell code given by the user. | ||
/** | ||
* Constructs the parse tree from the Python code given by the user. | ||
* | ||
* @param {String} input | ||
* @param {String} start - the name of the start node. Always defined in the | ||
* language-specific visitor. | ||
* @return {antlr4.ParserRuleContext} - The parse tree. | ||
*/ | ||
const loadPyTree = (input, start) => { | ||
const chars = new antlr4.InputStream(input + '\n'); // requires newline | ||
const lexer = new Python3Lexer.Python3Lexer(chars); | ||
const tokens = new antlr4.CommonTokenStream(lexer); | ||
const parser = new Python3Parser.Python3Parser(tokens); | ||
parser.buildParseTrees = true; | ||
const listener = new ErrorListener(); | ||
parser.removeErrorListeners(); // Remove the default ConsoleErrorListener | ||
parser.addErrorListener(listener); // Add back a custom error listener | ||
return parser[start](); | ||
}; | ||
const getTranspiler = (loadTree, visitor, generator, symbols) => { | ||
@@ -124,4 +77,12 @@ const Transpiler = generator(visitor); | ||
* then an error should be thrown. Can be empty, but must exist. */ | ||
['BasicTypes', 'BsonTypes', 'NativeTypes', 'SymbolTypes', 'BsonTypes', | ||
'BsonSymbols', 'NativeSymbols', 'SymbolTypes'].map((k) => { | ||
[ | ||
'BasicTypes', | ||
'BsonTypes', | ||
'NativeTypes', | ||
'SymbolTypes', | ||
'BsonTypes', | ||
'BsonSymbols', | ||
'NativeSymbols', | ||
'SymbolTypes', | ||
].map((k) => { | ||
if (!(k in doc)) { | ||
@@ -139,3 +100,3 @@ throw new BsonTranspilersInternalError( | ||
Syntax: doc.Syntax, | ||
Imports: doc.Imports | ||
Imports: doc.Imports, | ||
}); | ||
@@ -146,5 +107,4 @@ | ||
const tree = loadTree(input, transpiler.startRule); | ||
transpiler.idiomatic = idiomatic === undefined ? | ||
transpiler.idiomatic : | ||
idiomatic; | ||
transpiler.idiomatic = | ||
idiomatic === undefined ? transpiler.idiomatic : idiomatic; | ||
if (!driverSyntax) { | ||
@@ -172,8 +132,13 @@ transpiler.clearImports(); | ||
Object.keys(input).map((k) => { | ||
result[k] = k === 'options' ? input[k] : compile(input[k], idiomatic, true); | ||
result[k] = | ||
k === 'options' || k === 'exportMode' | ||
? input[k] | ||
: compile(input[k], idiomatic, true); | ||
}); | ||
if (!('options' in result) || | ||
!('uri' in result.options) || | ||
!('database' in result.options) || | ||
!('collection' in result.options)) { | ||
if ( | ||
!('options' in result) || | ||
!('uri' in result.options) || | ||
!('database' in result.options) || | ||
!('collection' in result.options) | ||
) { | ||
throw new BsonTranspilersInternalError( | ||
@@ -185,3 +150,3 @@ 'Missing required metadata to generate drivers syntax' | ||
throw new BsonTranspilersInternalError( | ||
'Need to pass \'aggregation\' or \'filter\' when compiling with driver syntax' | ||
"Need to pass 'aggregation' or 'filter' when compiling with driver syntax" | ||
); | ||
@@ -199,3 +164,3 @@ } | ||
return transpiler.getImports(mode, driverSyntax); | ||
} | ||
}, | ||
}; | ||
@@ -205,62 +170,8 @@ }; | ||
module.exports = { | ||
javascript: { | ||
java: getTranspiler( | ||
loadJSTree, | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)), | ||
getJavaGenerator, | ||
javascriptjavasymbols | ||
), | ||
python: getTranspiler( | ||
loadJSTree, | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)), | ||
getPythonGenerator, | ||
javascriptpythonsymbols | ||
), | ||
csharp: getTranspiler( | ||
loadJSTree, | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)), | ||
getCsharpGenerator, | ||
javascriptcsharpsymbols | ||
), | ||
shell: getTranspiler( | ||
loadJSTree, | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)), | ||
getShellGenerator, | ||
javascriptshellsymbols | ||
), | ||
object: getTranspiler( | ||
loadJSTree, | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)), | ||
getObjectGenerator, | ||
javascriptobjectsymbols | ||
), | ||
ruby: getTranspiler( | ||
loadJSTree, | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)), | ||
getRubyGenerator, | ||
javascriptrubysymbols | ||
), | ||
go: getTranspiler( | ||
loadJSTree, | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)), | ||
getGoGenerator, | ||
javascriptgosymbols | ||
), | ||
rust: getTranspiler( | ||
loadJSTree, | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)), | ||
getRustGenerator, | ||
javascriptrustsymbols | ||
), | ||
php: getTranspiler( | ||
loadJSTree, | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)), | ||
getPhpGenerator, | ||
javascriptphpsymbols | ||
) | ||
}, | ||
shell: { | ||
java: getTranspiler( | ||
loadJSTree, | ||
getShellVisitor(getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor))), | ||
getShellVisitor( | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)) | ||
), | ||
getJavaGenerator, | ||
@@ -271,3 +182,5 @@ shelljavasymbols | ||
loadJSTree, | ||
getShellVisitor(getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor))), | ||
getShellVisitor( | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)) | ||
), | ||
getPythonGenerator, | ||
@@ -278,3 +191,5 @@ shellpythonsymbols | ||
loadJSTree, | ||
getShellVisitor(getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor))), | ||
getShellVisitor( | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)) | ||
), | ||
getCsharpGenerator, | ||
@@ -285,3 +200,5 @@ shellcsharpsymbols | ||
loadJSTree, | ||
getShellVisitor(getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor))), | ||
getShellVisitor( | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)) | ||
), | ||
getJavascriptGenerator, | ||
@@ -292,3 +209,5 @@ shelljavascriptsymbols | ||
loadJSTree, | ||
getShellVisitor(getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor))), | ||
getShellVisitor( | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)) | ||
), | ||
getObjectGenerator, | ||
@@ -299,3 +218,5 @@ shellobjectsymbols | ||
loadJSTree, | ||
getShellVisitor(getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor))), | ||
getShellVisitor( | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)) | ||
), | ||
getRubyGenerator, | ||
@@ -306,3 +227,5 @@ shellrubysymbols | ||
loadJSTree, | ||
getShellVisitor(getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor))), | ||
getShellVisitor( | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)) | ||
), | ||
getGoGenerator, | ||
@@ -313,3 +236,5 @@ shellgosymbols | ||
loadJSTree, | ||
getShellVisitor(getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor))), | ||
getShellVisitor( | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)) | ||
), | ||
getRustGenerator, | ||
@@ -320,68 +245,12 @@ shellrustsymbols | ||
loadJSTree, | ||
getShellVisitor(getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor))), | ||
getShellVisitor( | ||
getJavascriptVisitor(getCodeGenerationVisitor(JavascriptANTLRVisitor)) | ||
), | ||
getPhpGenerator, | ||
shellphpsymbols | ||
) | ||
}, | ||
python: { | ||
java: getTranspiler( | ||
loadPyTree, | ||
getPythonVisitor(getCodeGenerationVisitor(PythonANTLRVisitor)), | ||
getJavaGenerator, | ||
pythonjavasymbols | ||
), | ||
shell: getTranspiler( | ||
loadPyTree, | ||
getPythonVisitor(getCodeGenerationVisitor(PythonANTLRVisitor)), | ||
getShellGenerator, | ||
pythonshellsymbols | ||
), | ||
csharp: getTranspiler( | ||
loadPyTree, | ||
getPythonVisitor(getCodeGenerationVisitor(PythonANTLRVisitor)), | ||
getCsharpGenerator, | ||
pythoncsharpsymbols | ||
), | ||
javascript: getTranspiler( | ||
loadPyTree, | ||
getPythonVisitor(getCodeGenerationVisitor(PythonANTLRVisitor)), | ||
getJavascriptGenerator, | ||
pythonjavascriptsymbols | ||
), | ||
object: getTranspiler( | ||
loadPyTree, | ||
getPythonVisitor(getCodeGenerationVisitor(PythonANTLRVisitor)), | ||
getObjectGenerator, | ||
pythonobjectsymbols | ||
), | ||
ruby: getTranspiler( | ||
loadPyTree, | ||
getPythonVisitor(getCodeGenerationVisitor(PythonANTLRVisitor)), | ||
getRubyGenerator, | ||
pythonrubysymbols | ||
), | ||
go: getTranspiler( | ||
loadPyTree, | ||
getPythonVisitor(getCodeGenerationVisitor(PythonANTLRVisitor)), | ||
getGoGenerator, | ||
pythongosymbols | ||
), | ||
rust: getTranspiler( | ||
loadPyTree, | ||
getPythonVisitor(getCodeGenerationVisitor(PythonANTLRVisitor)), | ||
getRustGenerator, | ||
pythonrustsymbols | ||
), | ||
php: getTranspiler( | ||
loadPyTree, | ||
getPythonVisitor(getCodeGenerationVisitor(PythonANTLRVisitor)), | ||
getPhpGenerator, | ||
pythonphpsymbols | ||
) | ||
}, | ||
getTree: { | ||
javascript: loadJSTree, | ||
shell: loadJSTree, | ||
python: loadPyTree | ||
} | ||
}, | ||
}; |
@@ -1,1 +0,1 @@ | ||
module.exports="SymbolTypes:\n VAR: &var 0\n CONSTRUCTOR: &constructor 1\n FUNC: &func 2\n# Internal patterns to save typing\n__type: &__type\n id: null\n callable: *var\n args: null\n type: null\n attr: {}\n template: null\n argsTemplate: null\n__func: &__func\n callable: *func\n args: []\n attr: {}\n template: null\n argsTemplate: null\n\n# Javascript Templates\nTemplates:\n # Misc\n RegexFlags: &RegexFlags\n i: 'i'\n m: 'm'\n u: 'u'\n y: 'y'\n g: 'g'\n BSONRegexFlags: &BSONRegexFlags\n i: 'i'\n m: 'm'\n x: 'x'\n s: 's'\n l: 'l'\n u: 'u'\n # Syntax\n DriverTemplate: &DriverTemplate !!js/function |\n (spec) => {\n const comment = `/*\n * Requires the MongoDB Node.js Driver\n * https://mongodb.github.io/node-mongodb-native\n */`;\n const translateKey = {\n project: 'projection'\n };\n\n let cmd;\n let defs;\n if ('aggregation' in spec) {\n const agg = spec.aggregation;\n cmd = `const cursor = coll.aggregate(agg);`;\n defs = `const agg = ${agg};\\n`;\n } else {\n let opts = '';\n const args = {};\n Object.keys(spec).forEach((k) => {\n if (k !== 'options') {\n args[k in translateKey ? translateKey[k] : k] = spec[k];\n }\n });\n\n if (Object.keys(args).length > 0) {\n defs = Object.keys(args).reduce((s, k) => {\n if (k !== 'filter') {\n if (opts === '') {\n opts = `${k}`;\n } else {\n opts = `${opts}, ${k}`;\n }\n }\n return `${s}const ${k} = ${args[k]};\\n`;\n }, '');\n opts = opts === '' ? '' : `, { ${opts} }`;\n }\n cmd = `const cursor = coll.find(filter${opts});`;\n }\n return `${comment}\\n\\n${defs}\n const client = await MongoClient.connect(\n '${spec.options.uri}',\n { useNewUrlParser: true, useUnifiedTopology: true }\n );\n const coll = client.db('${spec.options.database}').collection('${spec.options.collection}');\n ${cmd}\n const result = await cursor.toArray();\n await client.close();`;\n }\n EqualitySyntaxTemplate: &EqualitySyntaxTemplate !!js/function >\n (lhs, op, rhs) => {\n if (op.includes('!') || op.includes('not')) {\n return `${lhs} !== ${rhs}`;\n } else if (op === '==' || op === '===' || op === 'is') {\n return `${lhs} === ${rhs}`;\n }\n return `${lhs} ${op} ${rhs}`;\n }\n InSyntaxTemplate: &InSyntaxTemplate !!js/function >\n (lhs, op, rhs) => {\n let str = '!==';\n if (op.includes('!') || op.includes('not')) {\n str = '===';\n }\n return `${rhs}.indexOf(${lhs}) ${str} -1`\n }\n AndSyntaxTemplate: &AndSyntaxTemplate !!js/function >\n (args) => {\n return args.join(' && ');\n }\n OrSyntaxTemplate: &OrSyntaxTemplate !!js/function >\n (args) => {\n return args.join(' || ');\n }\n NotSyntaxTemplate: &NotSyntaxTemplate !!js/function >\n (arg) => {\n return `!${arg}`;\n }\n UnarySyntaxTemplate: &UnarySyntaxTemplate null\n BinarySyntaxTemplate: &BinarySyntaxTemplate !!js/function >\n (args) => {\n return args.reduce((s, op, i, arr) => {\n if (i % 2 === 0) {\n return s;\n }\n const rhs = arr[i + 1];\n switch(op) {\n case '//':\n return `Math.floor(${s}, ${rhs})`;\n case '**':\n return `Math.pow(${s}, ${rhs})`;\n default:\n return `${s} ${op} ${rhs}`;\n }\n }, args[0]);\n }\n ParensSyntaxTemplate: &ParensSyntaxTemplate null\n EosSyntaxTemplate: &EosSyntaxTemplate null\n EofSyntaxTemplate: &EofSyntaxTemplate null\n NewTemplate: &NewSyntaxTemplate !!js/function >\n (expr, skip, code) => {\n // Add classes that don't use \"new\" to array.\n // So far: [Date.now, Decimal128/NumberDecimal, Long/NumberLong]\n noNew = [200.1, 112, 106];\n if (skip || (code && noNew.indexOf(code) !== -1)) {\n return expr;\n }\n return `new ${expr}`;\n }\n # BSON Object Type templates\n CodeTypeTemplate: &CodeTypeTemplate null\n StringTypeTemplate: &StringTypeTemplate !!js/function >\n (str) => {\n let newStr = str;\n if (\n (str.charAt(0) === '\\'' && str.charAt(str.length - 1) === '\\'') ||\n (str.charAt(0) === '\"' && str.charAt(str.length - 1) === '\"')) {\n newStr = str.substr(1, str.length - 2);\n }\n return `'${newStr.replace(/\\\\([\\s\\S])|(')/g, '\\\\$1$2')}'`;\n }\n RegexTypeTemplate: &RegexTypeTemplate !!js/function >\n (pattern, flags) => {\n const str = pattern;\n let newStr = str;\n if (\n (str.charAt(0) === '\\'' && str.charAt(str.length - 1) === '\\'') ||\n (str.charAt(0) === '\"' && str.charAt(str.length - 1) === '\"')) {\n newStr = str.substr(1, str.length - 2);\n }\n pattern = `'${newStr.replace(/\\\\([\\s\\S])|(')/g, '\\\\$1$2')}'`;\n return `RegExp(${pattern}${flags ? ', ' + '\\'' + flags + '\\'': ''})`;\n }\n BoolTypeTemplate: &BoolTypeTemplate !!js/function >\n (literal) => {\n return literal.toLowerCase();\n }\n IntegerTypeTemplate: &IntegerTypeTemplate null\n DecimalTypeTemplate: &DecimalTypeTemplate null\n LongBasicTypeTemplate: &LongBasicTypeTemplate null\n HexTypeTemplate: &HexTypeTemplate null\n OctalTypeTemplate: &OctalTypeTemplate null\n NumericTypeTemplate: &NumericTypeTemplate null\n ArrayTypeTemplate: &ArrayTypeTemplate !!js/function >\n (literal, depth) => {\n depth++;\n if (literal === '') {\n return '[]'\n }\n const indent = '\\n' + ' '.repeat(depth);\n const closingIndent = '\\n' + ' '.repeat(depth - 1);\n\n return `[${indent}${literal}${closingIndent}]`;\n }\n ArrayTypeArgsTemplate: &ArrayTypeArgsTemplate null\n NullTypeTemplate: &NullTypeTemplate !!js/function >\n () => {\n return 'null';\n }\n UndefinedTypeTemplate: &UndefinedTypeTemplate !!js/function >\n () => {\n return 'undefined';\n }\n ObjectTypeTemplate: &ObjectTypeTemplate !!js/function >\n (literal) => {\n if (literal === '') {\n return '{}';\n }\n return literal;\n }\n ObjectTypeArgsTemplate: &ObjectTypeArgsTemplate !!js/function >\n (args, depth) => {\n if (args.length === 0) {\n return '{}';\n }\n depth++;\n const indent = '\\n' + ' '.repeat(depth);\n const closingIndent = '\\n' + ' '.repeat(depth - 1);\n const singleStringify = (str) => {\n let newStr = str;\n if (\n (str.charAt(0) === '\\'' && str.charAt(str.length - 1) === '\\'') ||\n (str.charAt(0) === '\"' && str.charAt(str.length - 1) === '\"')) {\n newStr = str.substr(1, str.length - 2);\n }\n return `'${newStr.replace(/\\\\([\\s\\S])|(')/g, '\\\\$1$2')}'`;\n }\n const pairs = args.map((arg) => {\n return `${indent}${singleStringify(arg[0])}: ${arg[1]}`;\n }).join(', ');\n\n return `{${pairs}${closingIndent}}`\n }\n # BSON Object Method templates\n CodeCodeTemplate: &CodeCodeTemplate null\n CodeCodeArgsTemplate: &CodeCodeArgsTemplate null\n CodeScopeTemplate: &CodeScopeTemplate null\n CodeScopeArgsTemplate: &CodeScopeArgsTemplate null\n ObjectIdToStringTemplate: &ObjectIdToStringTemplate !!js/function >\n (lhs) => {\n return `${lhs}.toString()`;\n }\n ObjectIdToStringArgsTemplate: &ObjectIdToStringArgsTemplate !!js/function >\n () => {\n return '';\n }\n ObjectIdEqualsTemplate: &ObjectIdEqualsTemplate null\n ObjectIdEqualsArgsTemplate: &ObjectIdEqualsArgsTemplate null\n ObjectIdGetTimestampTemplate: &ObjectIdGetTimestampTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getTimestamp()`;\n }\n ObjectIdGetTimestampArgsTemplate: &ObjectIdGetTimestampArgsTemplate !!js/function >\n () => {\n return '';\n }\n BinaryValueTemplate: &BinaryValueTemplate null\n BinaryValueArgsTemplate: &BinaryValueArgsTemplate null\n BinaryLengthTemplate: &BinaryLengthTemplate null\n BinaryLengthArgsTemplate: &BinaryLengthArgsTemplate null\n BinaryToStringTemplate: &BinaryToStringTemplate null\n BinaryToStringArgsTemplate: &BinaryToStringArgsTemplate null\n BinarySubtypeTemplate: &BinarySubtypeTemplate !!js/function >\n (lhs) => {\n return `${lhs}.sub_type`;\n }\n BinarySubtypeArgsTemplate: &BinarySubtypeArgsTemplate !!js/function >\n () => {\n return '';\n }\n DBRefGetDBTemplate: &DBRefGetDBTemplate !!js/function >\n (lhs) => {\n return `${lhs}.db`;\n }\n DBRefGetCollectionTemplate: &DBRefGetCollectionTemplate !!js/function >\n (lhs) => {\n return `${lhs}.namespace`;\n }\n DBRefGetIdTemplate: &DBRefGetIdTemplate !!js/function >\n (lhs) => {\n return `${lhs}.oid`;\n }\n DBRefGetDBArgsTemplate: &DBRefGetDBArgsTemplate !!js/function >\n () => {\n return '';\n }\n DBRefGetCollectionArgsTemplate: &DBRefGetCollectionArgsTemplate !!js/function >\n () => {\n return '';\n }\n DBRefGetIdArgsTemplate: &DBRefGetIdArgsTemplate !!js/function >\n () => {\n return '';\n }\n LongEqualsTemplate: &LongEqualsTemplate null\n LongEqualsArgsTemplate: &LongEqualsArgsTemplate null\n LongToStringTemplate: &LongToStringTemplate null\n LongToStringArgsTemplate: &LongToStringArgsTemplate null\n LongToIntTemplate: &LongToIntTemplate !!js/function >\n (lhs) => {\n return `${lhs}.toInt`;\n }\n LongToIntArgsTemplate: &LongToIntArgsTemplate null\n LongToNumberTemplate: &LongToNumberTemplate null\n LongToNumberArgsTemplate: &LongToNumberArgsTemplate null\n LongAddTemplate: &LongAddTemplate null\n LongAddArgsTemplate: &LongAddArgsTemplate null\n LongSubtractTemplate: &LongSubtractTemplate null\n LongSubtractArgsTemplate: &LongSubtractArgsTemplate null\n LongMultiplyTemplate: &LongMultiplyTemplate null\n LongMultiplyArgsTemplate: &LongMultiplyArgsTemplate null\n LongDivTemplate: &LongDivTemplate null\n LongDivArgsTemplate: &LongDivArgsTemplate null\n LongModuloTemplate: &LongModuloTemplate null\n LongModuloArgsTemplate: &LongModuloArgsTemplate null\n LongAndTemplate: &LongAndTemplate null\n LongAndArgsTemplate: &LongAndArgsTemplate null\n LongOrTemplate: &LongOrTemplate null\n LongOrArgsTemplate: &LongOrArgsTemplate null\n LongXorTemplate: &LongXorTemplate null\n LongXorArgsTemplate: &LongXorArgsTemplate null\n LongShiftLeftTemplate: &LongShiftLeftTemplate null\n LongShiftLeftArgsTemplate: &LongShiftLeftArgsTemplate null\n LongShiftRightTemplate: &LongShiftRightTemplate null\n LongShiftRightArgsTemplate: &LongShiftRightArgsTemplate null\n LongCompareTemplate: &LongCompareTemplate null\n LongCompareArgsTemplate: &LongCompareArgsTemplate null\n LongIsOddTemplate: &LongIsOddTemplate null\n LongIsOddArgsTemplate: &LongIsOddArgsTemplate null\n LongIsZeroTemplate: &LongIsZeroTemplate null\n LongIsZeroArgsTemplate: &LongIsZeroArgsTemplate null\n LongIsNegativeTemplate: &LongIsNegativeTemplate null\n LongIsNegativeArgsTemplate: &LongIsNegativeArgsTemplate null\n LongNegateTemplate: &LongNegateTemplate null\n LongNegateArgsTemplate: &LongNegateArgsTemplate null\n LongNotTemplate: &LongNotTemplate null\n LongNotArgsTemplate: &LongNotArgsTemplate null\n LongNotEqualsTemplate: &LongNotEqualsTemplate null\n LongNotEqualsArgsTemplate: &LongNotEqualsArgsTemplate null\n LongGreaterThanTemplate: &LongGreaterThanTemplate null\n LongGreaterThanArgsTemplate: &LongGreaterThanArgsTemplate null\n LongGreaterThanOrEqualTemplate: &LongGreaterThanOrEqualTemplate null\n LongGreaterThanOrEqualArgsTemplate: &LongGreaterThanOrEqualArgsTemplate null\n LongLessThanTemplate: &LongLessThanTemplate null\n LongLessThanArgsTemplate: &LongLessThanArgsTemplate null\n LongLessThanOrEqualTemplate: &LongLessThanOrEqualTemplate null\n LongLessThanOrEqualArgsTemplate: &LongLessThanOrEqualArgsTemplate null\n LongFloatApproxTemplate: &LongFloatApproxTemplate !!js/function >\n (lhs) => {\n return `${lhs}.toNumber()`;\n }\n LongTopTemplate: &LongTopTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getHighBits()`;\n }\n LongBottomTemplate: &LongBottomTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getLowBits()`;\n }\n TimestampToStringTemplate: &TimestampToStringTemplate null\n TimestampToStringArgsTemplate: &TimestampToStringArgsTemplate null\n TimestampEqualsTemplate: &TimestampEqualsTemplate null\n TimestampEqualsArgsTemplate: &TimestampEqualsArgsTemplate null\n TimestampGetLowBitsTemplate: &TimestampGetLowBitsTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getLowBits`;\n }\n TimestampGetLowBitsArgsTemplate: &TimestampGetLowBitsArgsTemplate null\n TimestampGetHighBitsTemplate: &TimestampGetHighBitsTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getHighBits`;\n }\n TimestampGetHighBitsArgsTemplate: &TimestampGetHighBitsArgsTemplate null\n TimestampTTemplate: &TimestampTTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getLowBits()`;\n }\n TimestampITemplate: &TimestampITemplate !!js/function >\n (lhs) => {\n return `${lhs}.getHighBits()`;\n }\n TimestampAsDateTemplate: &TimestampAsDateTemplate !!js/function >\n (lhs) => {\n return `new Date(${lhs}.getHighBits() * 1000)`;\n }\n TimestampAsDateArgsTemplate: &TimestampAsDateArgsTemplate !!js/function >\n () => {\n return '';\n }\n TimestampCompareTemplate: &TimestampCompareTemplate null\n TimestampCompareArgsTemplate: &TimestampCompareArgsTemplate null\n TimestampNotEqualsTemplate: &TimestampNotEqualsTemplate null\n TimestampNotEqualsArgsTemplate: &TimestampNotEqualsArgsTemplate null\n TimestampGreaterThanTemplate: &TimestampGreaterThanTemplate null\n TimestampGreaterThanArgsTemplate: &TimestampGreaterThanArgsTemplate null\n TimestampGreaterThanOrEqualTemplate: &TimestampGreaterThanOrEqualTemplate null\n TimestampGreaterThanOrEqualArgsTemplate: &TimestampGreaterThanOrEqualArgsTemplate null\n TimestampLessThanTemplate: &TimestampLessThanTemplate null\n TimestampLessThanArgsTemplate: &TimestampLessThanArgsTemplate null\n TimestampLessThanOrEqualTemplate: &TimestampLessThanOrEqualTemplate null\n TimestampLessThanOrEqualArgsTemplate: &TimestampLessThanOrEqualArgsTemplate null\n SymbolValueOfTemplate: &SymbolValueOfTemplate null\n SymbolValueOfArgsTemplate: &SymbolValueOfArgsTemplate null\n SymbolInspectTemplate: &SymbolInspectTemplate null\n SymbolInspectArgsTemplate: &SymbolInspectArgsTemplate null\n SymbolToStringTemplate: &SymbolToStringTemplate null\n SymbolToStringArgsTemplate: &SymbolToStringArgsTemplate null\n # Symbol Templates\n CodeSymbolTemplate: &CodeSymbolTemplate null\n CodeSymbolArgsTemplate: &CodeSymbolArgsTemplate !!js/function >\n (lhs, code, scope) => {\n code = code === undefined ? '\\'\\'' : code;\n scope = scope === undefined ? '' : `, ${scope}`;\n return `(${code}${scope})`;\n }\n ObjectIdSymbolTemplate: &ObjectIdSymbolTemplate null\n ObjectIdSymbolArgsTemplate: &ObjectIdSymbolArgsTemplate !!js/function >\n (lhs, str) => {\n if (!str || str.length === 0) {\n return '()';\n }\n let newStr = str;\n if (\n (str.charAt(0) === '\\'' && str.charAt(str.length - 1) === '\\'') ||\n (str.charAt(0) === '\"' && str.charAt(str.length - 1) === '\"')) {\n newStr = str.substr(1, str.length - 2);\n }\n return `('${newStr.replace(/\\\\([\\s\\S])|(\")/g, '\\\\$1$2')}')`;\n }\n BinarySymbolTemplate: &BinarySymbolTemplate !!js/function >\n () => {\n return 'Binary';\n }\n BinarySymbolArgsTemplate: &BinarySymbolArgsTemplate !!js/function >\n (lhs, buffer, subtype) => {\n return `(${buffer.toString('base64')}, '${subtype}')`;\n }\n BinarySymbolSubtypeDefaultTemplate: &BinarySymbolSubtypeDefaultTemplate null\n BinarySymbolSubtypeFunctionTemplate: &BinarySymbolSubtypeFunctionTemplate null\n BinarySymbolSubtypeByteArrayTemplate: &BinarySymbolSubtypeByteArrayTemplate null\n BinarySymbolSubtypeUuidOldTemplate: &BinarySymbolSubtypeUuidOldTemplate null\n BinarySymbolSubtypeUuidTemplate: &BinarySymbolSubtypeUuidTemplate null\n BinarySymbolSubtypeMd5Template: &BinarySymbolSubtypeMd5Template null\n BinarySymbolSubtypeUserDefinedTemplate: &BinarySymbolSubtypeUserDefinedTemplate null\n DBRefSymbolTemplate: &DBRefSymbolTemplate null\n DBRefSymbolArgsTemplate: &DBRefSymbolArgsTemplate null\n DoubleSymbolTemplate: &DoubleSymbolTemplate !!js/function >\n () => {\n return 'Double';\n }\n DoubleSymbolArgsTemplate: &DoubleSymbolArgsTemplate null\n Int32SymbolTemplate: &Int32SymbolTemplate !!js/function >\n () => {\n return 'Int32';\n }\n Int32SymbolArgsTemplate: &Int32SymbolArgsTemplate !!js/function >\n (lhs, arg) => {\n arg = arg === undefined ? 0 : arg;\n return `(${arg})`;\n }\n LongSymbolTemplate: &LongSymbolTemplate !!js/function >\n () => {\n return '';\n }\n LongSymbolArgsTemplate: &LongSymbolArgsTemplate !!js/function >\n (lhs, arg, type) => {\n arg = arg === undefined ? 0 : arg;\n if (type === '_string') {\n return `Long.fromString(${arg})`;\n }\n return `Long.fromNumber(${arg})`;\n }\n LongSymbolMaxTemplate: &LongSymbolMaxTemplate null\n LongSymbolMaxArgsTemplate: &LongSymbolMaxArgsTemplate null\n LongSymbolMinTemplate: &LongSymbolMinTemplate null\n LongSymbolMinArgsTemplate: &LongSymbolMinArgsTemplate null\n LongSymbolZeroTemplate: &LongSymbolZeroTemplate null\n LongSymbolZeroArgsTemplate: &LongSymbolZeroArgsTemplate null\n LongSymbolOneTemplate: &LongSymbolOneTemplate null\n LongSymbolOneArgsTemplate: &LongSymbolOneArgsTemplate null\n LongSymbolNegOneTemplate: &LongSymbolNegOneTemplate null\n LongSymbolNegOneArgsTemplate: &LongSymbolNegOneArgsTemplate null\n LongSymbolFromBitsTemplate: &LongSymbolFromBitsTemplate null\n LongSymbolFromBitsArgsTemplate: &LongSymbolFromBitsArgsTemplate null\n LongSymbolFromIntTemplate: &LongSymbolFromIntTemplate null\n LongSymbolFromIntArgsTemplate: &LongSymbolFromIntArgsTemplate null\n LongSymbolFromNumberTemplate: &LongSymbolFromNumberTemplate null\n LongSymbolFromNumberArgsTemplate: &LongSymbolFromNumberArgsTemplate null\n LongSymbolFromStringTemplate: &LongSymbolFromStringTemplate null\n LongSymbolFromStringArgsTemplate: &LongSymbolFromStringArgsTemplate null\n MinKeySymbolTemplate: &MinKeySymbolTemplate null\n MinKeySymbolArgsTemplate: &MinKeySymbolArgsTemplate null\n MaxKeySymbolTemplate: &MaxKeySymbolTemplate null\n MaxKeySymbolArgsTemplate: &MaxKeySymbolArgsTemplate null\n TimestampSymbolTemplate: &TimestampSymbolTemplate null\n TimestampSymbolArgsTemplate: &TimestampSymbolArgsTemplate !!js/function >\n (lhs, arg1, arg2) => {\n return `(${arg1 === undefined ? 0 : arg1}, ${arg2 === undefined ? 0 : arg2})`;\n }\n SymbolSymbolTemplate: &SymbolSymbolTemplate !!js/function >\n () => {\n return 'BSONSymbol';\n }\n SymbolSymbolArgsTemplate: &SymbolSymbolArgsTemplate null\n BSONRegExpSymbolTemplate: &BSONRegExpSymbolTemplate !!js/function >\n () => {\n return 'BSONRegExp';\n }\n BSONRegExpSymbolArgsTemplate: &BSONRegExpSymbolArgsTemplate !!js/function >\n (lhs, pattern, flags) => {\n const singleStringify = (str) => {\n let newStr = str;\n if (\n (str.charAt(0) === '\\'' && str.charAt(str.length - 1) === '\\'') ||\n (str.charAt(0) === '\"' && str.charAt(str.length - 1) === '\"')) {\n newStr = str.substr(1, str.length - 2);\n }\n return `'${newStr.replace(/\\\\([\\s\\S])|(\")/g, '\\\\$1$2')}'`;\n }\n return `(${singleStringify(pattern)}${flags ? ', ' + singleStringify(flags) : ''})`;\n }\n Decimal128SymbolTemplate: &Decimal128SymbolTemplate !!js/function >\n () => {\n return 'Decimal128';\n }\n Decimal128SymbolArgsTemplate: &Decimal128SymbolArgsTemplate !!js/function >\n (lhs, arg) => {\n arg = arg === undefined ? '0' : arg.toString();\n if (arg.charAt(0) === '\\'' && arg.charAt(arg.length - 1) === '\\'') {\n return `.fromString(${arg})`;\n }\n return `.fromString('${arg}')`;\n }\n Decimal128SymbolFromStringTemplate: &Decimal128SymbolFromStringTemplate null\n Decimal128SymbolFromStringArgsTemplate: &Decimal128SymbolFromStringArgsTemplate null\n Decimal128ToStringTemplate: &Decimal128ToStringTemplate null\n Decimal128ToStringArgsTemplate: &Decimal128ToStringArgsTemplate null\n # BSON Util Templates\n ObjectIdCreateFromHexStringTemplate: &ObjectIdCreateFromHexStringTemplate null\n ObjectIdCreateFromHexStringArgsTemplate: &ObjectIdCreateFromHexStringArgsTemplate null\n ObjectIdCreateFromTimeTemplate: &ObjectIdCreateFromTimeTemplate !!js/function >\n () => {\n return `ObjectId.createFromTime`;\n }\n ObjectIdCreateFromTimeArgsTemplate: &ObjectIdCreateFromTimeArgsTemplate !!js/function >\n (lhs, arg, isNumber) => {\n if (!isNumber) {\n return `(${arg}.getTime() / 1000)`;\n }\n return `(${arg})`;\n }\n ObjectIdIsValidTemplate: &ObjectIdIsValidTemplate !!js/function >\n (lhs) => {\n return `${lhs}.isValid`;\n }\n ObjectIdIsValidArgsTemplate: &ObjectIdIsValidArgsTemplate null\n # JS Symbol Templates\n NumberSymbolTemplate: &NumberSymbolTemplate !!js/function >\n () => {\n return 'Number';\n }\n NumberSymbolArgsTemplate: &NumberSymbolArgsTemplate !!js/function >\n (lhs, arg) => {\n arg = arg === undefined ? '0' : arg;\n return `(${arg})`;\n }\n DateSymbolTemplate: &DateSymbolTemplate !!js/function >\n () => {\n return 'Date';\n }\n DateSymbolArgsTemplate: &DateSymbolArgsTemplate null\n DateSymbolNowTemplate: &DateSymbolNowTemplate !!js/function >\n () => {\n return 'Date.now';\n }\n DateSymbolNowArgsTemplate: &DateSymbolNowArgsTemplate null\n RegExpSymbolTemplate: &RegExpSymbolTemplate !!js/function >\n () => {\n return 'RegExp';\n }\n RegExpSymbolArgsTemplate: &RegExpSymbolArgsTemplate null\n ImportTemplate: &ImportTemplate !!js/function >\n (args) => {\n const bson = [];\n const other = [];\n Object.keys(args).map(\n (m) => {\n if (m > 99 && m < 200) {\n bson.push(args[m]);\n } else {\n other.push(args[m]);\n }\n }\n );\n if (bson.length) {\n other.push(`import {\\n ${bson.join(',\\n ')}\\n} from 'mongodb';`);\n }\n return other.join('\\n');\n }\n DriverImportTemplate: &DriverImportTemplate !!js/function >\n () => {\n return `import { MongoClient } from 'mongodb';`;\n }\n 0ImportTemplate: &0ImportTemplate null\n 1ImportTemplate: &1ImportTemplate null\n 2ImportTemplate: &2ImportTemplate null\n 3ImportTemplate: &3ImportTemplate null\n 4ImportTemplate: &4ImportTemplate null\n 5ImportTemplate: &5ImportTemplate null\n 6ImportTemplate: &6ImportTemplate null\n 7ImportTemplate: &7ImportTemplate null\n 8ImportTemplate: &8ImportTemplate null\n 9ImportTemplate: &9ImportTemplate null\n 10ImportTemplate: &10ImportTemplate null\n 11ImportTemplate: &11ImportTemplate null\n 12ImportTemplate: &12ImportTemplate null\n 100ImportTemplate: &100ImportTemplate !!js/function >\n () => {\n return 'Code';\n }\n 101ImportTemplate: &101ImportTemplate !!js/function >\n () => {\n return 'ObjectId';\n }\n 102ImportTemplate: &102ImportTemplate !!js/function >\n () => {\n return 'Binary';\n }\n 103ImportTemplate: &103ImportTemplate !!js/function >\n () => {\n return 'DBRef';\n }\n 104ImportTemplate: &104ImportTemplate !!js/function >\n () => {\n return 'Double';\n }\n 105ImportTemplate: &105ImportTemplate !!js/function >\n () => {\n return 'Int32';\n }\n 106ImportTemplate: &106ImportTemplate !!js/function >\n () => {\n return 'Long';\n }\n 107ImportTemplate: &107ImportTemplate !!js/function >\n () => {\n return 'MinKey';\n }\n 108ImportTemplate: &108ImportTemplate !!js/function >\n () => {\n return 'MaxKey';\n }\n 109ImportTemplate: &109ImportTemplate !!js/function >\n () => {\n return 'BSONRegExp';\n }\n 110ImportTemplate: &110ImportTemplate !!js/function >\n () => {\n return 'Timestamp';\n }\n 111ImportTemplate: &111ImportTemplate !!js/function >\n () => {\n return 'BSONSymbol';\n }\n 112ImportTemplate: &112ImportTemplate !!js/function >\n () => {\n return 'Decimal128';\n }\n 113ImportTemplate: &113ImportTemplate null\n 114ImportTemplate: &114ImportTemplate null\n 200ImportTemplate: &200ImportTemplate null\n 201ImportTemplate: &201ImportTemplate null\n 300ImportTemplate: &300ImportTemplate null\n 301ImportTemplate: &301ImportTemplate null\n 302ImportTemplate: &302ImportTemplate null\n 303ImportTemplate: &303ImportTemplate null\n 304ImportTemplate: &304ImportTemplate null\n 305ImportTemplate: &305ImportTemplate null\n 306ImportTemplate: &306ImportTemplate null\n# Universal types\n# Everything inherits from StringType because we haven't implemented any of them.\nBasicTypes:\n # Universal basic types\n _bool: &BoolType\n <<: *__type\n id: \"_bool\"\n code: 0\n template: *BoolTypeTemplate\n _integer: &IntegerType\n <<: *__type\n id: \"_integer\"\n code: 1\n template: *IntegerTypeTemplate\n _long: &LongBasicType\n <<: *__type\n id: \"_long\"\n code: 2\n template: *LongBasicTypeTemplate\n _decimal: &DecimalType\n <<: *__type\n id: \"_decimal\"\n code: 3\n template: *DecimalTypeTemplate\n _hex: &HexType\n <<: *__type\n id: \"_hex\"\n code: 4\n template: *HexTypeTemplate\n _octal: &OctalType\n <<: *__type\n id: \"_octal\"\n code: 5\n template: *OctalTypeTemplate\n _numeric: &NumericType\n <<: *__type\n id: \"_numeric\"\n code: 6\n template: *NumericTypeTemplate\n _string: &StringType\n <<: *__type\n id: \"_string\"\n code: 7\n template: *StringTypeTemplate\n _regex: &RegexType\n <<: *__type\n id: \"_regex\"\n code: 8\n template: *RegexTypeTemplate\n _array: &ArrayType\n <<: *__type\n id: \"_array\"\n code: 9\n template: *ArrayTypeTemplate\n argsTemplate: *ArrayTypeArgsTemplate\n _object: &ObjectType\n <<: *__type\n id: \"_object\"\n code: 10\n template: *ObjectTypeTemplate\n argsTemplate: *ObjectTypeArgsTemplate\n _null: &NullType\n <<: *__type\n id: \"_null\"\n code: 11\n template: *NullTypeTemplate\n _undefined: &UndefinedType\n <<: *__type\n id: \"_undefined\"\n code: 12\n template: *UndefinedTypeTemplate\n\nSyntax:\n equality:\n template: *EqualitySyntaxTemplate\n in:\n template: *InSyntaxTemplate\n and:\n template: *AndSyntaxTemplate\n or:\n template: *OrSyntaxTemplate\n not:\n template: *NotSyntaxTemplate\n unary:\n template: *UnarySyntaxTemplate\n binary:\n template: *BinarySyntaxTemplate\n parens:\n template: *ParensSyntaxTemplate\n eos:\n template: *EosSyntaxTemplate\n eof:\n template: *EofSyntaxTemplate\n # The new template takes in expr, and an optional skip argument and optional\n # id argument. The skip argument is a boolean that if true then doesn't add\n # new. The code argument is the symbol code being called. The template will check\n # if it is an exception, i.e. a type that is a constructor but may not use new.\n new:\n template: *NewSyntaxTemplate\n # The regex flags that change symbols between languages can be defined here.\n # Flags that aren't defined can be left blank and will be ignored.\n regexFlags: *RegexFlags\n bsonRegexFlags: *BSONRegexFlags\n driver: *DriverTemplate\nImports:\n import:\n template: *ImportTemplate\n driver:\n template: *DriverImportTemplate\n 0:\n template: *0ImportTemplate\n 1:\n template: *1ImportTemplate\n 2:\n template: *2ImportTemplate\n 3:\n template: *3ImportTemplate\n 4:\n template: *4ImportTemplate\n 5:\n template: *5ImportTemplate\n 6:\n template: *6ImportTemplate\n 7:\n template: *7ImportTemplate\n 8:\n template: *8ImportTemplate\n 9:\n template: *9ImportTemplate\n 10:\n template: *10ImportTemplate\n 11:\n template: *11ImportTemplate\n 12:\n template: *12ImportTemplate\n 100:\n template: *100ImportTemplate\n 101:\n template: *101ImportTemplate\n 102:\n template: *102ImportTemplate\n 103:\n template: *103ImportTemplate\n 104:\n template: *104ImportTemplate\n 105:\n template: *105ImportTemplate\n 106:\n template: *106ImportTemplate\n 107:\n template: *107ImportTemplate\n 108:\n template: *108ImportTemplate\n 109:\n template: *109ImportTemplate\n 110:\n template: *110ImportTemplate\n 111:\n template: *111ImportTemplate\n 112:\n template: *112ImportTemplate\n 113:\n template: *113ImportTemplate\n 114:\n template: *114ImportTemplate\n 200:\n template: *200ImportTemplate\n 201:\n template: *201ImportTemplate\n 300:\n template: *300ImportTemplate\n 301:\n template: *301ImportTemplate\n 302:\n template: *302ImportTemplate\n 303:\n template: *303ImportTemplate\n 304:\n template: *304ImportTemplate\n 305:\n template: *305ImportTemplate\n 306:\n template: *306ImportTemplate\nBsonTypes:\n Code: &CodeType\n <<: *__type\n id: \"Code\"\n code: 100\n type: *ObjectType\n attr:\n code:\n callable: *var\n args: null\n attr: null\n id: \"code\"\n type: *StringType\n template: *CodeCodeTemplate\n argsTemplate: *CodeCodeArgsTemplate\n scope:\n callable: *var\n args: null\n attr: null\n id: \"scope\"\n type: *StringType\n template: *CodeScopeTemplate\n argsTemplate: *CodeScopeArgsTemplate\n ObjectId: &ObjectIdType\n <<: *__type\n id: \"ObjectId\"\n code: 101\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *ObjectIdToStringTemplate\n argsTemplate: *ObjectIdToStringArgsTemplate\n equals:\n <<: *__func\n id: \"equals\"\n args:\n - [ \"ObjectId\" ]\n type: *BoolType\n template: *ObjectIdEqualsTemplate\n argsTemplate: *ObjectIdEqualsArgsTemplate\n getTimestamp:\n <<: *__func\n id: \"getTimestamp\"\n type: *IntegerType\n template: *ObjectIdGetTimestampTemplate\n argsTemplate: *ObjectIdGetTimestampArgsTemplate\n BinData: &BinaryType\n <<: *__type\n id: \"BinData\"\n code: 102\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *BinaryToStringTemplate\n argsTemplate: *BinaryToStringArgsTemplate\n base64:\n <<: *__func\n id: \"base64\"\n type: *StringType\n template: *BinaryValueTemplate\n argsTemplate: *BinaryValueArgsTemplate\n length:\n <<: *__func\n id: \"length\"\n type: *IntegerType\n template: *BinaryLengthTemplate\n argsTemplate: *BinaryLengthArgsTemplate\n subtype:\n <<: *__func\n id: \"subtype\"\n type: *IntegerType\n template: *BinarySubtypeTemplate\n argsTemplate: *BinarySubtypeArgsTemplate\n DBRef: &DBRefType\n <<: *__type\n id: \"DBRef\"\n code: 103\n type: *ObjectType\n attr:\n getDb:\n <<: *__func\n id: \"getDb\"\n type: *StringType\n template: *DBRefGetDBTemplate\n argsTemplate: *DBRefGetDBArgsTemplate\n $db:\n callable: *var\n args: null\n attr: null\n id: \"$db\"\n type: *StringType\n template: *DBRefGetDBTemplate\n argsTemplate: *DBRefGetDBArgsTemplate\n getCollection:\n <<: *__func\n id: \"getCollection\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n getRef:\n <<: *__func\n id: \"getRef\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n $ref:\n callable: *var\n args: null\n attr: null\n id: \"$ref\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n getId:\n <<: *__func\n id: \"getId\"\n type: *StringType\n template: *DBRefGetIdTemplate\n argsTemplate: *DBRefGetIdArgsTemplate\n $id:\n callable: *var\n args: null\n attr: null\n id: \"$id\"\n type: *StringType\n template: *DBRefGetIdTemplate\n argsTemplate: *DBRefGetIdArgsTemplate\n NumberInt: &Int32Type\n <<: *__type\n id: \"NumberInt\"\n code: 105\n type: *ObjectType\n attr: {}\n NumberLong: &LongType\n <<: *__type\n id: \"NumberLong\"\n code: 106\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"LongtoString\" # Needs process method\n type: *StringType\n top:\n callable: *var\n args: null\n attr: null\n id: \"top\"\n type: *IntegerType\n template: *LongTopTemplate\n argsTemplate: null\n bottom:\n callable: *var\n args: null\n attr: null\n id: \"bottom\"\n type: *IntegerType\n template: *LongBottomTemplate\n argsTemplate: null\n floatApprox:\n callable: *var\n args: null\n attr: null\n id: \"floatApprox\"\n type: *IntegerType\n template: *LongFloatApproxTemplate\n argsTemplate: null\n MinKeyType: &MinKeyType\n <<: *__type\n id: \"MinKey\"\n code: 107\n type: *ObjectType\n MaxKeyType: &MaxKeyType\n <<: *__type\n id: \"MaxKey\"\n code: 108\n type: *ObjectType\n Timestamp: &TimestampType\n <<: *__type\n id: \"TimestampFromShell\"\n code: 110\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *TimestampToStringTemplate\n argsTemplate: *TimestampToStringArgsTemplate\n getTime:\n <<: *__func\n id: \"getTime\"\n type: *IntegerType\n template: *TimestampGetLowBitsTemplate\n argsTemplate: *TimestampGetLowBitsArgsTemplate\n getInc:\n <<: *__func\n id: \"getInc\"\n type: *IntegerType\n template: *TimestampGetHighBitsTemplate\n argsTemplate: *TimestampGetHighBitsArgsTemplate\n t:\n callable: *var\n args: null\n attr: null\n id: \"getTime\"\n type: *IntegerType\n template: *TimestampTTemplate\n argsTemplate: null\n i:\n callable: *var\n args: null\n attr: null\n id: \"getInc\"\n type: *IntegerType\n template: *TimestampITemplate\n argsTemplate: null\n Symbol: &SymbolType\n <<: *__type\n id: \"Symbol\"\n code: 111\n type: *ObjectType\n NumberDecimal: &Decimal128Type\n <<: *__type\n id: \"NumberDecimal\"\n code: 112\n type: *ObjectType\n attr: {}\n SUBTYPE_DEFAULT:\n id: \"SUBTYPE_DEFAULT\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeDefaultTemplate\n SUBTYPE_FUNCTION:\n id: \"SUBTYPE_FUNCTION\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeFunctionTemplate\n SUBTYPE_BYTE_ARRAY:\n id: \"SUBTYPE_BYTE_ARRAY\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeByteArrayTemplate\n SUBTYPE_UUID_OLD:\n id: \"SUBTYPE_UUID_OLD\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUuidOldTemplate\n SUBTYPE_UUID:\n id: \"SUBTYPE_UUID\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUuidTemplate\n SUBTYPE_MD5:\n id: \"SUBTYPE_MD5\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeMd5Template\n SUBTYPE_USER_DEFINED:\n id: \"SUBTYPE_USER_DEFINED\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUserDefinedTemplate\nNativeTypes:\n Date: &DateType\n <<: *__type\n id: \"Date\"\n code: 200\n type: *ObjectType\n attr: {} # TODO: no built-in date methods added yet\n RegExp: &RegExpType\n <<: *__type\n id: \"RegExp\"\n code: 8\n type: *ObjectType\n attr: {}\n\n\n\n\nBsonSymbols:\n Code: &CodeSymbol\n id: \"Code\"\n code: 100\n callable: *constructor\n args:\n - [ *StringType, null ]\n - [ *ObjectType, null ]\n type: *CodeType\n attr: {}\n template: *CodeSymbolTemplate\n argsTemplate: *CodeSymbolArgsTemplate\n ObjectId: &ObjectIdSymbol\n id: \"ObjectId\"\n code: 101\n callable: *constructor\n args:\n - [ *StringType, null ]\n type: *ObjectIdType\n attr:\n fromDate:\n <<: *__func\n id: \"ObjectIdCreateFromTime\"\n args:\n - [ *DateType ]\n type: *ObjectIdType\n template: *ObjectIdCreateFromTimeTemplate\n argsTemplate: *ObjectIdCreateFromTimeArgsTemplate\n template: *ObjectIdSymbolTemplate\n argsTemplate: *ObjectIdSymbolArgsTemplate\n BinData: &BinarySymbol\n id: \"BinData\"\n code: 102\n callable: *constructor\n args:\n - [ *IntegerType ]\n - [ *StringType ]\n type: *BinaryType\n attr: {}\n template: *BinarySymbolTemplate\n argsTemplate: *BinarySymbolArgsTemplate\n DBRef:\n id: \"DBRef\"\n code: 103\n callable: *constructor\n args:\n - [ *StringType ]\n - [ *ObjectIdType ]\n - [ *StringType, null ]\n type: *DBRefType\n attr: {}\n template: *DBRefSymbolTemplate\n argsTemplate: *DBRefSymbolArgsTemplate\n NumberInt:\n id: \"Int32\"\n code: 105\n callable: *constructor\n args:\n - [ *NumericType, *StringType, null ]\n type: *Int32Type\n attr: {}\n template: *Int32SymbolTemplate\n argsTemplate: *Int32SymbolArgsTemplate\n NumberLong:\n id: \"NumberLong\"\n code: 106\n callable: *constructor\n args:\n - [ *IntegerType, *StringType, null ]\n type: *LongType\n attr: {}\n template: *LongSymbolTemplate\n argsTemplate: *LongSymbolArgsTemplate\n MinKey:\n id: \"MinKey\"\n code: 107\n callable: *constructor\n args: []\n type: *MinKeyType\n attr: {}\n template: *MinKeySymbolTemplate\n argsTemplate: *MinKeySymbolArgsTemplate\n MaxKey:\n id: \"MaxKey\"\n code: 108\n callable: *constructor\n args: []\n type: *MaxKeyType\n attr: {}\n template: *MaxKeySymbolTemplate\n argsTemplate: *MaxKeySymbolArgsTemplate\n Timestamp:\n id: \"Timestamp\"\n code: 110\n callable: *constructor\n args:\n - [ *IntegerType, null ]\n - [ *IntegerType, null ]\n type: *TimestampType\n attr: {}\n template: *TimestampSymbolTemplate\n argsTemplate: *TimestampSymbolArgsTemplate\n Symbol:\n id: \"Symbol\"\n code: 111\n callable: *constructor\n args:\n - [ *StringType ]\n type: *SymbolType\n attr: {}\n template: *SymbolSymbolTemplate\n argsTemplate: *SymbolSymbolArgsTemplate\n NumberDecimal:\n id: \"NumberDecimal\"\n code: 112\n callable: *constructor\n args:\n - [ *StringType, *NumericType, null ]\n type: *Decimal128Type\n attr: {}\n template: *Decimal128SymbolTemplate\n argsTemplate: *Decimal128SymbolArgsTemplate\n\nNativeSymbols:\n Number:\n id: \"Number\"\n code: 2\n callable: *constructor\n args:\n - [ *IntegerType, *StringType, null ]\n type: *NumericType\n attr: {} # TODO: no built-in number funcs added yet\n template: *NumberSymbolTemplate\n argsTemplate: *NumberSymbolArgsTemplate\n Date: # Needs emit method\n id: \"Date\"\n code: 200\n callable: *constructor\n args:\n - [ *StringType, *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n type: *DateType\n attr: # TODO: add more date funcs?\n now:\n id: \"now\"\n code: 200.1\n callable: *func\n args: []\n type: *DateType\n attr: {}\n template: *DateSymbolNowTemplate\n argsTemplate: *DateSymbolNowArgsTemplate\n template: *DateSymbolTemplate\n argsTemplate: *DateSymbolArgsTemplate\n ISODate: # Needs emit method\n id: \"ISODate\"\n code: 200\n callable: *constructor\n args:\n - [ *StringType, null ]\n type: *DateType\n attr:\n now:\n id: \"now\"\n callable: *constructor\n args: []\n type: *DateType\n attr: {}\n template: *DateSymbolNowTemplate\n argsTemplate: *DateSymbolNowArgsTemplate\n template: *DateSymbolTemplate\n argsTemplate: *DateSymbolArgsTemplate\n RegExp: # Needs process method\n id: \"RegExp\"\n code: 8\n callable: *constructor\n args:\n - [ *StringType, *RegexType ]\n - [ *StringType, null ]\n type: *RegExpType\n attr: {} # TODO: no built-in regex funcs added yet\n template: *RegExpSymbolTemplate\n argsTemplate: *RegExpSymbolArgsTemplate\n\n"; | ||
module.exports="SymbolTypes:\n VAR: &var 0\n CONSTRUCTOR: &constructor 1\n FUNC: &func 2\n# Internal patterns to save typing\n__type: &__type\n id: null\n callable: *var\n args: null\n type: null\n attr: {}\n template: null\n argsTemplate: null\n__func: &__func\n callable: *func\n args: []\n attr: {}\n template: null\n argsTemplate: null\n\n# Javascript Templates\nTemplates:\n # Misc\n RegexFlags: &RegexFlags\n i: 'i'\n m: 'm'\n u: 'u'\n y: 'y'\n g: 'g'\n BSONRegexFlags: &BSONRegexFlags\n i: 'i'\n m: 'm'\n x: 'x'\n s: 's'\n l: 'l'\n u: 'u'\n # Syntax\n DriverTemplate: &DriverTemplate !!js/function |\n (spec) => {\n const comment = `/*\n * Requires the MongoDB Node.js Driver\n * https://mongodb.github.io/node-mongodb-native\n */`;\n const translateKey = {\n project: 'projection'\n };\n\n const exportMode = spec.exportMode;\n delete spec.exportMode;\n\n const args = {};\n Object.keys(spec).forEach((k) => {\n if (k !== 'options') {\n args[k in translateKey ? translateKey[k] : k] = spec[k];\n }\n });\n\n let cmd;\n let defs;\n if (exportMode == 'Delete Query') {\n defs = `const filter = ${args.filter};\\n`;\n cmd = `const result = coll.deleteMany(filter);`;\n }\n if ('aggregation' in spec) {\n const agg = spec.aggregation;\n cmd = `const cursor = coll.aggregate(agg);\\nconst result = await cursor.toArray();`;\n defs = `const agg = ${agg};\\n`;\n } else if (!cmd) {\n let opts = '';\n\n if (Object.keys(args).length > 0) {\n defs = Object.keys(args).reduce((s, k) => {\n if (k !== 'filter') {\n if (opts === '') {\n opts = `${k}`;\n } else {\n opts = `${opts}, ${k}`;\n }\n }\n return `${s}const ${k} = ${args[k]};\\n`;\n }, '');\n opts = opts === '' ? '' : `, { ${opts} }`;\n }\n cmd = `const cursor = coll.find(filter${opts});\\nconst result = await cursor.toArray();`;\n }\n return `${comment}\\n\\n${defs}\n const client = await MongoClient.connect(\n '${spec.options.uri}'\n );\n const coll = client.db('${spec.options.database}').collection('${spec.options.collection}');\n ${cmd}\n await client.close();`;\n }\n EqualitySyntaxTemplate: &EqualitySyntaxTemplate !!js/function >\n (lhs, op, rhs) => {\n if (op.includes('!') || op.includes('not')) {\n return `${lhs} !== ${rhs}`;\n } else if (op === '==' || op === '===' || op === 'is') {\n return `${lhs} === ${rhs}`;\n }\n return `${lhs} ${op} ${rhs}`;\n }\n InSyntaxTemplate: &InSyntaxTemplate !!js/function >\n (lhs, op, rhs) => {\n let str = '!==';\n if (op.includes('!') || op.includes('not')) {\n str = '===';\n }\n return `${rhs}.indexOf(${lhs}) ${str} -1`\n }\n AndSyntaxTemplate: &AndSyntaxTemplate !!js/function >\n (args) => {\n return args.join(' && ');\n }\n OrSyntaxTemplate: &OrSyntaxTemplate !!js/function >\n (args) => {\n return args.join(' || ');\n }\n NotSyntaxTemplate: &NotSyntaxTemplate !!js/function >\n (arg) => {\n return `!${arg}`;\n }\n UnarySyntaxTemplate: &UnarySyntaxTemplate null\n BinarySyntaxTemplate: &BinarySyntaxTemplate !!js/function >\n (args) => {\n return args.reduce((s, op, i, arr) => {\n if (i % 2 === 0) {\n return s;\n }\n const rhs = arr[i + 1];\n switch(op) {\n case '//':\n return `Math.floor(${s}, ${rhs})`;\n case '**':\n return `Math.pow(${s}, ${rhs})`;\n default:\n return `${s} ${op} ${rhs}`;\n }\n }, args[0]);\n }\n ParensSyntaxTemplate: &ParensSyntaxTemplate null\n EosSyntaxTemplate: &EosSyntaxTemplate null\n EofSyntaxTemplate: &EofSyntaxTemplate null\n NewTemplate: &NewSyntaxTemplate !!js/function >\n (expr, skip, code) => {\n // Add classes that don't use \"new\" to array.\n // So far: [Date.now, Decimal128/NumberDecimal, Long/NumberLong]\n noNew = [200.1, 112, 106];\n if (skip || (code && noNew.indexOf(code) !== -1)) {\n return expr;\n }\n return `new ${expr}`;\n }\n # BSON Object Type templates\n CodeTypeTemplate: &CodeTypeTemplate null\n StringTypeTemplate: &StringTypeTemplate !!js/function >\n (str) => {\n let newStr = str;\n if (\n (str.charAt(0) === '\\'' && str.charAt(str.length - 1) === '\\'') ||\n (str.charAt(0) === '\"' && str.charAt(str.length - 1) === '\"')) {\n newStr = str.substr(1, str.length - 2);\n }\n return `'${newStr.replace(/\\\\([\\s\\S])|(')/g, '\\\\$1$2')}'`;\n }\n RegexTypeTemplate: &RegexTypeTemplate !!js/function >\n (pattern, flags) => {\n const str = pattern;\n let newStr = str;\n if (\n (str.charAt(0) === '\\'' && str.charAt(str.length - 1) === '\\'') ||\n (str.charAt(0) === '\"' && str.charAt(str.length - 1) === '\"')) {\n newStr = str.substr(1, str.length - 2);\n }\n pattern = `'${newStr.replace(/\\\\([\\s\\S])|(')/g, '\\\\$1$2')}'`;\n return `RegExp(${pattern}${flags ? ', ' + '\\'' + flags + '\\'': ''})`;\n }\n BoolTypeTemplate: &BoolTypeTemplate !!js/function >\n (literal) => {\n return literal.toLowerCase();\n }\n IntegerTypeTemplate: &IntegerTypeTemplate null\n DecimalTypeTemplate: &DecimalTypeTemplate null\n LongBasicTypeTemplate: &LongBasicTypeTemplate null\n HexTypeTemplate: &HexTypeTemplate null\n OctalTypeTemplate: &OctalTypeTemplate null\n NumericTypeTemplate: &NumericTypeTemplate null\n ArrayTypeTemplate: &ArrayTypeTemplate !!js/function >\n (literal, depth) => {\n depth++;\n if (literal === '') {\n return '[]'\n }\n const indent = '\\n' + ' '.repeat(depth);\n const closingIndent = '\\n' + ' '.repeat(depth - 1);\n\n return `[${indent}${literal}${closingIndent}]`;\n }\n ArrayTypeArgsTemplate: &ArrayTypeArgsTemplate null\n NullTypeTemplate: &NullTypeTemplate !!js/function >\n () => {\n return 'null';\n }\n UndefinedTypeTemplate: &UndefinedTypeTemplate !!js/function >\n () => {\n return 'undefined';\n }\n ObjectTypeTemplate: &ObjectTypeTemplate !!js/function >\n (literal) => {\n if (literal === '') {\n return '{}';\n }\n return literal;\n }\n ObjectTypeArgsTemplate: &ObjectTypeArgsTemplate !!js/function >\n (args, depth) => {\n if (args.length === 0) {\n return '{}';\n }\n depth++;\n const indent = '\\n' + ' '.repeat(depth);\n const closingIndent = '\\n' + ' '.repeat(depth - 1);\n const singleStringify = (str) => {\n let newStr = str;\n if (\n (str.charAt(0) === '\\'' && str.charAt(str.length - 1) === '\\'') ||\n (str.charAt(0) === '\"' && str.charAt(str.length - 1) === '\"')) {\n newStr = str.substr(1, str.length - 2);\n }\n return `'${newStr.replace(/\\\\([\\s\\S])|(')/g, '\\\\$1$2')}'`;\n }\n const pairs = args.map((arg) => {\n return `${indent}${singleStringify(arg[0])}: ${arg[1]}`;\n }).join(', ');\n\n return `{${pairs}${closingIndent}}`\n }\n # BSON Object Method templates\n CodeCodeTemplate: &CodeCodeTemplate null\n CodeCodeArgsTemplate: &CodeCodeArgsTemplate null\n CodeScopeTemplate: &CodeScopeTemplate null\n CodeScopeArgsTemplate: &CodeScopeArgsTemplate null\n ObjectIdToStringTemplate: &ObjectIdToStringTemplate null\n ObjectIdToStringArgsTemplate: &ObjectIdToStringArgsTemplate null\n ObjectIdEqualsTemplate: &ObjectIdEqualsTemplate null\n ObjectIdEqualsArgsTemplate: &ObjectIdEqualsArgsTemplate null\n ObjectIdGetTimestampTemplate: &ObjectIdGetTimestampTemplate null\n ObjectIdGetTimestampArgsTemplate: &ObjectIdGetTimestampArgsTemplate null\n BinaryValueTemplate: &BinaryValueTemplate null\n BinaryValueArgsTemplate: &BinaryValueArgsTemplate null\n BinaryLengthTemplate: &BinaryLengthTemplate null\n BinaryLengthArgsTemplate: &BinaryLengthArgsTemplate null\n BinaryToStringTemplate: &BinaryToStringTemplate null\n BinaryToStringArgsTemplate: &BinaryToStringArgsTemplate null\n BinarySubtypeTemplate: &BinarySubtypeTemplate !!js/function >\n (lhs) => {\n return `${lhs}.sub_type`;\n }\n BinarySubtypeArgsTemplate: &BinarySubtypeArgsTemplate !!js/function >\n () => {\n return '';\n }\n DBRefGetDBTemplate: &DBRefGetDBTemplate !!js/function >\n (lhs) => {\n return `${lhs}.db`;\n }\n DBRefGetCollectionTemplate: &DBRefGetCollectionTemplate !!js/function >\n (lhs) => {\n return `${lhs}.namespace`;\n }\n DBRefGetIdTemplate: &DBRefGetIdTemplate !!js/function >\n (lhs) => {\n return `${lhs}.oid`;\n }\n DBRefGetDBArgsTemplate: &DBRefGetDBArgsTemplate !!js/function >\n () => {\n return '';\n }\n DBRefGetCollectionArgsTemplate: &DBRefGetCollectionArgsTemplate !!js/function >\n () => {\n return '';\n }\n DBRefGetIdArgsTemplate: &DBRefGetIdArgsTemplate !!js/function >\n () => {\n return '';\n }\n LongEqualsTemplate: &LongEqualsTemplate null\n LongEqualsArgsTemplate: &LongEqualsArgsTemplate null\n LongToStringTemplate: &LongToStringTemplate null\n LongToStringArgsTemplate: &LongToStringArgsTemplate null\n LongToIntTemplate: &LongToIntTemplate !!js/function >\n (lhs) => {\n return `${lhs}.toInt`;\n }\n LongToIntArgsTemplate: &LongToIntArgsTemplate null\n LongToNumberTemplate: &LongToNumberTemplate null\n LongToNumberArgsTemplate: &LongToNumberArgsTemplate null\n LongAddTemplate: &LongAddTemplate null\n LongAddArgsTemplate: &LongAddArgsTemplate null\n LongSubtractTemplate: &LongSubtractTemplate null\n LongSubtractArgsTemplate: &LongSubtractArgsTemplate null\n LongMultiplyTemplate: &LongMultiplyTemplate null\n LongMultiplyArgsTemplate: &LongMultiplyArgsTemplate null\n LongDivTemplate: &LongDivTemplate null\n LongDivArgsTemplate: &LongDivArgsTemplate null\n LongModuloTemplate: &LongModuloTemplate null\n LongModuloArgsTemplate: &LongModuloArgsTemplate null\n LongAndTemplate: &LongAndTemplate null\n LongAndArgsTemplate: &LongAndArgsTemplate null\n LongOrTemplate: &LongOrTemplate null\n LongOrArgsTemplate: &LongOrArgsTemplate null\n LongXorTemplate: &LongXorTemplate null\n LongXorArgsTemplate: &LongXorArgsTemplate null\n LongShiftLeftTemplate: &LongShiftLeftTemplate null\n LongShiftLeftArgsTemplate: &LongShiftLeftArgsTemplate null\n LongShiftRightTemplate: &LongShiftRightTemplate null\n LongShiftRightArgsTemplate: &LongShiftRightArgsTemplate null\n LongCompareTemplate: &LongCompareTemplate null\n LongCompareArgsTemplate: &LongCompareArgsTemplate null\n LongIsOddTemplate: &LongIsOddTemplate null\n LongIsOddArgsTemplate: &LongIsOddArgsTemplate null\n LongIsZeroTemplate: &LongIsZeroTemplate null\n LongIsZeroArgsTemplate: &LongIsZeroArgsTemplate null\n LongIsNegativeTemplate: &LongIsNegativeTemplate null\n LongIsNegativeArgsTemplate: &LongIsNegativeArgsTemplate null\n LongNegateTemplate: &LongNegateTemplate null\n LongNegateArgsTemplate: &LongNegateArgsTemplate null\n LongNotTemplate: &LongNotTemplate null\n LongNotArgsTemplate: &LongNotArgsTemplate null\n LongNotEqualsTemplate: &LongNotEqualsTemplate null\n LongNotEqualsArgsTemplate: &LongNotEqualsArgsTemplate null\n LongGreaterThanTemplate: &LongGreaterThanTemplate null\n LongGreaterThanArgsTemplate: &LongGreaterThanArgsTemplate null\n LongGreaterThanOrEqualTemplate: &LongGreaterThanOrEqualTemplate null\n LongGreaterThanOrEqualArgsTemplate: &LongGreaterThanOrEqualArgsTemplate null\n LongLessThanTemplate: &LongLessThanTemplate null\n LongLessThanArgsTemplate: &LongLessThanArgsTemplate null\n LongLessThanOrEqualTemplate: &LongLessThanOrEqualTemplate null\n LongLessThanOrEqualArgsTemplate: &LongLessThanOrEqualArgsTemplate null\n LongFloatApproxTemplate: &LongFloatApproxTemplate !!js/function >\n (lhs) => {\n return `${lhs}.toNumber()`;\n }\n LongTopTemplate: &LongTopTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getHighBits()`;\n }\n LongBottomTemplate: &LongBottomTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getLowBits()`;\n }\n TimestampToStringTemplate: &TimestampToStringTemplate null\n TimestampToStringArgsTemplate: &TimestampToStringArgsTemplate null\n TimestampEqualsTemplate: &TimestampEqualsTemplate null\n TimestampEqualsArgsTemplate: &TimestampEqualsArgsTemplate null\n TimestampGetLowBitsTemplate: &TimestampGetLowBitsTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getLowBits`;\n }\n TimestampGetLowBitsArgsTemplate: &TimestampGetLowBitsArgsTemplate null\n TimestampGetHighBitsTemplate: &TimestampGetHighBitsTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getHighBits`;\n }\n TimestampGetHighBitsArgsTemplate: &TimestampGetHighBitsArgsTemplate null\n TimestampTTemplate: &TimestampTTemplate !!js/function >\n (lhs) => {\n return `${lhs}.getLowBits()`;\n }\n TimestampITemplate: &TimestampITemplate !!js/function >\n (lhs) => {\n return `${lhs}.getHighBits()`;\n }\n TimestampAsDateTemplate: &TimestampAsDateTemplate !!js/function >\n (lhs) => {\n return `new Date(${lhs}.getHighBits() * 1000)`;\n }\n TimestampAsDateArgsTemplate: &TimestampAsDateArgsTemplate !!js/function >\n () => {\n return '';\n }\n TimestampCompareTemplate: &TimestampCompareTemplate null\n TimestampCompareArgsTemplate: &TimestampCompareArgsTemplate null\n TimestampNotEqualsTemplate: &TimestampNotEqualsTemplate null\n TimestampNotEqualsArgsTemplate: &TimestampNotEqualsArgsTemplate null\n TimestampGreaterThanTemplate: &TimestampGreaterThanTemplate null\n TimestampGreaterThanArgsTemplate: &TimestampGreaterThanArgsTemplate null\n TimestampGreaterThanOrEqualTemplate: &TimestampGreaterThanOrEqualTemplate null\n TimestampGreaterThanOrEqualArgsTemplate: &TimestampGreaterThanOrEqualArgsTemplate null\n TimestampLessThanTemplate: &TimestampLessThanTemplate null\n TimestampLessThanArgsTemplate: &TimestampLessThanArgsTemplate null\n TimestampLessThanOrEqualTemplate: &TimestampLessThanOrEqualTemplate null\n TimestampLessThanOrEqualArgsTemplate: &TimestampLessThanOrEqualArgsTemplate null\n SymbolValueOfTemplate: &SymbolValueOfTemplate null\n SymbolValueOfArgsTemplate: &SymbolValueOfArgsTemplate null\n SymbolInspectTemplate: &SymbolInspectTemplate null\n SymbolInspectArgsTemplate: &SymbolInspectArgsTemplate null\n SymbolToStringTemplate: &SymbolToStringTemplate null\n SymbolToStringArgsTemplate: &SymbolToStringArgsTemplate null\n # Symbol Templates\n CodeSymbolTemplate: &CodeSymbolTemplate null\n CodeSymbolArgsTemplate: &CodeSymbolArgsTemplate !!js/function >\n (lhs, code, scope) => {\n code = code === undefined ? '\\'\\'' : code;\n scope = scope === undefined ? '' : `, ${scope}`;\n return `(${code}${scope})`;\n }\n ObjectIdSymbolTemplate: &ObjectIdSymbolTemplate null\n ObjectIdSymbolArgsTemplate: &ObjectIdSymbolArgsTemplate !!js/function >\n (lhs, str) => {\n if (!str || str.length === 0) {\n return '()';\n }\n let newStr = str;\n if (\n (str.charAt(0) === '\\'' && str.charAt(str.length - 1) === '\\'') ||\n (str.charAt(0) === '\"' && str.charAt(str.length - 1) === '\"')) {\n newStr = str.substr(1, str.length - 2);\n }\n return `('${newStr.replace(/\\\\([\\s\\S])|(\")/g, '\\\\$1$2')}')`;\n }\n BinarySymbolTemplate: &BinarySymbolTemplate !!js/function >\n () => {\n return 'Binary';\n }\n BinarySymbolArgsTemplate: &BinarySymbolArgsTemplate !!js/function >\n (lhs, buffer, subtype) => {\n return `(${buffer.toString('base64')}, '${subtype}')`;\n }\n BinarySymbolSubtypeDefaultTemplate: &BinarySymbolSubtypeDefaultTemplate null\n BinarySymbolSubtypeFunctionTemplate: &BinarySymbolSubtypeFunctionTemplate null\n BinarySymbolSubtypeByteArrayTemplate: &BinarySymbolSubtypeByteArrayTemplate null\n BinarySymbolSubtypeUuidOldTemplate: &BinarySymbolSubtypeUuidOldTemplate null\n BinarySymbolSubtypeUuidTemplate: &BinarySymbolSubtypeUuidTemplate null\n BinarySymbolSubtypeMd5Template: &BinarySymbolSubtypeMd5Template null\n BinarySymbolSubtypeUserDefinedTemplate: &BinarySymbolSubtypeUserDefinedTemplate null\n DBRefSymbolTemplate: &DBRefSymbolTemplate null\n DBRefSymbolArgsTemplate: &DBRefSymbolArgsTemplate null\n DoubleSymbolTemplate: &DoubleSymbolTemplate !!js/function >\n () => {\n return 'Double';\n }\n DoubleSymbolArgsTemplate: &DoubleSymbolArgsTemplate null\n Int32SymbolTemplate: &Int32SymbolTemplate !!js/function >\n () => {\n return 'Int32';\n }\n Int32SymbolArgsTemplate: &Int32SymbolArgsTemplate !!js/function >\n (lhs, arg) => {\n arg = arg === undefined ? 0 : arg;\n return `(${arg})`;\n }\n LongSymbolTemplate: &LongSymbolTemplate !!js/function >\n () => {\n return '';\n }\n LongSymbolArgsTemplate: &LongSymbolArgsTemplate !!js/function >\n (lhs, arg, type) => {\n arg = arg === undefined ? 0 : arg;\n if (type === '_string') {\n return `Long.fromString(${arg})`;\n }\n return `Long.fromNumber(${arg})`;\n }\n LongSymbolMaxTemplate: &LongSymbolMaxTemplate null\n LongSymbolMaxArgsTemplate: &LongSymbolMaxArgsTemplate null\n LongSymbolMinTemplate: &LongSymbolMinTemplate null\n LongSymbolMinArgsTemplate: &LongSymbolMinArgsTemplate null\n LongSymbolZeroTemplate: &LongSymbolZeroTemplate null\n LongSymbolZeroArgsTemplate: &LongSymbolZeroArgsTemplate null\n LongSymbolOneTemplate: &LongSymbolOneTemplate null\n LongSymbolOneArgsTemplate: &LongSymbolOneArgsTemplate null\n LongSymbolNegOneTemplate: &LongSymbolNegOneTemplate null\n LongSymbolNegOneArgsTemplate: &LongSymbolNegOneArgsTemplate null\n LongSymbolFromBitsTemplate: &LongSymbolFromBitsTemplate null\n LongSymbolFromBitsArgsTemplate: &LongSymbolFromBitsArgsTemplate null\n LongSymbolFromIntTemplate: &LongSymbolFromIntTemplate null\n LongSymbolFromIntArgsTemplate: &LongSymbolFromIntArgsTemplate null\n LongSymbolFromNumberTemplate: &LongSymbolFromNumberTemplate null\n LongSymbolFromNumberArgsTemplate: &LongSymbolFromNumberArgsTemplate null\n LongSymbolFromStringTemplate: &LongSymbolFromStringTemplate null\n LongSymbolFromStringArgsTemplate: &LongSymbolFromStringArgsTemplate null\n MinKeySymbolTemplate: &MinKeySymbolTemplate null\n MinKeySymbolArgsTemplate: &MinKeySymbolArgsTemplate null\n MaxKeySymbolTemplate: &MaxKeySymbolTemplate null\n MaxKeySymbolArgsTemplate: &MaxKeySymbolArgsTemplate null\n TimestampSymbolTemplate: &TimestampSymbolTemplate null\n TimestampSymbolArgsTemplate: &TimestampSymbolArgsTemplate !!js/function >\n (lhs, arg1, arg2) => {\n return `(${arg1 === undefined ? 0 : arg1}, ${arg2 === undefined ? 0 : arg2})`;\n }\n SymbolSymbolTemplate: &SymbolSymbolTemplate !!js/function >\n () => {\n return 'BSONSymbol';\n }\n SymbolSymbolArgsTemplate: &SymbolSymbolArgsTemplate null\n BSONRegExpSymbolTemplate: &BSONRegExpSymbolTemplate !!js/function >\n () => {\n return 'BSONRegExp';\n }\n BSONRegExpSymbolArgsTemplate: &BSONRegExpSymbolArgsTemplate !!js/function >\n (lhs, pattern, flags) => {\n const singleStringify = (str) => {\n let newStr = str;\n if (\n (str.charAt(0) === '\\'' && str.charAt(str.length - 1) === '\\'') ||\n (str.charAt(0) === '\"' && str.charAt(str.length - 1) === '\"')) {\n newStr = str.substr(1, str.length - 2);\n }\n return `'${newStr.replace(/\\\\([\\s\\S])|(\")/g, '\\\\$1$2')}'`;\n }\n return `(${singleStringify(pattern)}${flags ? ', ' + singleStringify(flags) : ''})`;\n }\n Decimal128SymbolTemplate: &Decimal128SymbolTemplate !!js/function >\n () => {\n return 'Decimal128';\n }\n Decimal128SymbolArgsTemplate: &Decimal128SymbolArgsTemplate !!js/function >\n (lhs, arg) => {\n arg = arg === undefined ? '0' : arg.toString();\n if (arg.charAt(0) === '\\'' && arg.charAt(arg.length - 1) === '\\'') {\n return `.fromString(${arg})`;\n }\n return `.fromString('${arg}')`;\n }\n Decimal128SymbolFromStringTemplate: &Decimal128SymbolFromStringTemplate null\n Decimal128SymbolFromStringArgsTemplate: &Decimal128SymbolFromStringArgsTemplate null\n Decimal128ToStringTemplate: &Decimal128ToStringTemplate null\n Decimal128ToStringArgsTemplate: &Decimal128ToStringArgsTemplate null\n # BSON Util Templates\n ObjectIdCreateFromHexStringTemplate: &ObjectIdCreateFromHexStringTemplate null\n ObjectIdCreateFromHexStringArgsTemplate: &ObjectIdCreateFromHexStringArgsTemplate null\n ObjectIdCreateFromTimeTemplate: &ObjectIdCreateFromTimeTemplate !!js/function >\n () => {\n return `ObjectId.createFromTime`;\n }\n ObjectIdCreateFromTimeArgsTemplate: &ObjectIdCreateFromTimeArgsTemplate !!js/function >\n (lhs, arg, isNumber) => {\n if (!isNumber) {\n return `(${arg}.getTime() / 1000)`;\n }\n return `(${arg})`;\n }\n ObjectIdIsValidTemplate: &ObjectIdIsValidTemplate !!js/function >\n (lhs) => {\n return `${lhs}.isValid`;\n }\n ObjectIdIsValidArgsTemplate: &ObjectIdIsValidArgsTemplate null\n # JS Symbol Templates\n NumberSymbolTemplate: &NumberSymbolTemplate !!js/function >\n () => {\n return 'Number';\n }\n NumberSymbolArgsTemplate: &NumberSymbolArgsTemplate !!js/function >\n (lhs, arg) => {\n arg = arg === undefined ? '0' : arg;\n return `(${arg})`;\n }\n DateSymbolTemplate: &DateSymbolTemplate !!js/function >\n () => {\n return 'Date';\n }\n DateSymbolArgsTemplate: &DateSymbolArgsTemplate null\n DateSymbolNowTemplate: &DateSymbolNowTemplate !!js/function >\n () => {\n return 'Date.now';\n }\n DateSymbolNowArgsTemplate: &DateSymbolNowArgsTemplate null\n RegExpSymbolTemplate: &RegExpSymbolTemplate !!js/function >\n () => {\n return 'RegExp';\n }\n RegExpSymbolArgsTemplate: &RegExpSymbolArgsTemplate null\n ImportTemplate: &ImportTemplate !!js/function >\n (args) => {\n const bson = [];\n const other = [];\n Object.keys(args).map(\n (m) => {\n if (m > 99 && m < 200) {\n bson.push(args[m]);\n } else {\n other.push(args[m]);\n }\n }\n );\n if (bson.length) {\n other.push(`import {\\n ${bson.join(',\\n ')}\\n} from 'mongodb';`);\n }\n return other.join('\\n');\n }\n DriverImportTemplate: &DriverImportTemplate !!js/function >\n () => {\n return `import { MongoClient } from 'mongodb';`;\n }\n 0ImportTemplate: &0ImportTemplate null\n 1ImportTemplate: &1ImportTemplate null\n 2ImportTemplate: &2ImportTemplate null\n 3ImportTemplate: &3ImportTemplate null\n 4ImportTemplate: &4ImportTemplate null\n 5ImportTemplate: &5ImportTemplate null\n 6ImportTemplate: &6ImportTemplate null\n 7ImportTemplate: &7ImportTemplate null\n 8ImportTemplate: &8ImportTemplate null\n 9ImportTemplate: &9ImportTemplate null\n 10ImportTemplate: &10ImportTemplate null\n 11ImportTemplate: &11ImportTemplate null\n 12ImportTemplate: &12ImportTemplate null\n 100ImportTemplate: &100ImportTemplate !!js/function >\n () => {\n return 'Code';\n }\n 101ImportTemplate: &101ImportTemplate !!js/function >\n () => {\n return 'ObjectId';\n }\n 102ImportTemplate: &102ImportTemplate !!js/function >\n () => {\n return 'Binary';\n }\n 103ImportTemplate: &103ImportTemplate !!js/function >\n () => {\n return 'DBRef';\n }\n 104ImportTemplate: &104ImportTemplate !!js/function >\n () => {\n return 'Double';\n }\n 105ImportTemplate: &105ImportTemplate !!js/function >\n () => {\n return 'Int32';\n }\n 106ImportTemplate: &106ImportTemplate !!js/function >\n () => {\n return 'Long';\n }\n 107ImportTemplate: &107ImportTemplate !!js/function >\n () => {\n return 'MinKey';\n }\n 108ImportTemplate: &108ImportTemplate !!js/function >\n () => {\n return 'MaxKey';\n }\n 109ImportTemplate: &109ImportTemplate !!js/function >\n () => {\n return 'BSONRegExp';\n }\n 110ImportTemplate: &110ImportTemplate !!js/function >\n () => {\n return 'Timestamp';\n }\n 111ImportTemplate: &111ImportTemplate !!js/function >\n () => {\n return 'BSONSymbol';\n }\n 112ImportTemplate: &112ImportTemplate !!js/function >\n () => {\n return 'Decimal128';\n }\n 113ImportTemplate: &113ImportTemplate null\n 114ImportTemplate: &114ImportTemplate null\n 200ImportTemplate: &200ImportTemplate null\n 201ImportTemplate: &201ImportTemplate null\n 300ImportTemplate: &300ImportTemplate null\n 301ImportTemplate: &301ImportTemplate null\n 302ImportTemplate: &302ImportTemplate null\n 303ImportTemplate: &303ImportTemplate null\n 304ImportTemplate: &304ImportTemplate null\n 305ImportTemplate: &305ImportTemplate null\n 306ImportTemplate: &306ImportTemplate null\n# Universal types\n# Everything inherits from StringType because we haven't implemented any of them.\nBasicTypes:\n # Universal basic types\n _bool: &BoolType\n <<: *__type\n id: \"_bool\"\n code: 0\n template: *BoolTypeTemplate\n _integer: &IntegerType\n <<: *__type\n id: \"_integer\"\n code: 1\n template: *IntegerTypeTemplate\n _long: &LongBasicType\n <<: *__type\n id: \"_long\"\n code: 2\n template: *LongBasicTypeTemplate\n _decimal: &DecimalType\n <<: *__type\n id: \"_decimal\"\n code: 3\n template: *DecimalTypeTemplate\n _hex: &HexType\n <<: *__type\n id: \"_hex\"\n code: 4\n template: *HexTypeTemplate\n _octal: &OctalType\n <<: *__type\n id: \"_octal\"\n code: 5\n template: *OctalTypeTemplate\n _numeric: &NumericType\n <<: *__type\n id: \"_numeric\"\n code: 6\n template: *NumericTypeTemplate\n _string: &StringType\n <<: *__type\n id: \"_string\"\n code: 7\n template: *StringTypeTemplate\n _regex: &RegexType\n <<: *__type\n id: \"_regex\"\n code: 8\n template: *RegexTypeTemplate\n _array: &ArrayType\n <<: *__type\n id: \"_array\"\n code: 9\n template: *ArrayTypeTemplate\n argsTemplate: *ArrayTypeArgsTemplate\n _object: &ObjectType\n <<: *__type\n id: \"_object\"\n code: 10\n template: *ObjectTypeTemplate\n argsTemplate: *ObjectTypeArgsTemplate\n _null: &NullType\n <<: *__type\n id: \"_null\"\n code: 11\n template: *NullTypeTemplate\n _undefined: &UndefinedType\n <<: *__type\n id: \"_undefined\"\n code: 12\n template: *UndefinedTypeTemplate\n\nSyntax:\n equality:\n template: *EqualitySyntaxTemplate\n in:\n template: *InSyntaxTemplate\n and:\n template: *AndSyntaxTemplate\n or:\n template: *OrSyntaxTemplate\n not:\n template: *NotSyntaxTemplate\n unary:\n template: *UnarySyntaxTemplate\n binary:\n template: *BinarySyntaxTemplate\n parens:\n template: *ParensSyntaxTemplate\n eos:\n template: *EosSyntaxTemplate\n eof:\n template: *EofSyntaxTemplate\n # The new template takes in expr, and an optional skip argument and optional\n # id argument. The skip argument is a boolean that if true then doesn't add\n # new. The code argument is the symbol code being called. The template will check\n # if it is an exception, i.e. a type that is a constructor but may not use new.\n new:\n template: *NewSyntaxTemplate\n # The regex flags that change symbols between languages can be defined here.\n # Flags that aren't defined can be left blank and will be ignored.\n regexFlags: *RegexFlags\n bsonRegexFlags: *BSONRegexFlags\n driver: *DriverTemplate\nImports:\n import:\n template: *ImportTemplate\n driver:\n template: *DriverImportTemplate\n 0:\n template: *0ImportTemplate\n 1:\n template: *1ImportTemplate\n 2:\n template: *2ImportTemplate\n 3:\n template: *3ImportTemplate\n 4:\n template: *4ImportTemplate\n 5:\n template: *5ImportTemplate\n 6:\n template: *6ImportTemplate\n 7:\n template: *7ImportTemplate\n 8:\n template: *8ImportTemplate\n 9:\n template: *9ImportTemplate\n 10:\n template: *10ImportTemplate\n 11:\n template: *11ImportTemplate\n 12:\n template: *12ImportTemplate\n 100:\n template: *100ImportTemplate\n 101:\n template: *101ImportTemplate\n 102:\n template: *102ImportTemplate\n 103:\n template: *103ImportTemplate\n 104:\n template: *104ImportTemplate\n 105:\n template: *105ImportTemplate\n 106:\n template: *106ImportTemplate\n 107:\n template: *107ImportTemplate\n 108:\n template: *108ImportTemplate\n 109:\n template: *109ImportTemplate\n 110:\n template: *110ImportTemplate\n 111:\n template: *111ImportTemplate\n 112:\n template: *112ImportTemplate\n 113:\n template: *113ImportTemplate\n 114:\n template: *114ImportTemplate\n 200:\n template: *200ImportTemplate\n 201:\n template: *201ImportTemplate\n 300:\n template: *300ImportTemplate\n 301:\n template: *301ImportTemplate\n 302:\n template: *302ImportTemplate\n 303:\n template: *303ImportTemplate\n 304:\n template: *304ImportTemplate\n 305:\n template: *305ImportTemplate\n 306:\n template: *306ImportTemplate\nBsonTypes:\n Code: &CodeType\n <<: *__type\n id: \"Code\"\n code: 100\n type: *ObjectType\n attr:\n code:\n callable: *var\n args: null\n attr: null\n id: \"code\"\n type: *StringType\n template: *CodeCodeTemplate\n argsTemplate: *CodeCodeArgsTemplate\n scope:\n callable: *var\n args: null\n attr: null\n id: \"scope\"\n type: *StringType\n template: *CodeScopeTemplate\n argsTemplate: *CodeScopeArgsTemplate\n ObjectId: &ObjectIdType\n <<: *__type\n id: \"ObjectId\"\n code: 101\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *ObjectIdToStringTemplate\n argsTemplate: *ObjectIdToStringArgsTemplate\n equals:\n <<: *__func\n id: \"equals\"\n args:\n - [ \"ObjectId\" ]\n type: *BoolType\n template: *ObjectIdEqualsTemplate\n argsTemplate: *ObjectIdEqualsArgsTemplate\n getTimestamp:\n <<: *__func\n id: \"getTimestamp\"\n type: *IntegerType\n template: *ObjectIdGetTimestampTemplate\n argsTemplate: *ObjectIdGetTimestampArgsTemplate\n BinData: &BinaryType\n <<: *__type\n id: \"BinData\"\n code: 102\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *BinaryToStringTemplate\n argsTemplate: *BinaryToStringArgsTemplate\n base64:\n <<: *__func\n id: \"base64\"\n type: *StringType\n template: *BinaryValueTemplate\n argsTemplate: *BinaryValueArgsTemplate\n length:\n <<: *__func\n id: \"length\"\n type: *IntegerType\n template: *BinaryLengthTemplate\n argsTemplate: *BinaryLengthArgsTemplate\n subtype:\n <<: *__func\n id: \"subtype\"\n type: *IntegerType\n template: *BinarySubtypeTemplate\n argsTemplate: *BinarySubtypeArgsTemplate\n DBRef: &DBRefType\n <<: *__type\n id: \"DBRef\"\n code: 103\n type: *ObjectType\n attr:\n getDb:\n <<: *__func\n id: \"getDb\"\n type: *StringType\n template: *DBRefGetDBTemplate\n argsTemplate: *DBRefGetDBArgsTemplate\n $db:\n callable: *var\n args: null\n attr: null\n id: \"$db\"\n type: *StringType\n template: *DBRefGetDBTemplate\n argsTemplate: *DBRefGetDBArgsTemplate\n getCollection:\n <<: *__func\n id: \"getCollection\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n getRef:\n <<: *__func\n id: \"getRef\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n $ref:\n callable: *var\n args: null\n attr: null\n id: \"$ref\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n getId:\n <<: *__func\n id: \"getId\"\n type: *StringType\n template: *DBRefGetIdTemplate\n argsTemplate: *DBRefGetIdArgsTemplate\n $id:\n callable: *var\n args: null\n attr: null\n id: \"$id\"\n type: *StringType\n template: *DBRefGetIdTemplate\n argsTemplate: *DBRefGetIdArgsTemplate\n NumberInt: &Int32Type\n <<: *__type\n id: \"NumberInt\"\n code: 105\n type: *ObjectType\n attr: {}\n NumberLong: &LongType\n <<: *__type\n id: \"NumberLong\"\n code: 106\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"LongtoString\" # Needs process method\n args:\n - [ *IntegerType, null ]\n type: *StringType\n template: *LongToStringTemplate\n argsTemplate: *LongToStringArgsTemplate\n equals:\n <<: *__func\n id: \"equals\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongEqualsTemplate\n argsTemplate: *LongEqualsArgsTemplate\n toInt:\n <<: *__func\n id: \"toInt\"\n type: *IntegerType\n template: *LongToIntTemplate\n argsTemplate: *LongToIntArgsTemplate\n toNumber:\n <<: *__func\n id: \"toNumber\"\n type: *DecimalType\n template: *LongToNumberTemplate\n argsTemplate: *LongToNumberArgsTemplate\n compare:\n <<: *__func\n id: \"compare\"\n args:\n - [ \"Long\" ]\n type: *StringType\n template: *LongCompareTemplate\n argsTemplate: *LongCompareArgsTemplate\n isOdd:\n <<: *__func\n id: \"isOdd\"\n type: *BoolType\n template: *LongIsOddTemplate\n argsTemplate: *LongIsOddArgsTemplate\n isZero:\n <<: *__func\n id: \"isZero\"\n type: *BoolType\n template: *LongIsZeroTemplate\n argsTemplate: *LongIsZeroArgsTemplate\n isNegative:\n <<: *__func\n id: \"isNegative\"\n type: *BoolType\n template: *LongIsNegativeTemplate\n argsTemplate: *LongIsNegativeArgsTemplate\n negate:\n <<: *__func\n id: \"negate\"\n type: \"Long\"\n template: *LongNegateTemplate\n argsTemplate: *LongNegateArgsTemplate\n not:\n <<: *__func\n id: \"not\"\n type: \"Long\"\n template: *LongNotTemplate\n argsTemplate: *LongNotArgsTemplate\n notEquals:\n <<: *__func\n id: \"notEquals\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongNotEqualsTemplate\n argsTemplate: *LongNotEqualsArgsTemplate\n greaterThan:\n <<: *__func\n id: \"greaterThan\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongGreaterThanTemplate\n argsTemplate: *LongGreaterThanArgsTemplate\n greaterThanOrEqual:\n <<: *__func\n id: \"greaterThanOrEqual\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongGreaterThanOrEqualTemplate\n argsTemplate: *LongGreaterThanOrEqualArgsTemplate\n lessThan:\n <<: *__func\n id: \"lessThan\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongLessThanTemplate\n argsTemplate: *LongLessThanArgsTemplate\n lessThanOrEqual:\n <<: *__func\n id: \"lessThanOrEqual\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongLessThanOrEqualTemplate\n argsTemplate: *LongLessThanOrEqualArgsTemplate\n add:\n <<: *__func\n id: \"add\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongAddTemplate\n argsTemplate: *LongAddArgsTemplate\n subtract:\n <<: *__func\n id: \"subtract\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongSubtractTemplate\n argsTemplate: *LongSubtractArgsTemplate\n multiply:\n <<: *__func\n id: \"multiply\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongMultiplyTemplate\n argsTemplate: *LongMultiplyArgsTemplate\n div:\n <<: *__func\n id: \"div\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongDivTemplate\n argsTemplate: *LongDivArgsTemplate\n modulo:\n <<: *__func\n id: \"modulo\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongModuloTemplate\n argsTemplate: *LongModuloArgsTemplate\n and:\n <<: *__func\n id: \"and\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongAndTemplate\n argsTemplate: *LongAndArgsTemplate\n or:\n <<: *__func\n id: \"or\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongOrTemplate\n argsTemplate: *LongOrArgsTemplate\n xor:\n <<: *__func\n id: \"xor\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongXorTemplate\n argsTemplate: *LongXorArgsTemplate\n shiftLeft:\n <<: *__func\n id: \"shiftLeft\"\n args:\n - [ *IntegerType ]\n type: \"Long\"\n template: *LongShiftLeftTemplate\n argsTemplate: *LongShiftLeftArgsTemplate\n shiftRight:\n <<: *__func\n id: \"shiftRight\"\n args:\n - [ *IntegerType ]\n type: \"Long\"\n template: *LongShiftRightTemplate\n argsTemplate: *LongShiftRightArgsTemplate\n MinKeyType: &MinKeyType\n <<: *__type\n id: \"MinKey\"\n code: 107\n type: *ObjectType\n MaxKeyType: &MaxKeyType\n <<: *__type\n id: \"MaxKey\"\n code: 108\n type: *ObjectType\n Timestamp: &TimestampType\n <<: *__type\n id: \"Timestamp\"\n code: 110\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *TimestampToStringTemplate\n argsTemplate: *TimestampToStringArgsTemplate\n equals:\n <<: *__func\n id: \"equals\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampEqualsTemplate\n argsTemplate: *TimestampEqualsArgsTemplate\n getLowBits:\n <<: *__func\n id: \"getLowBits\"\n type: *IntegerType\n template: *TimestampGetLowBitsTemplate\n argsTemplate: *TimestampGetLowBitsArgsTemplate\n getHighBits:\n <<: *__func\n id: \"getHighBits\"\n type: *IntegerType\n template: *TimestampGetHighBitsTemplate\n argsTemplate: *TimestampGetHighBitsArgsTemplate\n compare:\n <<: *__func\n id: \"compare\"\n args:\n - [ \"Timestamp\" ]\n type: *StringType\n template: *TimestampCompareTemplate\n argsTemplate: *TimestampCompareArgsTemplate\n notEquals:\n <<: *__func\n id: \"notEquals\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampNotEqualsTemplate\n argsTemplate: *TimestampNotEqualsArgsTemplate\n greaterThan:\n <<: *__func\n id: \"greaterThan\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampGreaterThanTemplate\n argsTemplate: *TimestampGreaterThanArgsTemplate\n greaterThanOrEqual:\n <<: *__func\n id: \"greaterThanOrEqual\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampGreaterThanOrEqualTemplate\n argsTemplate: *TimestampGreaterThanOrEqualArgsTemplate\n lessThan:\n <<: *__func\n id: \"lessThan\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampLessThanTemplate\n argsTemplate: *TimestampLessThanArgsTemplate\n lessThanOrEqual:\n <<: *__func\n id: \"lessThanOrEqual\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampLessThanOrEqualTemplate\n argsTemplate: *TimestampLessThanOrEqualArgsTemplate\n BSONSymbol: &SymbolType\n <<: *__type\n id: \"BSONSymbol\"\n code: 111\n type: *ObjectType\n attr:\n valueOf:\n <<: *__func\n id: \"valueOf\"\n type: *StringType\n template: *SymbolValueOfTemplate\n argsTemplate: *SymbolValueOfArgsTemplate\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *SymbolToStringTemplate\n argsTemplate: *SymbolToStringArgsTemplate\n inspect:\n <<: *__func\n id: \"inspect\"\n type: *StringType\n template: *SymbolInspectTemplate\n argsTemplate: *SymbolInspectArgsTemplate\n Double: &DoubleType\n <<: *__type\n id: \"Double\"\n code: 104\n type: *ObjectType\n attr: {}\n Decimal128: &Decimal128Type\n <<: *__type\n id: \"Decimal128\"\n code: 112\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *Decimal128ToStringTemplate\n argsTemplate: *Decimal128ToStringArgsTemplate\n NumberDecimal: &NumberDecimalType\n <<: *__type\n id: \"NumberDecimal\"\n code: 112\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *Decimal128ToStringTemplate\n argsTemplate: *Decimal128ToStringArgsTemplate\n\n\n SUBTYPE_DEFAULT:\n id: \"SUBTYPE_DEFAULT\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeDefaultTemplate\n SUBTYPE_FUNCTION:\n id: \"SUBTYPE_FUNCTION\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeFunctionTemplate\n SUBTYPE_BYTE_ARRAY:\n id: \"SUBTYPE_BYTE_ARRAY\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeByteArrayTemplate\n SUBTYPE_UUID_OLD:\n id: \"SUBTYPE_UUID_OLD\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUuidOldTemplate\n SUBTYPE_UUID:\n id: \"SUBTYPE_UUID\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUuidTemplate\n SUBTYPE_MD5:\n id: \"SUBTYPE_MD5\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeMd5Template\n SUBTYPE_USER_DEFINED:\n id: \"SUBTYPE_USER_DEFINED\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUserDefinedTemplate\n BSONRegExpType: &BSONRegExpType\n <<: *__type\n id: \"BSONRegExp\"\n code: 109\n type: *ObjectType\nNativeTypes:\n Date: &DateType\n <<: *__type\n id: \"Date\"\n code: 200\n type: *ObjectType\n attr: {} # TODO: no built-in date methods added yet\n RegExp: &RegExpType\n <<: *__type\n id: \"RegExp\"\n code: 8\n type: *ObjectType\n attr: {}\n\n\nBsonSymbols:\n Code: &CodeSymbol\n id: \"Code\"\n code: 100\n callable: *constructor\n args:\n - [ *StringType, null ]\n - [ *ObjectType, null ]\n type: *CodeType\n attr: {}\n template: *CodeSymbolTemplate\n argsTemplate: *CodeSymbolArgsTemplate\n ObjectId: &ObjectIdSymbol\n id: \"ObjectId\"\n code: 101\n callable: *constructor\n args:\n - [ *StringType, *NumericType, null ]\n type: *ObjectIdType\n attr:\n createFromHexString:\n <<: *__func\n id: \"createFromHexString\"\n args:\n - [ *StringType ]\n type: *ObjectIdType\n template: *ObjectIdCreateFromHexStringTemplate\n argsTemplate: *ObjectIdCreateFromHexStringArgsTemplate\n createFromTime:\n <<: *__func\n id: \"ObjectIdCreateFromTime\"\n args:\n - [ *NumericType, *DateType ]\n type: *ObjectIdType\n template: *ObjectIdCreateFromTimeTemplate\n argsTemplate: *ObjectIdCreateFromTimeArgsTemplate\n isValid:\n <<: *__func\n id: \"isValid\"\n args:\n - [ *StringType ]\n type: *BoolType\n template: *ObjectIdIsValidTemplate\n argsTemplate: *ObjectIdIsValidArgsTemplate\n template: *ObjectIdSymbolTemplate\n argsTemplate: *ObjectIdSymbolArgsTemplate\n BinData: &BinarySymbol\n id: \"BinData\"\n code: 102\n callable: *constructor\n args:\n - [ *IntegerType ]\n - [ *StringType ]\n type: *BinaryType\n attr: {}\n template: *BinarySymbolTemplate\n argsTemplate: *BinarySymbolArgsTemplate\n DBRef:\n id: \"DBRef\"\n code: 103\n callable: *constructor\n args:\n - [ *StringType ]\n - [ *ObjectIdType ]\n - [ *StringType, null ]\n type: *DBRefType\n attr: {}\n template: *DBRefSymbolTemplate\n argsTemplate: *DBRefSymbolArgsTemplate\n NumberInt:\n id: \"Int32\"\n code: 105\n callable: *constructor\n args:\n - [ *NumericType, *StringType, null ]\n type: *Int32Type\n attr: {}\n template: *Int32SymbolTemplate\n argsTemplate: *Int32SymbolArgsTemplate\n NumberLong:\n id: \"NumberLong\"\n code: 106\n callable: *constructor\n args:\n - [ *IntegerType, *StringType, null ]\n type: *LongType\n attr: {}\n template: *LongSymbolTemplate\n argsTemplate: *LongSymbolArgsTemplate\n MinKey:\n id: \"MinKey\"\n code: 107\n callable: *constructor\n args: []\n type: *MinKeyType\n attr: {}\n template: *MinKeySymbolTemplate\n argsTemplate: *MinKeySymbolArgsTemplate\n MaxKey:\n id: \"MaxKey\"\n code: 108\n callable: *constructor\n args: []\n type: *MaxKeyType\n attr: {}\n template: *MaxKeySymbolTemplate\n argsTemplate: *MaxKeySymbolArgsTemplate\n Timestamp:\n id: \"Timestamp\"\n code: 110\n callable: *constructor\n args:\n - [ *IntegerType, null ]\n - [ *IntegerType, null ]\n type: *TimestampType\n attr: {}\n template: *TimestampSymbolTemplate\n argsTemplate: *TimestampSymbolArgsTemplate\n Symbol:\n id: \"Symbol\"\n code: 111\n callable: *constructor\n args:\n - [ *StringType ]\n type: *SymbolType\n attr: {}\n template: *SymbolSymbolTemplate\n argsTemplate: *SymbolSymbolArgsTemplate\n NumberDecimal:\n id: \"NumberDecimal\"\n code: 112\n callable: *constructor\n args:\n - [ *StringType, *NumericType, null ]\n type: *Decimal128Type\n attr: {}\n template: *Decimal128SymbolTemplate\n argsTemplate: *Decimal128SymbolArgsTemplate\n BSONRegExp:\n id: \"BSONRegExp\"\n code: 109\n callable: *constructor\n args:\n - [ *StringType ]\n - [ *StringType, null ]\n type: *BSONRegExpType\n attr: {}\n template: *BSONRegExpSymbolTemplate\n argsTemplate: *BSONRegExpSymbolArgsTemplate\n BSONSymbol:\n id: \"BSONSymbol\"\n code: 111\n callable: *constructor\n args:\n - [ *StringType ]\n type: *SymbolType\n attr: {}\n template: *SymbolSymbolTemplate\n argsTemplate: *SymbolSymbolArgsTemplate\n Decimal128:\n id: \"Decimal128\"\n code: 112\n callable: *constructor\n args:\n - [ *ObjectType ]\n type: *Decimal128Type\n attr:\n fromString:\n id: \"fromString\"\n callable: *func\n args:\n - [ *StringType ]\n type: *Decimal128Type\n attr: {}\n template: *Decimal128SymbolFromStringTemplate\n argsTemplate: *Decimal128SymbolFromStringArgsTemplate\n template: *Decimal128SymbolTemplate\n argsTemplate: *Decimal128SymbolArgsTemplate\n Double:\n id: \"Double\"\n code: 104\n callable: *constructor\n args:\n - [ *NumericType, *StringType ]\n type: *DoubleType\n attr: {}\n template: *DoubleSymbolTemplate\n argsTemplate: *DoubleSymbolArgsTemplate\n Int32:\n id: \"Int32\"\n code: 105\n callable: *constructor\n args:\n - [ *NumericType, *StringType ]\n type: *Int32Type\n attr: {}\n template: *Int32SymbolTemplate\n argsTemplate: *Int32SymbolArgsTemplate\n Long:\n id: \"Long\"\n code: 106\n callable: *constructor\n args:\n - [ *IntegerType ]\n - [ *IntegerType ]\n type: *LongType\n attr:\n MAX_VALUE:\n id: \"MAX_VALUE\"\n callable: *var\n args: null\n type: *LongType\n attr: {}\n template: *LongSymbolMaxTemplate\n argsTemplate: *LongSymbolMaxArgsTemplate\n MIN_VALUE:\n id: \"MIN_VALUE\"\n callable: *var\n args: null\n type: *LongType\n attr: {}\n template: *LongSymbolMinTemplate\n argsTemplate: *LongSymbolMinArgsTemplate\n ZERO:\n id: \"ZERO\"\n callable: *var\n args: null\n type: *LongType\n attr: {}\n template: *LongSymbolZeroTemplate\n argsTemplate: *LongSymbolZeroArgsTemplate\n ONE:\n id: \"ONE\"\n callable: *var\n args: null\n type: *LongType\n attr: {}\n template: *LongSymbolOneTemplate\n argsTemplate: *LongSymbolOneArgsTemplate\n NEG_ONE:\n id: \"NEG_ONE\"\n callable: *var\n args: null\n type: *LongType\n attr: {}\n template: *LongSymbolNegOneTemplate\n argsTemplate: *LongSymbolNegOneArgsTemplate\n fromBits:\n id: \"LongfromBits\" # Needs process method\n callable: *func\n args:\n - [ *IntegerType ]\n - [ *IntegerType ]\n type: *LongType\n attr: {}\n template: *LongSymbolFromBitsTemplate\n argsTemplate: *LongSymbolFromBitsArgsTemplate\n fromInt:\n id: \"fromInt\"\n callable: *func\n args:\n - [ *IntegerType ]\n type: *LongType\n attr: {}\n template: *LongSymbolFromIntTemplate\n argsTemplate: *LongSymbolFromIntArgsTemplate\n fromNumber:\n id: \"fromNumber\"\n callable: *func\n args:\n - [ *NumericType ]\n type: *LongType\n attr: {}\n template: *LongSymbolFromNumberTemplate\n argsTemplate: *LongSymbolFromNumberArgsTemplate\n fromString:\n id: \"fromString\"\n callable: *func\n args:\n - [ *StringType ]\n - [ *IntegerType, null ]\n type: *LongType\n attr: {}\n template: *LongSymbolFromStringTemplate\n argsTemplate: *LongSymbolFromStringArgsTemplate\n template: *LongSymbolTemplate\n argsTemplate: *LongSymbolArgsTemplate\n\nNativeSymbols:\n Number:\n id: \"Number\"\n code: 2\n callable: *constructor\n args:\n - [ *IntegerType, *StringType, null ]\n type: *NumericType\n attr: {} # TODO: no built-in number funcs added yet\n template: *NumberSymbolTemplate\n argsTemplate: *NumberSymbolArgsTemplate\n Date: # Needs emit method\n id: \"Date\"\n code: 200\n callable: *constructor\n args:\n - [ *StringType, *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n type: *DateType\n attr: # TODO: add more date funcs?\n now:\n id: \"now\"\n code: 200.1\n callable: *func\n args: []\n type: *DateType\n attr: {}\n template: *DateSymbolNowTemplate\n argsTemplate: *DateSymbolNowArgsTemplate\n template: *DateSymbolTemplate\n argsTemplate: *DateSymbolArgsTemplate\n ISODate: # Needs emit method\n id: \"ISODate\"\n code: 200\n callable: *constructor\n args:\n - [ *StringType, null ]\n type: *DateType\n attr:\n now:\n id: \"now\"\n callable: *constructor\n args: []\n type: *DateType\n attr: {}\n template: *DateSymbolNowTemplate\n argsTemplate: *DateSymbolNowArgsTemplate\n template: *DateSymbolTemplate\n argsTemplate: *DateSymbolArgsTemplate\n RegExp: # Needs process method\n id: \"RegExp\"\n code: 8\n callable: *constructor\n args:\n - [ *StringType, *RegexType ]\n - [ *StringType, null ]\n type: *RegExpType\n attr: {} # TODO: no built-in regex funcs added yet\n template: *RegExpSymbolTemplate\n argsTemplate: *RegExpSymbolArgsTemplate\n\n"; |
@@ -1,1 +0,1 @@ | ||
module.exports="SymbolTypes:\n VAR: &var 0\n CONSTRUCTOR: &constructor 1\n FUNC: &func 2\n# Internal patterns to save typing\n__type: &__type\n id: null\n callable: *var\n args: null\n type: null\n attr: {}\n template: null\n argsTemplate: null\n__func: &__func\n callable: *func\n args: []\n attr: {}\n template: null\n argsTemplate: null\n\n#############################################\n# Sample Templates #\n# #\n# The expected arguments are commented next #\n# to the template itself. Currently all are #\n# set to null, but to define a function #\n# replace 'null' with '!!js/function > \\n #\n# and a function defined below. #\n# #\n# See the other template files for examples #\n# #\n# Good to know: #\n# lhs is left-hand-side of the expression #\n# rhs is right-hand-side of the expression #\n# All args are strings unless noted #\n# - arg? is boolean #\n# - arg# is number #\n# #\n#############################################\nTemplates:\n ########\n # Misc #\n ########\n\n # Filter out regex flags that have translations or are unsupported.\n RegexFlags: &RegexFlags\n i: 'i'\n m: 'm'\n u: 'u'\n y: 'y'\n g: 'g'\n BSONRegexFlags: &BSONRegexFlags\n i: 'i'\n m: 'm'\n x: 'x'\n s: 's'\n l: 'l'\n u: 'u'\n\n #############################################\n # Syntax #\n # #\n # Templates for language syntax expressions #\n # #\n #############################################\n\n DriverTemplate: &DriverTemplate null\n EqualitySyntaxTemplate: &EqualitySyntaxTemplate !!js/function >\n (lhs, op, rhs) => {\n if (op.includes('!') || op.includes('not')) {\n return lhs !== rhs;\n }\n if (op === '==' || op === '===' || op === 'is') {\n if (typeof(lhs) === 'object' && 'equals' in lhs) {\n // Use '.equals' for objects, if it exists.\n return lhs.equals(rhs);\n }\n return lhs === rhs;\n }\n if (op === '>') {\n return lhs > rhs;\n }\n if (op === '<') {\n return lhs < rhs;\n }\n if (op === '>=') {\n return lhs >= rhs;\n }\n if (op === '<=') {\n return lhs <= rhs;\n }\n throw new Error(`unrecognized operation: ${op}`);\n }\n InSyntaxTemplate: &InSyntaxTemplate !!js/function >\n (lhs, op, rhs) => {\n if (op.includes('!') || op.includes('not')) {\n if (typeof rhs === 'array') {\n return rhs.indexOf(lhs) === -1;\n }\n return !(lhs in rhs);\n }\n if (typeof rhs === 'array') {\n return rhs.indexOf(lhs) !== -1;\n }\n return lhs in rhs;\n }\n\n AndSyntaxTemplate: &AndSyntaxTemplate !!js/function >\n (args) => {\n return args.reduce((t, k, i) => {\n return t && k;\n });\n }\n OrSyntaxTemplate: &OrSyntaxTemplate !!js/function >\n (args) => {\n return args.reduce((t, k, i) => {\n return t || k;\n });\n }\n NotSyntaxTemplate: &NotSyntaxTemplate !!js/function >\n (arg) => {\n return !arg;\n }\n UnarySyntaxTemplate: &UnarySyntaxTemplate !!js/function >\n (op, arg) => {\n switch(op) {\n case '+':\n return +arg;\n case '-':\n return -arg;\n case '~':\n return ~arg;\n default:\n throw new Error(`unrecognized operation: ${op}`);\n }\n }\n BinarySyntaxTemplate: &BinarySyntaxTemplate !!js/function >\n (args) => {\n return args.reduce((s, op, i, arr) => {\n if (i % 2 === 0) {\n return s;\n }\n const rhs = arr[i + 1];\n switch(op) {\n case '+':\n return s + rhs;\n case '-':\n return s - rhs;\n case '*':\n return s * rhs;\n case '/':\n return s / rhs;\n case '**':\n return Math.pow(s, rhs);\n case '//':\n return Math.floor(s, rhs);\n case '%':\n return s % rhs;\n case '>>':\n return s >> rhs;\n case '<<':\n return s << rhs;\n case '|':\n return s | rhs;\n case '&':\n return s & rhs;\n case '^':\n return s ^ rhs;\n default:\n throw new Error(`unrecognized operation: ${op}`);\n }\n }, args[0]);\n }\n ParensSyntaxTemplate: &ParensSyntaxTemplate !!js/function >\n (arg) => {\n return arg;\n }\n EosSyntaxTemplate: &EosSyntaxTemplate !!js/function >\n () => {\n return 'a unique thing';\n }\n EofSyntaxTemplate: &EofSyntaxTemplate !!js/function >\n () => {\n return 'a unique thing';\n }\n FloorDivTemplate: &FloorDivSyntaxTemplate null # Args: lhs, rhs\n PowerTemplate: &PowerSyntaxTemplate null # Args: lhs, rhs\n NewTemplate: &NewSyntaxTemplate null # Args: expression, skip?, code# [to check if meant to be skipped]\n\n #############################################\n # Literal Types #\n # #\n # Templates for literal type instance. Most #\n # get passed the literal itself as an arg. #\n # #\n #############################################\n StringTypeTemplate: &StringTypeTemplate !!js/function >\n (str) => {\n let newStr = str.toString();\n if (\n (newStr.charAt(0) === '\"' && newStr.charAt(newStr.length - 1) === '\"') ||\n (newStr.charAt(0) === '\\'' && newStr.charAt(newStr.length - 1) === '\\'')\n ) {\n newStr = newStr.substr(1, newStr.length - 2);\n }\n return newStr;\n }\n RegexTypeTemplate: &RegexTypeTemplate !!js/function >\n (pattern, flags) => {\n return new RegExp(pattern, flags);\n }\n BoolTypeTemplate: &BoolTypeTemplate !!js/function >\n (str) => {\n return str.toLowerCase() === 'true';\n }\n IntegerTypeTemplate: &IntegerTypeTemplate !!js/function >\n (arg) => {\n return parseInt(arg, 10);\n }\n DecimalTypeTemplate: &DecimalTypeTemplate !!js/function >\n (arg) => {\n return parseFloat(arg);\n }\n LongBasicTypeTemplate: &LongBasicTypeTemplate !!js/function >\n (arg) => {\n return parseInt(arg, 10);\n }\n HexTypeTemplate: &HexTypeTemplate !!js/function >\n (arg) => {\n return parseInt(arg, 16);\n }\n OctalTypeTemplate: &OctalTypeTemplate !!js/function >\n (arg) => {\n arg = arg.replace(/[oO]/g, '')\n return parseInt(arg, 8);\n }\n NumericTypeTemplate: &NumericTypeTemplate !!js/function >\n (arg) => {\n if (arg.contains('x')) {\n return parseInt(arg, 16);\n }\n if (arg.contains('o') || arg.startsWith('0')) {\n arg = arg.replace(/o/g, '')\n return parseInt(arg, 8);\n }\n return parseFloat(arg);\n }\n ArrayTypeTemplate: &ArrayTypeTemplate null\n ArrayTypeArgsTemplate: &ArrayTypeArgsTemplate null # Args: single array element, nestedness, lastElement? (note: not being used atm)\n NullTypeTemplate: &NullTypeTemplate !!js/function >\n () => {\n return null;\n }\n UndefinedTypeTemplate: &UndefinedTypeTemplate !!js/function >\n () => {\n return undefined;\n }\n ObjectTypeTemplate: &ObjectTypeTemplate null # Args: literal (for empty array, is empty string. Otherwise all set)\n ObjectTypeArgsTemplate: &ObjectTypeArgsTemplate null # Args: single object element [2] (i.e. array with [key, value]), nestedness#\n\n #############################################\n # Symbols #\n # #\n # Templates for symbols, can be either #\n # functions or variables. #\n # #\n # The *SymbolTemplates return names and #\n # usually don't take any arguments. The #\n # *SymbolArgsTemplates are invoked for func #\n # calls. The first argument is always the #\n # lhs, i.e. the symbol returned from the #\n # corresponding SymbolTemplate. The rest of #\n # the arguments are the processed arguments #\n # passed to the original function. #\n # #\n #############################################\n CodeSymbolTemplate: &CodeSymbolTemplate null # No args\n CodeSymbolArgsTemplate: &CodeSymbolArgsTemplate null # Args: code, scope\n ObjectIdSymbolTemplate: &ObjectIdSymbolTemplate null # No args\n ObjectIdSymbolArgsTemplate: &ObjectIdSymbolArgsTemplate null # Args: lhs, string (can be empty or null for no arg)\n BinarySymbolTemplate: &BinarySymbolTemplate null\n BinarySymbolArgsTemplate: &BinarySymbolArgsTemplate null\n BinarySymbolSubtypeDefaultTemplate: &BinarySymbolSubtypeDefaultTemplate null\n BinarySymbolSubtypeFunctionTemplate: &BinarySymbolSubtypeFunctionTemplate null\n BinarySymbolSubtypeByteArrayTemplate: &BinarySymbolSubtypeByteArrayTemplate null\n BinarySymbolSubtypeUuidOldTemplate: &BinarySymbolSubtypeUuidOldTemplate null\n BinarySymbolSubtypeUuidTemplate: &BinarySymbolSubtypeUuidTemplate null\n BinarySymbolSubtypeMd5Template: &BinarySymbolSubtypeMd5Template null\n BinarySymbolSubtypeUserDefinedTemplate: &BinarySymbolSubtypeUserDefinedTemplate null\n DBRefSymbolTemplate: &DBRefSymbolTemplate null # No args\n DBRefSymbolArgsTemplate: &DBRefSymbolArgsTemplate null # Args: lhs, coll, id, db\n DoubleSymbolTemplate: &DoubleSymbolTemplate null # No args\n DoubleSymbolArgsTemplate: &DoubleSymbolArgsTemplate null # Args: lhs, arg, argType (i.e. '_string', '_double')\n Int32SymbolTemplate: &Int32SymbolTemplate null # No args\n Int32SymbolArgsTemplate: &Int32SymbolArgsTemplate null # Args: lhs, arg, argType\n LongSymbolTemplate: &LongSymbolTemplate null # No args\n LongSymbolArgsTemplate: &LongSymbolArgsTemplate !!js/function > # Args: lhs, arg, argType\n (lhs, arg) => {\n return lhs.fromNumber(arg);\n }\n RegExpSymbolTemplate: &RegExpSymbolTemplate null # No args\n RegExpSymbolArgsTemplate: &RegExpSymbolArgsTemplate null # Args: lhs, pattern, flags\n SymbolSymbolTemplate: &SymbolSymbolTemplate null # No args\n SymbolSymbolArgsTemplate: &SymbolSymbolArgsTemplate null # Args: lhs, arg\n BSONRegExpSymbolTemplate: &BSONRegExpSymbolTemplate null # No args\n BSONRegExpSymbolArgsTemplate: &BSONRegExpSymbolArgsTemplate null # Args: lhs, pattern, flags\n Decimal128SymbolTemplate: &Decimal128SymbolTemplate null # No args\n Decimal128SymbolArgsTemplate: &Decimal128SymbolArgsTemplate null # Args: lhs, arg\n MinKeySymbolTemplate: &MinKeySymbolTemplate null # No args\n MinKeySymbolArgsTemplate: &MinKeySymbolArgsTemplate null # No args\n MaxKeySymbolTemplate: &MaxKeySymbolTemplate null # No args\n MaxKeySymbolArgsTemplate: &MaxKeySymbolArgsTemplate null # No args\n TimestampSymbolTemplate: &TimestampSymbolTemplate null # No args\n TimestampSymbolArgsTemplate: &TimestampSymbolArgsTemplate null # Args: lhs, low, high\n # non bson-specific\n NumberSymbolTemplate: &NumberSymbolTemplate !!js/function >\n () => {\n return Number;\n }\n NumberSymbolArgsTemplate: &NumberSymbolArgsTemplate null # Args: lhs, arg, argType\n DateSymbolTemplate: &DateSymbolTemplate null # No args\n DateSymbolArgsTemplate: &DateSymbolArgsTemplate !!js/function >\n (lhs, date, isString) => {\n if (isString) {\n return date.toString();\n }\n return date;\n }\n\n #############################################\n # Object Attributes/Methods #\n # #\n # These're variables or functions called on #\n # instantiated objects. For example, #\n # ObjectId().isValid() or Timestamp().t #\n # #\n # They follow the same pattern with the\n # *Template/*ArgsTemplates: usually no args #\n # to the Template and lhs plus any original #\n # arguments to the ArgsTemplate. #\n # #\n #############################################\n CodeCodeTemplate: &CodeCodeTemplate null\n CodeCodeArgsTemplate: &CodeCodeArgsTemplate null\n CodeScopeTemplate: &CodeScopeTemplate null\n CodeScopeArgsTemplate: &CodeScopeArgsTemplate null\n ObjectIdToStringTemplate: &ObjectIdToStringTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.toString();\n }\n ObjectIdToStringArgsTemplate: &ObjectIdToStringArgsTemplate !!js/function >\n (lhs) => {\n return lhs;\n }\n ObjectIdEqualsTemplate: &ObjectIdEqualsTemplate !!js/function >\n (lhs) => {\n return lhs;\n }\n ObjectIdEqualsArgsTemplate: &ObjectIdEqualsArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.equals(rhs);\n }\n ObjectIdGetTimestampTemplate: &ObjectIdGetTimestampTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.getTimestamp();\n }\n ObjectIdGetTimestampArgsTemplate: &ObjectIdGetTimestampArgsTemplate !!js/function >\n (lhs) => {\n return lhs;\n }\n ObjectIdIsValidTemplate: &ObjectIdIsValidTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.isValid;\n }\n ObjectIdIsValidArgsTemplate: &ObjectIdIsValidArgsTemplate null\n BinaryValueTemplate: &BinaryValueTemplate null\n BinaryValueArgsTemplate: &BinaryValueArgsTemplate null\n BinaryLengthTemplate: &BinaryLengthTemplate null\n BinaryLengthArgsTemplate: &BinaryLengthArgsTemplate null\n BinaryToStringTemplate: &BinaryToStringTemplate null\n BinaryToStringArgsTemplate: &BinaryToStringArgsTemplate null\n BinarySubtypeTemplate: &BinarySubtypeTemplate null\n BinarySubtypeArgsTemplate: &BinarySubtypeArgsTemplate null\n DBRefGetDBTemplate: &DBRefGetDBTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.db;\n }\n DBRefGetCollectionTemplate: &DBRefGetCollectionTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.collection;\n }\n DBRefGetIdTemplate: &DBRefGetIdTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.oid;\n }\n DBRefGetDBArgsTemplate: &DBRefGetDBArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n DBRefGetCollectionArgsTemplate: &DBRefGetCollectionArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n DBRefGetIdArgsTemplate: &DBRefGetIdArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n LongEqualsTemplate: &LongEqualsTemplate null\n LongEqualsArgsTemplate: &LongEqualsArgsTemplate null\n LongToStringTemplate: &LongToStringTemplate null\n LongToStringArgsTemplate: &LongToStringArgsTemplate null\n LongToIntTemplate: &LongToIntTemplate null\n LongToIntArgsTemplate: &LongToIntArgsTemplate null\n LongValueOfTemplate: &LongValueOfTemplate null\n LongValueOfArgsTemplate: &LongValueOfArgsTemplate null\n LongToNumberTemplate: &LongToNumberTemplate null\n LongToNumberArgsTemplate: &LongToNumberArgsTemplate null\n LongAddTemplate: &LongAddTemplate null\n LongAddArgsTemplate: &LongAddArgsTemplate null\n LongSubtractTemplate: &LongSubtractTemplate null\n LongSubtractArgsTemplate: &LongSubtractArgsTemplate null\n LongMultiplyTemplate: &LongMultiplyTemplate null\n LongMultiplyArgsTemplate: &LongMultiplyArgsTemplate null\n LongDivTemplate: &LongDivTemplate null\n LongDivArgsTemplate: &LongDivArgsTemplate null\n LongModuloTemplate: &LongModuloTemplate null\n LongModuloArgsTemplate: &LongModuloArgsTemplate null\n LongAndTemplate: &LongAndTemplate null\n LongAndArgsTemplate: &LongAndArgsTemplate null\n LongOrTemplate: &LongOrTemplate null\n LongOrArgsTemplate: &LongOrArgsTemplate null\n LongXorTemplate: &LongXorTemplate null\n LongXorArgsTemplate: &LongXorArgsTemplate null\n LongShiftLeftTemplate: &LongShiftLeftTemplate null\n LongShiftLeftArgsTemplate: &LongShiftLeftArgsTemplate null\n LongShiftRightTemplate: &LongShiftRightTemplate null\n LongShiftRightArgsTemplate: &LongShiftRightArgsTemplate null\n LongCompareTemplate: &LongCompareTemplate null\n LongCompareArgsTemplate: &LongCompareArgsTemplate null\n LongIsOddTemplate: &LongIsOddTemplate null\n LongIsOddArgsTemplate: &LongIsOddArgsTemplate null\n LongIsZeroTemplate: &LongIsZeroTemplate null\n LongIsZeroArgsTemplate: &LongIsZeroArgsTemplate null\n LongIsNegativeTemplate: &LongIsNegativeTemplate null\n LongIsNegativeArgsTemplate: &LongIsNegativeArgsTemplate null\n LongNegateTemplate: &LongNegateTemplate null\n LongNegateArgsTemplate: &LongNegateArgsTemplate null\n LongNotTemplate: &LongNotTemplate null\n LongNotArgsTemplate: &LongNotArgsTemplate null\n LongNotEqualsTemplate: &LongNotEqualsTemplate null\n LongNotEqualsArgsTemplate: &LongNotEqualsArgsTemplate null\n LongGreaterThanTemplate: &LongGreaterThanTemplate null\n LongGreaterThanArgsTemplate: &LongGreaterThanArgsTemplate null\n LongGreaterThanOrEqualTemplate: &LongGreaterThanOrEqualTemplate null\n LongGreaterThanOrEqualArgsTemplate: &LongGreaterThanOrEqualArgsTemplate null\n LongLessThanTemplate: &LongLessThanTemplate null\n LongLessThanArgsTemplate: &LongLessThanArgsTemplate null\n LongLessThanOrEqualTemplate: &LongLessThanOrEqualTemplate null\n LongLessThanOrEqualArgsTemplate: &LongLessThanOrEqualArgsTemplate null\n LongFloatApproxTemplate: &LongFloatApproxTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.toNumber();\n }\n LongTopTemplate: &LongTopTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.high;\n }\n LongBottomTemplate: &LongBottomTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.low;\n }\n TimestampToStringTemplate: &TimestampToStringTemplate null\n TimestampToStringArgsTemplate: &TimestampToStringArgsTemplate null\n TimestampEqualsTemplate: &TimestampEqualsTemplate null\n TimestampEqualsArgsTemplate: &TimestampEqualsArgsTemplate null\n TimestampGetLowBitsTemplate: &TimestampGetLowBitsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.getLowBits();\n }\n TimestampGetLowBitsArgsTemplate: &TimestampGetLowBitsArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n TimestampGetHighBitsTemplate: &TimestampGetHighBitsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.getHighBits();\n }\n TimestampGetHighBitsArgsTemplate: &TimestampGetHighBitsArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n TimestampTTemplate: &TimestampTTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.getLowBits();\n }\n TimestampITemplate: &TimestampITemplate !!js/function >\n (lhs, rhs) => {\n return lhs.getHighBits();\n }\n TimestampAsDateTemplate: &TimestampAsDateTemplate !!js/function >\n (lhs, rhs) => {\n return new Date(lhs.getHighBits() * 1000);\n }\n TimestampAsDateArgsTemplate: &TimestampAsDateArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n TimestampCompareTemplate: &TimestampCompareTemplate null\n TimestampCompareArgsTemplate: &TimestampCompareArgsTemplate null\n TimestampNotEqualsTemplate: &TimestampNotEqualsTemplate null\n TimestampNotEqualsArgsTemplate: &TimestampNotEqualsArgsTemplate null\n TimestampGreaterThanTemplate: &TimestampGreaterThanTemplate null\n TimestampGreaterThanArgsTemplate: &TimestampGreaterThanArgsTemplate null\n TimestampGreaterThanOrEqualTemplate: &TimestampGreaterThanOrEqualTemplate null\n TimestampGreaterThanOrEqualArgsTemplate: &TimestampGreaterThanOrEqualArgsTemplate null\n TimestampLessThanTemplate: &TimestampLessThanTemplate null\n TimestampLessThanArgsTemplate: &TimestampLessThanArgsTemplate null\n TimestampLessThanOrEqualTemplate: &TimestampLessThanOrEqualTemplate null\n TimestampLessThanOrEqualArgsTemplate: &TimestampLessThanOrEqualArgsTemplate null\n SymbolValueOfTemplate: &SymbolValueOfTemplate null\n SymbolValueOfArgsTemplate: &SymbolValueOfArgsTemplate null\n SymbolInspectTemplate: &SymbolInspectTemplate null\n SymbolInspectArgsTemplate: &SymbolInspectArgsTemplate null\n SymbolToStringTemplate: &SymbolToStringTemplate null\n SymbolToStringArgsTemplate: &SymbolToStringArgsTemplate null\n Decimal128ToStringTemplate: &Decimal128ToStringTemplate null\n Decimal128ToStringArgsTemplate: &Decimal128ToStringArgsTemplate null\n # non bson-specific\n DateSymbolNowTemplate: &DateSymbolNowTemplate !!js/function >\n () => {\n return Date.now;\n }\n DateSymbolNowArgsTemplate: &DateSymbolNowArgsTemplate null\n\n #############################################\n # Symbol Attributes/Methods #\n # #\n # These're variables or functions called on #\n # symbols. Also called bson-utils. #\n # #\n # They are basically the same thing as #\n # object attributes/methods, but need to be #\n # distinguished since they are separate #\n # namespaces that happen to have the same #\n # name which is v confusing. #\n # #\n # For example, ObjectId().toString() is an #\n # object method, while ObjectId.fromString #\n # is a symbol attribute. These are two #\n # separate ObjectId related namespaces that #\n # don't overlap. #\n # #\n #############################################\n LongSymbolMaxTemplate: &LongSymbolMaxTemplate null\n LongSymbolMaxArgsTemplate: &LongSymbolMaxArgsTemplate null\n LongSymbolMinTemplate: &LongSymbolMinTemplate null\n LongSymbolMinArgsTemplate: &LongSymbolMinArgsTemplate null\n LongSymbolZeroTemplate: &LongSymbolZeroTemplate null\n LongSymbolZeroArgsTemplate: &LongSymbolZeroArgsTemplate null\n LongSymbolOneTemplate: &LongSymbolOneTemplate null\n LongSymbolOneArgsTemplate: &LongSymbolOneArgsTemplate null\n LongSymbolNegOneTemplate: &LongSymbolNegOneTemplate null\n LongSymbolNegOneArgsTemplate: &LongSymbolNegOneArgsTemplate null\n LongSymbolFromBitsTemplate: &LongSymbolFromBitsTemplate null\n LongSymbolFromBitsArgsTemplate: &LongSymbolFromBitsArgsTemplate null\n LongSymbolFromIntTemplate: &LongSymbolFromIntTemplate null\n LongSymbolFromIntArgsTemplate: &LongSymbolFromIntArgsTemplate null\n LongSymbolFromNumberTemplate: &LongSymbolFromNumberTemplate null\n LongSymbolFromNumberArgsTemplate: &LongSymbolFromNumberArgsTemplate null\n LongSymbolFromStringTemplate: &LongSymbolFromStringTemplate null\n LongSymbolFromStringArgsTemplate: &LongSymbolFromStringArgsTemplate null\n Decimal128SymbolFromStringTemplate: &Decimal128SymbolFromStringTemplate null\n Decimal128SymbolFromStringArgsTemplate: &Decimal128SymbolFromStringArgsTemplate null\n ObjectIdCreateFromHexStringTemplate: &ObjectIdCreateFromHexStringTemplate null\n ObjectIdCreateFromHexStringArgsTemplate: &ObjectIdCreateFromHexStringArgsTemplate null\n ObjectIdCreateFromTimeTemplate: &ObjectIdCreateFromTimeTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.createFromTime;\n }\n ObjectIdCreateFromTimeArgsTemplate: &ObjectIdCreateFromTimeArgsTemplate null\n # non bson-specific would go here, but there aren't any atm.\n\n #############################################\n # Imports #\n # #\n # Each type has a 'code' that is consistent #\n # between languages. The import templates #\n # for each code generate the required #\n # statement for each type. No args. #\n # #\n # The ImportTemplate collects everything #\n # into one statement. #\n # #\n #############################################\n ImportTemplate: &ImportTemplate null\n DriverImportTemplate: &DriverImportTemplate null\n 0ImportTemplate: &0ImportTemplate null\n 1ImportTemplate: &1ImportTemplate null\n 2ImportTemplate: &2ImportTemplate null\n 3ImportTemplate: &3ImportTemplate null\n 4ImportTemplate: &4ImportTemplate null\n 5ImportTemplate: &5ImportTemplate null\n 6ImportTemplate: &6ImportTemplate null\n 7ImportTemplate: &7ImportTemplate null\n 8ImportTemplate: &8ImportTemplate null\n 9ImportTemplate: &9ImportTemplate null\n 10ImportTemplate: &10ImportTemplate null\n 11ImportTemplate: &11ImportTemplate null\n 12ImportTemplate: &12ImportTemplate null\n 100ImportTemplate: &100ImportTemplate null\n 101ImportTemplate: &101ImportTemplate null\n 102ImportTemplate: &102ImportTemplate null\n 103ImportTemplate: &103ImportTemplate null\n 104ImportTemplate: &104ImportTemplate null\n 105ImportTemplate: &105ImportTemplate null\n 106ImportTemplate: &106ImportTemplate null\n 107ImportTemplate: &107ImportTemplate null\n 108ImportTemplate: &108ImportTemplate null\n 109ImportTemplate: &109ImportTemplate null\n 110ImportTemplate: &110ImportTemplate null\n 111ImportTemplate: &111ImportTemplate null\n 112ImportTemplate: &112ImportTemplate null\n 113ImportTemplate: &113ImportTemplate null\n 114ImportTemplate: &114ImportTemplate null\n 200ImportTemplate: &200ImportTemplate null\n 201ImportTemplate: &201ImportTemplate null\n 300ImportTemplate: &300ImportTemplate null\n 301ImportTemplate: &301ImportTemplate null\n 302ImportTemplate: &302ImportTemplate null\n 303ImportTemplate: &303ImportTemplate null\n 304ImportTemplate: &304ImportTemplate null\n 305ImportTemplate: &305ImportTemplate null\n 306ImportTemplate: &306ImportTemplate null\n# Universal types\n# Everything inherits from StringType because we haven't implemented any of them.\nBasicTypes:\n # Universal basic types\n _bool: &BoolType\n <<: *__type\n id: \"_bool\"\n code: 0\n template: *BoolTypeTemplate\n _integer: &IntegerType\n <<: *__type\n id: \"_integer\"\n code: 1\n template: *IntegerTypeTemplate\n _long: &LongBasicType\n <<: *__type\n id: \"_long\"\n code: 2\n template: *LongBasicTypeTemplate\n _decimal: &DecimalType\n <<: *__type\n id: \"_decimal\"\n code: 3\n template: *DecimalTypeTemplate\n _hex: &HexType\n <<: *__type\n id: \"_hex\"\n code: 4\n template: *HexTypeTemplate\n _octal: &OctalType\n <<: *__type\n id: \"_octal\"\n code: 5\n template: *OctalTypeTemplate\n _numeric: &NumericType\n <<: *__type\n id: \"_numeric\"\n code: 6\n template: *NumericTypeTemplate\n _string: &StringType\n <<: *__type\n id: \"_string\"\n code: 7\n template: *StringTypeTemplate\n _regex: &RegexType\n <<: *__type\n id: \"_regex\"\n code: 8\n template: *RegexTypeTemplate\n _array: &ArrayType\n <<: *__type\n id: \"_array\"\n code: 9\n template: *ArrayTypeTemplate\n argsTemplate: *ArrayTypeArgsTemplate\n _object: &ObjectType\n <<: *__type\n id: \"_object\"\n code: 10\n template: *ObjectTypeTemplate\n argsTemplate: *ObjectTypeArgsTemplate\n _null: &NullType\n <<: *__type\n id: \"_null\"\n code: 11\n template: *NullTypeTemplate\n _undefined: &UndefinedType\n <<: *__type\n id: \"_undefined\"\n code: 12\n template: *UndefinedTypeTemplate\n\nSyntax:\n equality:\n template: *EqualitySyntaxTemplate\n in:\n template: *InSyntaxTemplate\n and:\n template: *AndSyntaxTemplate\n or:\n template: *OrSyntaxTemplate\n not:\n template: *NotSyntaxTemplate\n unary:\n template: *UnarySyntaxTemplate\n binary:\n template: *BinarySyntaxTemplate\n parens:\n template: *ParensSyntaxTemplate\n eos:\n template: *EosSyntaxTemplate\n eof:\n template: *EofSyntaxTemplate\n # The new template takes in expr, and an optional skip argument and optional\n # id argument. The skip argument is a boolean that if true then doesn't add\n # new. The code argument is the symbol code being called. The template will check\n # if it is an exception, i.e. a type that is a constructor but may not use new.\n new:\n template: *NewSyntaxTemplate\n # The regex flags that change symbols between languages can be defined here.\n # Flags that aren't defined can be left blank and will be ignored.\n regexFlags: *RegexFlags\n bsonRegexFlags: *BSONRegexFlags\n driver: *DriverTemplate\nImports:\n import:\n template: *ImportTemplate\n driver:\n template: *DriverImportTemplate\n 0:\n template: *0ImportTemplate\n 1:\n template: *1ImportTemplate\n 2:\n template: *2ImportTemplate\n 3:\n template: *3ImportTemplate\n 4:\n template: *4ImportTemplate\n 5:\n template: *5ImportTemplate\n 6:\n template: *6ImportTemplate\n 7:\n template: *7ImportTemplate\n 8:\n template: *8ImportTemplate\n 9:\n template: *9ImportTemplate\n 10:\n template: *10ImportTemplate\n 11:\n template: *11ImportTemplate\n 12:\n template: *12ImportTemplate\n 100:\n template: *100ImportTemplate\n 101:\n template: *101ImportTemplate\n 102:\n template: *102ImportTemplate\n 103:\n template: *103ImportTemplate\n 104:\n template: *104ImportTemplate\n 105:\n template: *105ImportTemplate\n 106:\n template: *106ImportTemplate\n 107:\n template: *107ImportTemplate\n 108:\n template: *108ImportTemplate\n 109:\n template: *109ImportTemplate\n 110:\n template: *110ImportTemplate\n 111:\n template: *111ImportTemplate\n 112:\n template: *112ImportTemplate\n 113:\n template: *113ImportTemplate\n 114:\n template: *114ImportTemplate\n 200:\n template: *200ImportTemplate\n 201:\n template: *201ImportTemplate\n 300:\n template: *300ImportTemplate\n 301:\n template: *301ImportTemplate\n 302:\n template: *302ImportTemplate\n 303:\n template: *303ImportTemplate\n 304:\n template: *304ImportTemplate\n 305:\n template: *305ImportTemplate\n 306:\n template: *306ImportTemplate\nBsonTypes:\n Code: &CodeType\n <<: *__type\n id: \"Code\"\n code: 100\n type: *ObjectType\n attr:\n code:\n callable: *var\n args: null\n attr: null\n id: \"code\"\n type: *StringType\n template: *CodeCodeTemplate\n argsTemplate: *CodeCodeArgsTemplate\n scope:\n callable: *var\n args: null\n attr: null\n id: \"scope\"\n type: *StringType\n template: *CodeScopeTemplate\n argsTemplate: *CodeScopeArgsTemplate\n ObjectId: &ObjectIdType\n <<: *__type\n id: \"ObjectId\"\n code: 101\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *ObjectIdToStringTemplate\n argsTemplate: *ObjectIdToStringArgsTemplate\n equals:\n <<: *__func\n id: \"equals\"\n args:\n - [ \"ObjectId\" ]\n type: *BoolType\n template: *ObjectIdEqualsTemplate\n argsTemplate: *ObjectIdEqualsArgsTemplate\n getTimestamp:\n <<: *__func\n id: \"getTimestamp\"\n type: *IntegerType\n template: *ObjectIdGetTimestampTemplate\n argsTemplate: *ObjectIdGetTimestampArgsTemplate\n BinData: &BinaryType\n <<: *__type\n id: \"BinData\"\n code: 102\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *BinaryToStringTemplate\n argsTemplate: *BinaryToStringArgsTemplate\n base64:\n <<: *__func\n id: \"base64\"\n type: *StringType\n template: *BinaryValueTemplate\n argsTemplate: *BinaryValueArgsTemplate\n length:\n <<: *__func\n id: \"length\"\n type: *IntegerType\n template: *BinaryLengthTemplate\n argsTemplate: *BinaryLengthArgsTemplate\n subtype:\n <<: *__func\n id: \"subtype\"\n type: *IntegerType\n template: *BinarySubtypeTemplate\n argsTemplate: *BinarySubtypeArgsTemplate\n DBRef: &DBRefType\n <<: *__type\n id: \"DBRef\"\n code: 103\n type: *ObjectType\n attr:\n getDb:\n <<: *__func\n id: \"getDb\"\n type: *StringType\n template: *DBRefGetDBTemplate\n argsTemplate: *DBRefGetDBArgsTemplate\n $db:\n callable: *var\n args: null\n attr: null\n id: \"$db\"\n type: *StringType\n template: *DBRefGetDBTemplate\n argsTemplate: *DBRefGetDBArgsTemplate\n getCollection:\n <<: *__func\n id: \"getCollection\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n getRef:\n <<: *__func\n id: \"getRef\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n $ref:\n callable: *var\n args: null\n attr: null\n id: \"$ref\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n getId:\n <<: *__func\n id: \"getId\"\n type: *StringType\n template: *DBRefGetIdTemplate\n argsTemplate: *DBRefGetIdArgsTemplate\n $id:\n callable: *var\n args: null\n attr: null\n id: \"$id\"\n type: *StringType\n template: *DBRefGetIdTemplate\n argsTemplate: *DBRefGetIdArgsTemplate\n NumberInt: &Int32Type\n <<: *__type\n id: \"NumberInt\"\n code: 105\n type: *ObjectType\n attr: {}\n NumberLong: &LongType\n <<: *__type\n id: \"NumberLong\"\n code: 106\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"LongtoString\" # Needs process method\n type: *StringType\n top:\n callable: *var\n args: null\n attr: null\n id: \"top\"\n type: *IntegerType\n template: *LongTopTemplate\n argsTemplate: null\n bottom:\n callable: *var\n args: null\n attr: null\n id: \"bottom\"\n type: *IntegerType\n template: *LongBottomTemplate\n argsTemplate: null\n floatApprox:\n callable: *var\n args: null\n attr: null\n id: \"floatApprox\"\n type: *IntegerType\n template: *LongFloatApproxTemplate\n argsTemplate: null\n MinKeyType: &MinKeyType\n <<: *__type\n id: \"MinKey\"\n code: 107\n type: *ObjectType\n MaxKeyType: &MaxKeyType\n <<: *__type\n id: \"MaxKey\"\n code: 108\n type: *ObjectType\n Timestamp: &TimestampType\n <<: *__type\n id: \"TimestampFromShell\"\n code: 110\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *TimestampToStringTemplate\n argsTemplate: *TimestampToStringArgsTemplate\n getTime:\n <<: *__func\n id: \"getTime\"\n type: *IntegerType\n template: *TimestampGetLowBitsTemplate\n argsTemplate: *TimestampGetLowBitsArgsTemplate\n getInc:\n <<: *__func\n id: \"getInc\"\n type: *IntegerType\n template: *TimestampGetHighBitsTemplate\n argsTemplate: *TimestampGetHighBitsArgsTemplate\n t:\n callable: *var\n args: null\n attr: null\n id: \"getTime\"\n type: *IntegerType\n template: *TimestampTTemplate\n argsTemplate: null\n i:\n callable: *var\n args: null\n attr: null\n id: \"getInc\"\n type: *IntegerType\n template: *TimestampITemplate\n argsTemplate: null\n Symbol: &SymbolType\n <<: *__type\n id: \"Symbol\"\n code: 111\n type: *ObjectType\n NumberDecimal: &Decimal128Type\n <<: *__type\n id: \"NumberDecimal\"\n code: 112\n type: *ObjectType\n attr: {}\n SUBTYPE_DEFAULT:\n id: \"SUBTYPE_DEFAULT\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeDefaultTemplate\n SUBTYPE_FUNCTION:\n id: \"SUBTYPE_FUNCTION\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeFunctionTemplate\n SUBTYPE_BYTE_ARRAY:\n id: \"SUBTYPE_BYTE_ARRAY\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeByteArrayTemplate\n SUBTYPE_UUID_OLD:\n id: \"SUBTYPE_UUID_OLD\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUuidOldTemplate\n SUBTYPE_UUID:\n id: \"SUBTYPE_UUID\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUuidTemplate\n SUBTYPE_MD5:\n id: \"SUBTYPE_MD5\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeMd5Template\n SUBTYPE_USER_DEFINED:\n id: \"SUBTYPE_USER_DEFINED\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUserDefinedTemplate\nNativeTypes:\n Date: &DateType\n <<: *__type\n id: \"Date\"\n code: 200\n type: *ObjectType\n attr: {} # TODO: no built-in date methods added yet\n RegExp: &RegExpType\n <<: *__type\n id: \"RegExp\"\n code: 8\n type: *ObjectType\n attr: {}\n\n\n\n\nBsonSymbols:\n Code: &CodeSymbol\n id: \"Code\"\n code: 100\n callable: *constructor\n args:\n - [ *StringType, null ]\n - [ *ObjectType, null ]\n type: *CodeType\n attr: {}\n template: *CodeSymbolTemplate\n argsTemplate: *CodeSymbolArgsTemplate\n ObjectId: &ObjectIdSymbol\n id: \"ObjectId\"\n code: 101\n callable: *constructor\n args:\n - [ *StringType, null ]\n type: *ObjectIdType\n attr:\n fromDate:\n <<: *__func\n id: \"ObjectIdCreateFromTime\"\n args:\n - [ *DateType ]\n type: *ObjectIdType\n template: *ObjectIdCreateFromTimeTemplate\n argsTemplate: *ObjectIdCreateFromTimeArgsTemplate\n template: *ObjectIdSymbolTemplate\n argsTemplate: *ObjectIdSymbolArgsTemplate\n BinData: &BinarySymbol\n id: \"BinData\"\n code: 102\n callable: *constructor\n args:\n - [ *IntegerType ]\n - [ *StringType ]\n type: *BinaryType\n attr: {}\n template: *BinarySymbolTemplate\n argsTemplate: *BinarySymbolArgsTemplate\n DBRef:\n id: \"DBRef\"\n code: 103\n callable: *constructor\n args:\n - [ *StringType ]\n - [ *ObjectIdType ]\n - [ *StringType, null ]\n type: *DBRefType\n attr: {}\n template: *DBRefSymbolTemplate\n argsTemplate: *DBRefSymbolArgsTemplate\n NumberInt:\n id: \"Int32\"\n code: 105\n callable: *constructor\n args:\n - [ *NumericType, *StringType, null ]\n type: *Int32Type\n attr: {}\n template: *Int32SymbolTemplate\n argsTemplate: *Int32SymbolArgsTemplate\n NumberLong:\n id: \"NumberLong\"\n code: 106\n callable: *constructor\n args:\n - [ *IntegerType, *StringType, null ]\n type: *LongType\n attr: {}\n template: *LongSymbolTemplate\n argsTemplate: *LongSymbolArgsTemplate\n MinKey:\n id: \"MinKey\"\n code: 107\n callable: *constructor\n args: []\n type: *MinKeyType\n attr: {}\n template: *MinKeySymbolTemplate\n argsTemplate: *MinKeySymbolArgsTemplate\n MaxKey:\n id: \"MaxKey\"\n code: 108\n callable: *constructor\n args: []\n type: *MaxKeyType\n attr: {}\n template: *MaxKeySymbolTemplate\n argsTemplate: *MaxKeySymbolArgsTemplate\n Timestamp:\n id: \"Timestamp\"\n code: 110\n callable: *constructor\n args:\n - [ *IntegerType, null ]\n - [ *IntegerType, null ]\n type: *TimestampType\n attr: {}\n template: *TimestampSymbolTemplate\n argsTemplate: *TimestampSymbolArgsTemplate\n Symbol:\n id: \"Symbol\"\n code: 111\n callable: *constructor\n args:\n - [ *StringType ]\n type: *SymbolType\n attr: {}\n template: *SymbolSymbolTemplate\n argsTemplate: *SymbolSymbolArgsTemplate\n NumberDecimal:\n id: \"NumberDecimal\"\n code: 112\n callable: *constructor\n args:\n - [ *StringType, *NumericType, null ]\n type: *Decimal128Type\n attr: {}\n template: *Decimal128SymbolTemplate\n argsTemplate: *Decimal128SymbolArgsTemplate\n\nNativeSymbols:\n Number:\n id: \"Number\"\n code: 2\n callable: *constructor\n args:\n - [ *IntegerType, *StringType, null ]\n type: *NumericType\n attr: {} # TODO: no built-in number funcs added yet\n template: *NumberSymbolTemplate\n argsTemplate: *NumberSymbolArgsTemplate\n Date: # Needs emit method\n id: \"Date\"\n code: 200\n callable: *constructor\n args:\n - [ *StringType, *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n type: *DateType\n attr: # TODO: add more date funcs?\n now:\n id: \"now\"\n code: 200.1\n callable: *func\n args: []\n type: *DateType\n attr: {}\n template: *DateSymbolNowTemplate\n argsTemplate: *DateSymbolNowArgsTemplate\n template: *DateSymbolTemplate\n argsTemplate: *DateSymbolArgsTemplate\n ISODate: # Needs emit method\n id: \"ISODate\"\n code: 200\n callable: *constructor\n args:\n - [ *StringType, null ]\n type: *DateType\n attr:\n now:\n id: \"now\"\n callable: *constructor\n args: []\n type: *DateType\n attr: {}\n template: *DateSymbolNowTemplate\n argsTemplate: *DateSymbolNowArgsTemplate\n template: *DateSymbolTemplate\n argsTemplate: *DateSymbolArgsTemplate\n RegExp: # Needs process method\n id: \"RegExp\"\n code: 8\n callable: *constructor\n args:\n - [ *StringType, *RegexType ]\n - [ *StringType, null ]\n type: *RegExpType\n attr: {} # TODO: no built-in regex funcs added yet\n template: *RegExpSymbolTemplate\n argsTemplate: *RegExpSymbolArgsTemplate\n\n"; | ||
module.exports="SymbolTypes:\n VAR: &var 0\n CONSTRUCTOR: &constructor 1\n FUNC: &func 2\n# Internal patterns to save typing\n__type: &__type\n id: null\n callable: *var\n args: null\n type: null\n attr: {}\n template: null\n argsTemplate: null\n__func: &__func\n callable: *func\n args: []\n attr: {}\n template: null\n argsTemplate: null\n\n#############################################\n# Sample Templates #\n# #\n# The expected arguments are commented next #\n# to the template itself. Currently all are #\n# set to null, but to define a function #\n# replace 'null' with '!!js/function > \\n #\n# and a function defined below. #\n# #\n# See the other template files for examples #\n# #\n# Good to know: #\n# lhs is left-hand-side of the expression #\n# rhs is right-hand-side of the expression #\n# All args are strings unless noted #\n# - arg? is boolean #\n# - arg# is number #\n# #\n#############################################\nTemplates:\n ########\n # Misc #\n ########\n\n # Filter out regex flags that have translations or are unsupported.\n RegexFlags: &RegexFlags\n i: 'i'\n m: 'm'\n u: 'u'\n y: 'y'\n g: 'g'\n BSONRegexFlags: &BSONRegexFlags\n i: 'i'\n m: 'm'\n x: 'x'\n s: 's'\n l: 'l'\n u: 'u'\n\n #############################################\n # Syntax #\n # #\n # Templates for language syntax expressions #\n # #\n #############################################\n\n DriverTemplate: &DriverTemplate null\n EqualitySyntaxTemplate: &EqualitySyntaxTemplate !!js/function >\n (lhs, op, rhs) => {\n if (op.includes('!') || op.includes('not')) {\n return lhs !== rhs;\n }\n if (op === '==' || op === '===' || op === 'is') {\n if (typeof(lhs) === 'object' && 'equals' in lhs) {\n // Use '.equals' for objects, if it exists.\n return lhs.equals(rhs);\n }\n return lhs === rhs;\n }\n if (op === '>') {\n return lhs > rhs;\n }\n if (op === '<') {\n return lhs < rhs;\n }\n if (op === '>=') {\n return lhs >= rhs;\n }\n if (op === '<=') {\n return lhs <= rhs;\n }\n throw new Error(`unrecognized operation: ${op}`);\n }\n InSyntaxTemplate: &InSyntaxTemplate !!js/function >\n (lhs, op, rhs) => {\n if (op.includes('!') || op.includes('not')) {\n if (typeof rhs === 'array') {\n return rhs.indexOf(lhs) === -1;\n }\n return !(lhs in rhs);\n }\n if (typeof rhs === 'array') {\n return rhs.indexOf(lhs) !== -1;\n }\n return lhs in rhs;\n }\n\n AndSyntaxTemplate: &AndSyntaxTemplate !!js/function >\n (args) => {\n return args.reduce((t, k, i) => {\n return t && k;\n });\n }\n OrSyntaxTemplate: &OrSyntaxTemplate !!js/function >\n (args) => {\n return args.reduce((t, k, i) => {\n return t || k;\n });\n }\n NotSyntaxTemplate: &NotSyntaxTemplate !!js/function >\n (arg) => {\n return !arg;\n }\n UnarySyntaxTemplate: &UnarySyntaxTemplate !!js/function >\n (op, arg) => {\n switch(op) {\n case '+':\n return +arg;\n case '-':\n return -arg;\n case '~':\n return ~arg;\n default:\n throw new Error(`unrecognized operation: ${op}`);\n }\n }\n BinarySyntaxTemplate: &BinarySyntaxTemplate !!js/function >\n (args) => {\n return args.reduce((s, op, i, arr) => {\n if (i % 2 === 0) {\n return s;\n }\n const rhs = arr[i + 1];\n switch(op) {\n case '+':\n return s + rhs;\n case '-':\n return s - rhs;\n case '*':\n return s * rhs;\n case '/':\n return s / rhs;\n case '**':\n return Math.pow(s, rhs);\n case '//':\n return Math.floor(s, rhs);\n case '%':\n return s % rhs;\n case '>>':\n return s >> rhs;\n case '<<':\n return s << rhs;\n case '|':\n return s | rhs;\n case '&':\n return s & rhs;\n case '^':\n return s ^ rhs;\n default:\n throw new Error(`unrecognized operation: ${op}`);\n }\n }, args[0]);\n }\n ParensSyntaxTemplate: &ParensSyntaxTemplate !!js/function >\n (arg) => {\n return arg;\n }\n EosSyntaxTemplate: &EosSyntaxTemplate !!js/function >\n () => {\n return 'a unique thing';\n }\n EofSyntaxTemplate: &EofSyntaxTemplate !!js/function >\n () => {\n return 'a unique thing';\n }\n FloorDivTemplate: &FloorDivSyntaxTemplate null # Args: lhs, rhs\n PowerTemplate: &PowerSyntaxTemplate null # Args: lhs, rhs\n NewTemplate: &NewSyntaxTemplate null # Args: expression, skip?, code# [to check if meant to be skipped]\n\n #############################################\n # Literal Types #\n # #\n # Templates for literal type instance. Most #\n # get passed the literal itself as an arg. #\n # #\n #############################################\n StringTypeTemplate: &StringTypeTemplate !!js/function >\n (str) => {\n let newStr = str.toString();\n if (\n (newStr.charAt(0) === '\"' && newStr.charAt(newStr.length - 1) === '\"') ||\n (newStr.charAt(0) === '\\'' && newStr.charAt(newStr.length - 1) === '\\'')\n ) {\n newStr = newStr.substr(1, newStr.length - 2);\n }\n return newStr;\n }\n RegexTypeTemplate: &RegexTypeTemplate !!js/function >\n (pattern, flags) => {\n return new RegExp(pattern, flags);\n }\n BoolTypeTemplate: &BoolTypeTemplate !!js/function >\n (str) => {\n return str.toLowerCase() === 'true';\n }\n IntegerTypeTemplate: &IntegerTypeTemplate !!js/function >\n (arg) => {\n return parseInt(arg, 10);\n }\n DecimalTypeTemplate: &DecimalTypeTemplate !!js/function >\n (arg) => {\n return parseFloat(arg);\n }\n LongBasicTypeTemplate: &LongBasicTypeTemplate !!js/function >\n (arg) => {\n return parseInt(arg, 10);\n }\n HexTypeTemplate: &HexTypeTemplate !!js/function >\n (arg) => {\n return parseInt(arg, 16);\n }\n OctalTypeTemplate: &OctalTypeTemplate !!js/function >\n (arg) => {\n arg = arg.replace(/[oO]/g, '')\n return parseInt(arg, 8);\n }\n NumericTypeTemplate: &NumericTypeTemplate !!js/function >\n (arg) => {\n if (arg.contains('x')) {\n return parseInt(arg, 16);\n }\n if (arg.contains('o') || arg.startsWith('0')) {\n arg = arg.replace(/o/g, '')\n return parseInt(arg, 8);\n }\n return parseFloat(arg);\n }\n ArrayTypeTemplate: &ArrayTypeTemplate null\n ArrayTypeArgsTemplate: &ArrayTypeArgsTemplate null # Args: single array element, nestedness, lastElement? (note: not being used atm)\n NullTypeTemplate: &NullTypeTemplate !!js/function >\n () => {\n return null;\n }\n UndefinedTypeTemplate: &UndefinedTypeTemplate !!js/function >\n () => {\n return undefined;\n }\n ObjectTypeTemplate: &ObjectTypeTemplate null # Args: literal (for empty array, is empty string. Otherwise all set)\n ObjectTypeArgsTemplate: &ObjectTypeArgsTemplate null # Args: single object element [2] (i.e. array with [key, value]), nestedness#\n\n #############################################\n # Symbols #\n # #\n # Templates for symbols, can be either #\n # functions or variables. #\n # #\n # The *SymbolTemplates return names and #\n # usually don't take any arguments. The #\n # *SymbolArgsTemplates are invoked for func #\n # calls. The first argument is always the #\n # lhs, i.e. the symbol returned from the #\n # corresponding SymbolTemplate. The rest of #\n # the arguments are the processed arguments #\n # passed to the original function. #\n # #\n #############################################\n CodeSymbolTemplate: &CodeSymbolTemplate null # No args\n CodeSymbolArgsTemplate: &CodeSymbolArgsTemplate null # Args: code, scope\n ObjectIdSymbolTemplate: &ObjectIdSymbolTemplate null # No args\n ObjectIdSymbolArgsTemplate: &ObjectIdSymbolArgsTemplate null # Args: lhs, string (can be empty or null for no arg)\n BinarySymbolTemplate: &BinarySymbolTemplate null\n BinarySymbolArgsTemplate: &BinarySymbolArgsTemplate null\n BinarySymbolSubtypeDefaultTemplate: &BinarySymbolSubtypeDefaultTemplate null\n BinarySymbolSubtypeFunctionTemplate: &BinarySymbolSubtypeFunctionTemplate null\n BinarySymbolSubtypeByteArrayTemplate: &BinarySymbolSubtypeByteArrayTemplate null\n BinarySymbolSubtypeUuidOldTemplate: &BinarySymbolSubtypeUuidOldTemplate null\n BinarySymbolSubtypeUuidTemplate: &BinarySymbolSubtypeUuidTemplate null\n BinarySymbolSubtypeMd5Template: &BinarySymbolSubtypeMd5Template null\n BinarySymbolSubtypeUserDefinedTemplate: &BinarySymbolSubtypeUserDefinedTemplate null\n DBRefSymbolTemplate: &DBRefSymbolTemplate null # No args\n DBRefSymbolArgsTemplate: &DBRefSymbolArgsTemplate null # Args: lhs, coll, id, db\n DoubleSymbolTemplate: &DoubleSymbolTemplate null # No args\n DoubleSymbolArgsTemplate: &DoubleSymbolArgsTemplate null # Args: lhs, arg, argType (i.e. '_string', '_double')\n Int32SymbolTemplate: &Int32SymbolTemplate null # No args\n Int32SymbolArgsTemplate: &Int32SymbolArgsTemplate null # Args: lhs, arg, argType\n LongSymbolTemplate: &LongSymbolTemplate null # No args\n LongSymbolArgsTemplate: &LongSymbolArgsTemplate !!js/function > # Args: lhs, arg, argType\n (lhs, arg) => {\n return lhs.fromNumber(arg);\n }\n RegExpSymbolTemplate: &RegExpSymbolTemplate null # No args\n RegExpSymbolArgsTemplate: &RegExpSymbolArgsTemplate null # Args: lhs, pattern, flags\n SymbolSymbolTemplate: &SymbolSymbolTemplate null # No args\n SymbolSymbolArgsTemplate: &SymbolSymbolArgsTemplate null # Args: lhs, arg\n BSONRegExpSymbolTemplate: &BSONRegExpSymbolTemplate null # No args\n BSONRegExpSymbolArgsTemplate: &BSONRegExpSymbolArgsTemplate null # Args: lhs, pattern, flags\n Decimal128SymbolTemplate: &Decimal128SymbolTemplate null # No args\n Decimal128SymbolArgsTemplate: &Decimal128SymbolArgsTemplate null # Args: lhs, arg\n MinKeySymbolTemplate: &MinKeySymbolTemplate null # No args\n MinKeySymbolArgsTemplate: &MinKeySymbolArgsTemplate null # No args\n MaxKeySymbolTemplate: &MaxKeySymbolTemplate null # No args\n MaxKeySymbolArgsTemplate: &MaxKeySymbolArgsTemplate null # No args\n TimestampSymbolTemplate: &TimestampSymbolTemplate null # No args\n TimestampSymbolArgsTemplate: &TimestampSymbolArgsTemplate null # Args: lhs, low, high\n # non bson-specific\n NumberSymbolTemplate: &NumberSymbolTemplate !!js/function >\n () => {\n return Number;\n }\n NumberSymbolArgsTemplate: &NumberSymbolArgsTemplate null # Args: lhs, arg, argType\n DateSymbolTemplate: &DateSymbolTemplate null # No args\n DateSymbolArgsTemplate: &DateSymbolArgsTemplate !!js/function >\n (lhs, date, isString) => {\n if (isString) {\n return date.toString();\n }\n return date;\n }\n\n #############################################\n # Object Attributes/Methods #\n # #\n # These're variables or functions called on #\n # instantiated objects. For example, #\n # ObjectId().isValid() or Timestamp().t #\n # #\n # They follow the same pattern with the\n # *Template/*ArgsTemplates: usually no args #\n # to the Template and lhs plus any original #\n # arguments to the ArgsTemplate. #\n # #\n #############################################\n CodeCodeTemplate: &CodeCodeTemplate null\n CodeCodeArgsTemplate: &CodeCodeArgsTemplate null\n CodeScopeTemplate: &CodeScopeTemplate null\n CodeScopeArgsTemplate: &CodeScopeArgsTemplate null\n ObjectIdToStringTemplate: &ObjectIdToStringTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.toString();\n }\n ObjectIdToStringArgsTemplate: &ObjectIdToStringArgsTemplate !!js/function >\n (lhs) => {\n return lhs;\n }\n ObjectIdEqualsTemplate: &ObjectIdEqualsTemplate !!js/function >\n (lhs) => {\n return lhs;\n }\n ObjectIdEqualsArgsTemplate: &ObjectIdEqualsArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.equals(rhs);\n }\n ObjectIdGetTimestampTemplate: &ObjectIdGetTimestampTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.getTimestamp();\n }\n ObjectIdGetTimestampArgsTemplate: &ObjectIdGetTimestampArgsTemplate !!js/function >\n (lhs) => {\n return lhs;\n }\n ObjectIdIsValidTemplate: &ObjectIdIsValidTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.isValid;\n }\n ObjectIdIsValidArgsTemplate: &ObjectIdIsValidArgsTemplate null\n BinaryValueTemplate: &BinaryValueTemplate null\n BinaryValueArgsTemplate: &BinaryValueArgsTemplate null\n BinaryLengthTemplate: &BinaryLengthTemplate null\n BinaryLengthArgsTemplate: &BinaryLengthArgsTemplate null\n BinaryToStringTemplate: &BinaryToStringTemplate null\n BinaryToStringArgsTemplate: &BinaryToStringArgsTemplate null\n BinarySubtypeTemplate: &BinarySubtypeTemplate null\n BinarySubtypeArgsTemplate: &BinarySubtypeArgsTemplate null\n DBRefGetDBTemplate: &DBRefGetDBTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.db;\n }\n DBRefGetCollectionTemplate: &DBRefGetCollectionTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.collection;\n }\n DBRefGetIdTemplate: &DBRefGetIdTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.oid;\n }\n DBRefGetDBArgsTemplate: &DBRefGetDBArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n DBRefGetCollectionArgsTemplate: &DBRefGetCollectionArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n DBRefGetIdArgsTemplate: &DBRefGetIdArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n LongEqualsTemplate: &LongEqualsTemplate null\n LongEqualsArgsTemplate: &LongEqualsArgsTemplate null\n LongToStringTemplate: &LongToStringTemplate null\n LongToStringArgsTemplate: &LongToStringArgsTemplate null\n LongToIntTemplate: &LongToIntTemplate null\n LongToIntArgsTemplate: &LongToIntArgsTemplate null\n LongValueOfTemplate: &LongValueOfTemplate null\n LongValueOfArgsTemplate: &LongValueOfArgsTemplate null\n LongToNumberTemplate: &LongToNumberTemplate null\n LongToNumberArgsTemplate: &LongToNumberArgsTemplate null\n LongAddTemplate: &LongAddTemplate null\n LongAddArgsTemplate: &LongAddArgsTemplate null\n LongSubtractTemplate: &LongSubtractTemplate null\n LongSubtractArgsTemplate: &LongSubtractArgsTemplate null\n LongMultiplyTemplate: &LongMultiplyTemplate null\n LongMultiplyArgsTemplate: &LongMultiplyArgsTemplate null\n LongDivTemplate: &LongDivTemplate null\n LongDivArgsTemplate: &LongDivArgsTemplate null\n LongModuloTemplate: &LongModuloTemplate null\n LongModuloArgsTemplate: &LongModuloArgsTemplate null\n LongAndTemplate: &LongAndTemplate null\n LongAndArgsTemplate: &LongAndArgsTemplate null\n LongOrTemplate: &LongOrTemplate null\n LongOrArgsTemplate: &LongOrArgsTemplate null\n LongXorTemplate: &LongXorTemplate null\n LongXorArgsTemplate: &LongXorArgsTemplate null\n LongShiftLeftTemplate: &LongShiftLeftTemplate null\n LongShiftLeftArgsTemplate: &LongShiftLeftArgsTemplate null\n LongShiftRightTemplate: &LongShiftRightTemplate null\n LongShiftRightArgsTemplate: &LongShiftRightArgsTemplate null\n LongCompareTemplate: &LongCompareTemplate null\n LongCompareArgsTemplate: &LongCompareArgsTemplate null\n LongIsOddTemplate: &LongIsOddTemplate null\n LongIsOddArgsTemplate: &LongIsOddArgsTemplate null\n LongIsZeroTemplate: &LongIsZeroTemplate null\n LongIsZeroArgsTemplate: &LongIsZeroArgsTemplate null\n LongIsNegativeTemplate: &LongIsNegativeTemplate null\n LongIsNegativeArgsTemplate: &LongIsNegativeArgsTemplate null\n LongNegateTemplate: &LongNegateTemplate null\n LongNegateArgsTemplate: &LongNegateArgsTemplate null\n LongNotTemplate: &LongNotTemplate null\n LongNotArgsTemplate: &LongNotArgsTemplate null\n LongNotEqualsTemplate: &LongNotEqualsTemplate null\n LongNotEqualsArgsTemplate: &LongNotEqualsArgsTemplate null\n LongGreaterThanTemplate: &LongGreaterThanTemplate null\n LongGreaterThanArgsTemplate: &LongGreaterThanArgsTemplate null\n LongGreaterThanOrEqualTemplate: &LongGreaterThanOrEqualTemplate null\n LongGreaterThanOrEqualArgsTemplate: &LongGreaterThanOrEqualArgsTemplate null\n LongLessThanTemplate: &LongLessThanTemplate null\n LongLessThanArgsTemplate: &LongLessThanArgsTemplate null\n LongLessThanOrEqualTemplate: &LongLessThanOrEqualTemplate null\n LongLessThanOrEqualArgsTemplate: &LongLessThanOrEqualArgsTemplate null\n LongFloatApproxTemplate: &LongFloatApproxTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.toNumber();\n }\n LongTopTemplate: &LongTopTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.high;\n }\n LongBottomTemplate: &LongBottomTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.low;\n }\n TimestampToStringTemplate: &TimestampToStringTemplate null\n TimestampToStringArgsTemplate: &TimestampToStringArgsTemplate null\n TimestampEqualsTemplate: &TimestampEqualsTemplate null\n TimestampEqualsArgsTemplate: &TimestampEqualsArgsTemplate null\n TimestampGetLowBitsTemplate: &TimestampGetLowBitsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.getLowBits();\n }\n TimestampGetLowBitsArgsTemplate: &TimestampGetLowBitsArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n TimestampGetHighBitsTemplate: &TimestampGetHighBitsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.getHighBits();\n }\n TimestampGetHighBitsArgsTemplate: &TimestampGetHighBitsArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n TimestampTTemplate: &TimestampTTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.getLowBits();\n }\n TimestampITemplate: &TimestampITemplate !!js/function >\n (lhs, rhs) => {\n return lhs.getHighBits();\n }\n TimestampAsDateTemplate: &TimestampAsDateTemplate !!js/function >\n (lhs, rhs) => {\n return new Date(lhs.getHighBits() * 1000);\n }\n TimestampAsDateArgsTemplate: &TimestampAsDateArgsTemplate !!js/function >\n (lhs, rhs) => {\n return lhs;\n }\n TimestampCompareTemplate: &TimestampCompareTemplate null\n TimestampCompareArgsTemplate: &TimestampCompareArgsTemplate null\n TimestampNotEqualsTemplate: &TimestampNotEqualsTemplate null\n TimestampNotEqualsArgsTemplate: &TimestampNotEqualsArgsTemplate null\n TimestampGreaterThanTemplate: &TimestampGreaterThanTemplate null\n TimestampGreaterThanArgsTemplate: &TimestampGreaterThanArgsTemplate null\n TimestampGreaterThanOrEqualTemplate: &TimestampGreaterThanOrEqualTemplate null\n TimestampGreaterThanOrEqualArgsTemplate: &TimestampGreaterThanOrEqualArgsTemplate null\n TimestampLessThanTemplate: &TimestampLessThanTemplate null\n TimestampLessThanArgsTemplate: &TimestampLessThanArgsTemplate null\n TimestampLessThanOrEqualTemplate: &TimestampLessThanOrEqualTemplate null\n TimestampLessThanOrEqualArgsTemplate: &TimestampLessThanOrEqualArgsTemplate null\n SymbolValueOfTemplate: &SymbolValueOfTemplate null\n SymbolValueOfArgsTemplate: &SymbolValueOfArgsTemplate null\n SymbolInspectTemplate: &SymbolInspectTemplate null\n SymbolInspectArgsTemplate: &SymbolInspectArgsTemplate null\n SymbolToStringTemplate: &SymbolToStringTemplate null\n SymbolToStringArgsTemplate: &SymbolToStringArgsTemplate null\n Decimal128ToStringTemplate: &Decimal128ToStringTemplate null\n Decimal128ToStringArgsTemplate: &Decimal128ToStringArgsTemplate null\n # non bson-specific\n DateSymbolNowTemplate: &DateSymbolNowTemplate !!js/function >\n () => {\n return Date.now;\n }\n DateSymbolNowArgsTemplate: &DateSymbolNowArgsTemplate null\n\n #############################################\n # Symbol Attributes/Methods #\n # #\n # These're variables or functions called on #\n # symbols. Also called bson-utils. #\n # #\n # They are basically the same thing as #\n # object attributes/methods, but need to be #\n # distinguished since they are separate #\n # namespaces that happen to have the same #\n # name which is v confusing. #\n # #\n # For example, ObjectId().toString() is an #\n # object method, while ObjectId.fromString #\n # is a symbol attribute. These are two #\n # separate ObjectId related namespaces that #\n # don't overlap. #\n # #\n #############################################\n LongSymbolMaxTemplate: &LongSymbolMaxTemplate null\n LongSymbolMaxArgsTemplate: &LongSymbolMaxArgsTemplate null\n LongSymbolMinTemplate: &LongSymbolMinTemplate null\n LongSymbolMinArgsTemplate: &LongSymbolMinArgsTemplate null\n LongSymbolZeroTemplate: &LongSymbolZeroTemplate null\n LongSymbolZeroArgsTemplate: &LongSymbolZeroArgsTemplate null\n LongSymbolOneTemplate: &LongSymbolOneTemplate null\n LongSymbolOneArgsTemplate: &LongSymbolOneArgsTemplate null\n LongSymbolNegOneTemplate: &LongSymbolNegOneTemplate null\n LongSymbolNegOneArgsTemplate: &LongSymbolNegOneArgsTemplate null\n LongSymbolFromBitsTemplate: &LongSymbolFromBitsTemplate null\n LongSymbolFromBitsArgsTemplate: &LongSymbolFromBitsArgsTemplate null\n LongSymbolFromIntTemplate: &LongSymbolFromIntTemplate null\n LongSymbolFromIntArgsTemplate: &LongSymbolFromIntArgsTemplate null\n LongSymbolFromNumberTemplate: &LongSymbolFromNumberTemplate null\n LongSymbolFromNumberArgsTemplate: &LongSymbolFromNumberArgsTemplate null\n LongSymbolFromStringTemplate: &LongSymbolFromStringTemplate null\n LongSymbolFromStringArgsTemplate: &LongSymbolFromStringArgsTemplate null\n Decimal128SymbolFromStringTemplate: &Decimal128SymbolFromStringTemplate null\n Decimal128SymbolFromStringArgsTemplate: &Decimal128SymbolFromStringArgsTemplate null\n ObjectIdCreateFromHexStringTemplate: &ObjectIdCreateFromHexStringTemplate null\n ObjectIdCreateFromHexStringArgsTemplate: &ObjectIdCreateFromHexStringArgsTemplate null\n ObjectIdCreateFromTimeTemplate: &ObjectIdCreateFromTimeTemplate !!js/function >\n (lhs, rhs) => {\n return lhs.createFromTime;\n }\n ObjectIdCreateFromTimeArgsTemplate: &ObjectIdCreateFromTimeArgsTemplate null\n # non bson-specific would go here, but there aren't any atm.\n\n #############################################\n # Imports #\n # #\n # Each type has a 'code' that is consistent #\n # between languages. The import templates #\n # for each code generate the required #\n # statement for each type. No args. #\n # #\n # The ImportTemplate collects everything #\n # into one statement. #\n # #\n #############################################\n ImportTemplate: &ImportTemplate null\n DriverImportTemplate: &DriverImportTemplate null\n 0ImportTemplate: &0ImportTemplate null\n 1ImportTemplate: &1ImportTemplate null\n 2ImportTemplate: &2ImportTemplate null\n 3ImportTemplate: &3ImportTemplate null\n 4ImportTemplate: &4ImportTemplate null\n 5ImportTemplate: &5ImportTemplate null\n 6ImportTemplate: &6ImportTemplate null\n 7ImportTemplate: &7ImportTemplate null\n 8ImportTemplate: &8ImportTemplate null\n 9ImportTemplate: &9ImportTemplate null\n 10ImportTemplate: &10ImportTemplate null\n 11ImportTemplate: &11ImportTemplate null\n 12ImportTemplate: &12ImportTemplate null\n 100ImportTemplate: &100ImportTemplate null\n 101ImportTemplate: &101ImportTemplate null\n 102ImportTemplate: &102ImportTemplate null\n 103ImportTemplate: &103ImportTemplate null\n 104ImportTemplate: &104ImportTemplate null\n 105ImportTemplate: &105ImportTemplate null\n 106ImportTemplate: &106ImportTemplate null\n 107ImportTemplate: &107ImportTemplate null\n 108ImportTemplate: &108ImportTemplate null\n 109ImportTemplate: &109ImportTemplate null\n 110ImportTemplate: &110ImportTemplate null\n 111ImportTemplate: &111ImportTemplate null\n 112ImportTemplate: &112ImportTemplate null\n 113ImportTemplate: &113ImportTemplate null\n 114ImportTemplate: &114ImportTemplate null\n 200ImportTemplate: &200ImportTemplate null\n 201ImportTemplate: &201ImportTemplate null\n 300ImportTemplate: &300ImportTemplate null\n 301ImportTemplate: &301ImportTemplate null\n 302ImportTemplate: &302ImportTemplate null\n 303ImportTemplate: &303ImportTemplate null\n 304ImportTemplate: &304ImportTemplate null\n 305ImportTemplate: &305ImportTemplate null\n 306ImportTemplate: &306ImportTemplate null\n# Universal types\n# Everything inherits from StringType because we haven't implemented any of them.\nBasicTypes:\n # Universal basic types\n _bool: &BoolType\n <<: *__type\n id: \"_bool\"\n code: 0\n template: *BoolTypeTemplate\n _integer: &IntegerType\n <<: *__type\n id: \"_integer\"\n code: 1\n template: *IntegerTypeTemplate\n _long: &LongBasicType\n <<: *__type\n id: \"_long\"\n code: 2\n template: *LongBasicTypeTemplate\n _decimal: &DecimalType\n <<: *__type\n id: \"_decimal\"\n code: 3\n template: *DecimalTypeTemplate\n _hex: &HexType\n <<: *__type\n id: \"_hex\"\n code: 4\n template: *HexTypeTemplate\n _octal: &OctalType\n <<: *__type\n id: \"_octal\"\n code: 5\n template: *OctalTypeTemplate\n _numeric: &NumericType\n <<: *__type\n id: \"_numeric\"\n code: 6\n template: *NumericTypeTemplate\n _string: &StringType\n <<: *__type\n id: \"_string\"\n code: 7\n template: *StringTypeTemplate\n _regex: &RegexType\n <<: *__type\n id: \"_regex\"\n code: 8\n template: *RegexTypeTemplate\n _array: &ArrayType\n <<: *__type\n id: \"_array\"\n code: 9\n template: *ArrayTypeTemplate\n argsTemplate: *ArrayTypeArgsTemplate\n _object: &ObjectType\n <<: *__type\n id: \"_object\"\n code: 10\n template: *ObjectTypeTemplate\n argsTemplate: *ObjectTypeArgsTemplate\n _null: &NullType\n <<: *__type\n id: \"_null\"\n code: 11\n template: *NullTypeTemplate\n _undefined: &UndefinedType\n <<: *__type\n id: \"_undefined\"\n code: 12\n template: *UndefinedTypeTemplate\n\nSyntax:\n equality:\n template: *EqualitySyntaxTemplate\n in:\n template: *InSyntaxTemplate\n and:\n template: *AndSyntaxTemplate\n or:\n template: *OrSyntaxTemplate\n not:\n template: *NotSyntaxTemplate\n unary:\n template: *UnarySyntaxTemplate\n binary:\n template: *BinarySyntaxTemplate\n parens:\n template: *ParensSyntaxTemplate\n eos:\n template: *EosSyntaxTemplate\n eof:\n template: *EofSyntaxTemplate\n # The new template takes in expr, and an optional skip argument and optional\n # id argument. The skip argument is a boolean that if true then doesn't add\n # new. The code argument is the symbol code being called. The template will check\n # if it is an exception, i.e. a type that is a constructor but may not use new.\n new:\n template: *NewSyntaxTemplate\n # The regex flags that change symbols between languages can be defined here.\n # Flags that aren't defined can be left blank and will be ignored.\n regexFlags: *RegexFlags\n bsonRegexFlags: *BSONRegexFlags\n driver: *DriverTemplate\nImports:\n import:\n template: *ImportTemplate\n driver:\n template: *DriverImportTemplate\n 0:\n template: *0ImportTemplate\n 1:\n template: *1ImportTemplate\n 2:\n template: *2ImportTemplate\n 3:\n template: *3ImportTemplate\n 4:\n template: *4ImportTemplate\n 5:\n template: *5ImportTemplate\n 6:\n template: *6ImportTemplate\n 7:\n template: *7ImportTemplate\n 8:\n template: *8ImportTemplate\n 9:\n template: *9ImportTemplate\n 10:\n template: *10ImportTemplate\n 11:\n template: *11ImportTemplate\n 12:\n template: *12ImportTemplate\n 100:\n template: *100ImportTemplate\n 101:\n template: *101ImportTemplate\n 102:\n template: *102ImportTemplate\n 103:\n template: *103ImportTemplate\n 104:\n template: *104ImportTemplate\n 105:\n template: *105ImportTemplate\n 106:\n template: *106ImportTemplate\n 107:\n template: *107ImportTemplate\n 108:\n template: *108ImportTemplate\n 109:\n template: *109ImportTemplate\n 110:\n template: *110ImportTemplate\n 111:\n template: *111ImportTemplate\n 112:\n template: *112ImportTemplate\n 113:\n template: *113ImportTemplate\n 114:\n template: *114ImportTemplate\n 200:\n template: *200ImportTemplate\n 201:\n template: *201ImportTemplate\n 300:\n template: *300ImportTemplate\n 301:\n template: *301ImportTemplate\n 302:\n template: *302ImportTemplate\n 303:\n template: *303ImportTemplate\n 304:\n template: *304ImportTemplate\n 305:\n template: *305ImportTemplate\n 306:\n template: *306ImportTemplate\nBsonTypes:\n Code: &CodeType\n <<: *__type\n id: \"Code\"\n code: 100\n type: *ObjectType\n attr:\n code:\n callable: *var\n args: null\n attr: null\n id: \"code\"\n type: *StringType\n template: *CodeCodeTemplate\n argsTemplate: *CodeCodeArgsTemplate\n scope:\n callable: *var\n args: null\n attr: null\n id: \"scope\"\n type: *StringType\n template: *CodeScopeTemplate\n argsTemplate: *CodeScopeArgsTemplate\n ObjectId: &ObjectIdType\n <<: *__type\n id: \"ObjectId\"\n code: 101\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *ObjectIdToStringTemplate\n argsTemplate: *ObjectIdToStringArgsTemplate\n equals:\n <<: *__func\n id: \"equals\"\n args:\n - [ \"ObjectId\" ]\n type: *BoolType\n template: *ObjectIdEqualsTemplate\n argsTemplate: *ObjectIdEqualsArgsTemplate\n getTimestamp:\n <<: *__func\n id: \"getTimestamp\"\n type: *IntegerType\n template: *ObjectIdGetTimestampTemplate\n argsTemplate: *ObjectIdGetTimestampArgsTemplate\n BinData: &BinaryType\n <<: *__type\n id: \"BinData\"\n code: 102\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *BinaryToStringTemplate\n argsTemplate: *BinaryToStringArgsTemplate\n base64:\n <<: *__func\n id: \"base64\"\n type: *StringType\n template: *BinaryValueTemplate\n argsTemplate: *BinaryValueArgsTemplate\n length:\n <<: *__func\n id: \"length\"\n type: *IntegerType\n template: *BinaryLengthTemplate\n argsTemplate: *BinaryLengthArgsTemplate\n subtype:\n <<: *__func\n id: \"subtype\"\n type: *IntegerType\n template: *BinarySubtypeTemplate\n argsTemplate: *BinarySubtypeArgsTemplate\n DBRef: &DBRefType\n <<: *__type\n id: \"DBRef\"\n code: 103\n type: *ObjectType\n attr:\n getDb:\n <<: *__func\n id: \"getDb\"\n type: *StringType\n template: *DBRefGetDBTemplate\n argsTemplate: *DBRefGetDBArgsTemplate\n $db:\n callable: *var\n args: null\n attr: null\n id: \"$db\"\n type: *StringType\n template: *DBRefGetDBTemplate\n argsTemplate: *DBRefGetDBArgsTemplate\n getCollection:\n <<: *__func\n id: \"getCollection\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n getRef:\n <<: *__func\n id: \"getRef\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n $ref:\n callable: *var\n args: null\n attr: null\n id: \"$ref\"\n type: *StringType\n template: *DBRefGetCollectionTemplate\n argsTemplate: *DBRefGetCollectionArgsTemplate\n getId:\n <<: *__func\n id: \"getId\"\n type: *StringType\n template: *DBRefGetIdTemplate\n argsTemplate: *DBRefGetIdArgsTemplate\n $id:\n callable: *var\n args: null\n attr: null\n id: \"$id\"\n type: *StringType\n template: *DBRefGetIdTemplate\n argsTemplate: *DBRefGetIdArgsTemplate\n NumberInt: &Int32Type\n <<: *__type\n id: \"NumberInt\"\n code: 105\n type: *ObjectType\n attr: {}\n NumberLong: &LongType\n <<: *__type\n id: \"NumberLong\"\n code: 106\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"LongtoString\" # Needs process method\n args:\n - [ *IntegerType, null ]\n type: *StringType\n template: *LongToStringTemplate\n argsTemplate: *LongToStringArgsTemplate\n equals:\n <<: *__func\n id: \"equals\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongEqualsTemplate\n argsTemplate: *LongEqualsArgsTemplate\n toInt:\n <<: *__func\n id: \"toInt\"\n type: *IntegerType\n template: *LongToIntTemplate\n argsTemplate: *LongToIntArgsTemplate\n toNumber:\n <<: *__func\n id: \"toNumber\"\n type: *DecimalType\n template: *LongToNumberTemplate\n argsTemplate: *LongToNumberArgsTemplate\n compare:\n <<: *__func\n id: \"compare\"\n args:\n - [ \"Long\" ]\n type: *StringType\n template: *LongCompareTemplate\n argsTemplate: *LongCompareArgsTemplate\n isOdd:\n <<: *__func\n id: \"isOdd\"\n type: *BoolType\n template: *LongIsOddTemplate\n argsTemplate: *LongIsOddArgsTemplate\n isZero:\n <<: *__func\n id: \"isZero\"\n type: *BoolType\n template: *LongIsZeroTemplate\n argsTemplate: *LongIsZeroArgsTemplate\n isNegative:\n <<: *__func\n id: \"isNegative\"\n type: *BoolType\n template: *LongIsNegativeTemplate\n argsTemplate: *LongIsNegativeArgsTemplate\n negate:\n <<: *__func\n id: \"negate\"\n type: \"Long\"\n template: *LongNegateTemplate\n argsTemplate: *LongNegateArgsTemplate\n not:\n <<: *__func\n id: \"not\"\n type: \"Long\"\n template: *LongNotTemplate\n argsTemplate: *LongNotArgsTemplate\n notEquals:\n <<: *__func\n id: \"notEquals\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongNotEqualsTemplate\n argsTemplate: *LongNotEqualsArgsTemplate\n greaterThan:\n <<: *__func\n id: \"greaterThan\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongGreaterThanTemplate\n argsTemplate: *LongGreaterThanArgsTemplate\n greaterThanOrEqual:\n <<: *__func\n id: \"greaterThanOrEqual\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongGreaterThanOrEqualTemplate\n argsTemplate: *LongGreaterThanOrEqualArgsTemplate\n lessThan:\n <<: *__func\n id: \"lessThan\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongLessThanTemplate\n argsTemplate: *LongLessThanArgsTemplate\n lessThanOrEqual:\n <<: *__func\n id: \"lessThanOrEqual\"\n args:\n - [ \"Long\" ]\n type: *BoolType\n template: *LongLessThanOrEqualTemplate\n argsTemplate: *LongLessThanOrEqualArgsTemplate\n add:\n <<: *__func\n id: \"add\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongAddTemplate\n argsTemplate: *LongAddArgsTemplate\n subtract:\n <<: *__func\n id: \"subtract\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongSubtractTemplate\n argsTemplate: *LongSubtractArgsTemplate\n multiply:\n <<: *__func\n id: \"multiply\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongMultiplyTemplate\n argsTemplate: *LongMultiplyArgsTemplate\n div:\n <<: *__func\n id: \"div\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongDivTemplate\n argsTemplate: *LongDivArgsTemplate\n modulo:\n <<: *__func\n id: \"modulo\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongModuloTemplate\n argsTemplate: *LongModuloArgsTemplate\n and:\n <<: *__func\n id: \"and\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongAndTemplate\n argsTemplate: *LongAndArgsTemplate\n or:\n <<: *__func\n id: \"or\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongOrTemplate\n argsTemplate: *LongOrArgsTemplate\n xor:\n <<: *__func\n id: \"xor\"\n args:\n - [ \"Long\" ]\n type: \"Long\"\n template: *LongXorTemplate\n argsTemplate: *LongXorArgsTemplate\n shiftLeft:\n <<: *__func\n id: \"shiftLeft\"\n args:\n - [ *IntegerType ]\n type: \"Long\"\n template: *LongShiftLeftTemplate\n argsTemplate: *LongShiftLeftArgsTemplate\n shiftRight:\n <<: *__func\n id: \"shiftRight\"\n args:\n - [ *IntegerType ]\n type: \"Long\"\n template: *LongShiftRightTemplate\n argsTemplate: *LongShiftRightArgsTemplate\n MinKeyType: &MinKeyType\n <<: *__type\n id: \"MinKey\"\n code: 107\n type: *ObjectType\n MaxKeyType: &MaxKeyType\n <<: *__type\n id: \"MaxKey\"\n code: 108\n type: *ObjectType\n Timestamp: &TimestampType\n <<: *__type\n id: \"Timestamp\"\n code: 110\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *TimestampToStringTemplate\n argsTemplate: *TimestampToStringArgsTemplate\n equals:\n <<: *__func\n id: \"equals\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampEqualsTemplate\n argsTemplate: *TimestampEqualsArgsTemplate\n getLowBits:\n <<: *__func\n id: \"getLowBits\"\n type: *IntegerType\n template: *TimestampGetLowBitsTemplate\n argsTemplate: *TimestampGetLowBitsArgsTemplate\n getHighBits:\n <<: *__func\n id: \"getHighBits\"\n type: *IntegerType\n template: *TimestampGetHighBitsTemplate\n argsTemplate: *TimestampGetHighBitsArgsTemplate\n compare:\n <<: *__func\n id: \"compare\"\n args:\n - [ \"Timestamp\" ]\n type: *StringType\n template: *TimestampCompareTemplate\n argsTemplate: *TimestampCompareArgsTemplate\n notEquals:\n <<: *__func\n id: \"notEquals\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampNotEqualsTemplate\n argsTemplate: *TimestampNotEqualsArgsTemplate\n greaterThan:\n <<: *__func\n id: \"greaterThan\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampGreaterThanTemplate\n argsTemplate: *TimestampGreaterThanArgsTemplate\n greaterThanOrEqual:\n <<: *__func\n id: \"greaterThanOrEqual\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampGreaterThanOrEqualTemplate\n argsTemplate: *TimestampGreaterThanOrEqualArgsTemplate\n lessThan:\n <<: *__func\n id: \"lessThan\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampLessThanTemplate\n argsTemplate: *TimestampLessThanArgsTemplate\n lessThanOrEqual:\n <<: *__func\n id: \"lessThanOrEqual\"\n args:\n - [ \"Timestamp\" ]\n type: *BoolType\n template: *TimestampLessThanOrEqualTemplate\n argsTemplate: *TimestampLessThanOrEqualArgsTemplate\n BSONSymbol: &SymbolType\n <<: *__type\n id: \"BSONSymbol\"\n code: 111\n type: *ObjectType\n attr:\n valueOf:\n <<: *__func\n id: \"valueOf\"\n type: *StringType\n template: *SymbolValueOfTemplate\n argsTemplate: *SymbolValueOfArgsTemplate\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *SymbolToStringTemplate\n argsTemplate: *SymbolToStringArgsTemplate\n inspect:\n <<: *__func\n id: \"inspect\"\n type: *StringType\n template: *SymbolInspectTemplate\n argsTemplate: *SymbolInspectArgsTemplate\n Double: &DoubleType\n <<: *__type\n id: \"Double\"\n code: 104\n type: *ObjectType\n attr: {}\n Decimal128: &Decimal128Type\n <<: *__type\n id: \"Decimal128\"\n code: 112\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *Decimal128ToStringTemplate\n argsTemplate: *Decimal128ToStringArgsTemplate\n NumberDecimal: &NumberDecimalType\n <<: *__type\n id: \"NumberDecimal\"\n code: 112\n type: *ObjectType\n attr:\n toString:\n <<: *__func\n id: \"toString\"\n type: *StringType\n template: *Decimal128ToStringTemplate\n argsTemplate: *Decimal128ToStringArgsTemplate\n\n\n SUBTYPE_DEFAULT:\n id: \"SUBTYPE_DEFAULT\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeDefaultTemplate\n SUBTYPE_FUNCTION:\n id: \"SUBTYPE_FUNCTION\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeFunctionTemplate\n SUBTYPE_BYTE_ARRAY:\n id: \"SUBTYPE_BYTE_ARRAY\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeByteArrayTemplate\n SUBTYPE_UUID_OLD:\n id: \"SUBTYPE_UUID_OLD\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUuidOldTemplate\n SUBTYPE_UUID:\n id: \"SUBTYPE_UUID\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUuidTemplate\n SUBTYPE_MD5:\n id: \"SUBTYPE_MD5\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeMd5Template\n SUBTYPE_USER_DEFINED:\n id: \"SUBTYPE_USER_DEFINED\"\n callable: *var\n args: null\n code: 113\n type: *IntegerType\n template: *BinarySymbolSubtypeUserDefinedTemplate\n BSONRegExpType: &BSONRegExpType\n <<: *__type\n id: \"BSONRegExp\"\n code: 109\n type: *ObjectType\nNativeTypes:\n Date: &DateType\n <<: *__type\n id: \"Date\"\n code: 200\n type: *ObjectType\n attr: {} # TODO: no built-in date methods added yet\n RegExp: &RegExpType\n <<: *__type\n id: \"RegExp\"\n code: 8\n type: *ObjectType\n attr: {}\n\n\nBsonSymbols:\n Code: &CodeSymbol\n id: \"Code\"\n code: 100\n callable: *constructor\n args:\n - [ *StringType, null ]\n - [ *ObjectType, null ]\n type: *CodeType\n attr: {}\n template: *CodeSymbolTemplate\n argsTemplate: *CodeSymbolArgsTemplate\n ObjectId: &ObjectIdSymbol\n id: \"ObjectId\"\n code: 101\n callable: *constructor\n args:\n - [ *StringType, *NumericType, null ]\n type: *ObjectIdType\n attr:\n createFromHexString:\n <<: *__func\n id: \"createFromHexString\"\n args:\n - [ *StringType ]\n type: *ObjectIdType\n template: *ObjectIdCreateFromHexStringTemplate\n argsTemplate: *ObjectIdCreateFromHexStringArgsTemplate\n createFromTime:\n <<: *__func\n id: \"ObjectIdCreateFromTime\"\n args:\n - [ *NumericType, *DateType ]\n type: *ObjectIdType\n template: *ObjectIdCreateFromTimeTemplate\n argsTemplate: *ObjectIdCreateFromTimeArgsTemplate\n isValid:\n <<: *__func\n id: \"isValid\"\n args:\n - [ *StringType ]\n type: *BoolType\n template: *ObjectIdIsValidTemplate\n argsTemplate: *ObjectIdIsValidArgsTemplate\n template: *ObjectIdSymbolTemplate\n argsTemplate: *ObjectIdSymbolArgsTemplate\n BinData: &BinarySymbol\n id: \"BinData\"\n code: 102\n callable: *constructor\n args:\n - [ *IntegerType ]\n - [ *StringType ]\n type: *BinaryType\n attr: {}\n template: *BinarySymbolTemplate\n argsTemplate: *BinarySymbolArgsTemplate\n DBRef:\n id: \"DBRef\"\n code: 103\n callable: *constructor\n args:\n - [ *StringType ]\n - [ *ObjectIdType ]\n - [ *StringType, null ]\n type: *DBRefType\n attr: {}\n template: *DBRefSymbolTemplate\n argsTemplate: *DBRefSymbolArgsTemplate\n NumberInt:\n id: \"Int32\"\n code: 105\n callable: *constructor\n args:\n - [ *NumericType, *StringType, null ]\n type: *Int32Type\n attr: {}\n template: *Int32SymbolTemplate\n argsTemplate: *Int32SymbolArgsTemplate\n NumberLong:\n id: \"NumberLong\"\n code: 106\n callable: *constructor\n args:\n - [ *IntegerType, *StringType, null ]\n type: *LongType\n attr: {}\n template: *LongSymbolTemplate\n argsTemplate: *LongSymbolArgsTemplate\n MinKey:\n id: \"MinKey\"\n code: 107\n callable: *constructor\n args: []\n type: *MinKeyType\n attr: {}\n template: *MinKeySymbolTemplate\n argsTemplate: *MinKeySymbolArgsTemplate\n MaxKey:\n id: \"MaxKey\"\n code: 108\n callable: *constructor\n args: []\n type: *MaxKeyType\n attr: {}\n template: *MaxKeySymbolTemplate\n argsTemplate: *MaxKeySymbolArgsTemplate\n Timestamp:\n id: \"Timestamp\"\n code: 110\n callable: *constructor\n args:\n - [ *IntegerType, null ]\n - [ *IntegerType, null ]\n type: *TimestampType\n attr: {}\n template: *TimestampSymbolTemplate\n argsTemplate: *TimestampSymbolArgsTemplate\n Symbol:\n id: \"Symbol\"\n code: 111\n callable: *constructor\n args:\n - [ *StringType ]\n type: *SymbolType\n attr: {}\n template: *SymbolSymbolTemplate\n argsTemplate: *SymbolSymbolArgsTemplate\n NumberDecimal:\n id: \"NumberDecimal\"\n code: 112\n callable: *constructor\n args:\n - [ *StringType, *NumericType, null ]\n type: *Decimal128Type\n attr: {}\n template: *Decimal128SymbolTemplate\n argsTemplate: *Decimal128SymbolArgsTemplate\n BSONRegExp:\n id: \"BSONRegExp\"\n code: 109\n callable: *constructor\n args:\n - [ *StringType ]\n - [ *StringType, null ]\n type: *BSONRegExpType\n attr: {}\n template: *BSONRegExpSymbolTemplate\n argsTemplate: *BSONRegExpSymbolArgsTemplate\n BSONSymbol:\n id: \"BSONSymbol\"\n code: 111\n callable: *constructor\n args:\n - [ *StringType ]\n type: *SymbolType\n attr: {}\n template: *SymbolSymbolTemplate\n argsTemplate: *SymbolSymbolArgsTemplate\n Decimal128:\n id: \"Decimal128\"\n code: 112\n callable: *constructor\n args:\n - [ *ObjectType ]\n type: *Decimal128Type\n attr:\n fromString:\n id: \"fromString\"\n callable: *func\n args:\n - [ *StringType ]\n type: *Decimal128Type\n attr: {}\n template: *Decimal128SymbolFromStringTemplate\n argsTemplate: *Decimal128SymbolFromStringArgsTemplate\n template: *Decimal128SymbolTemplate\n argsTemplate: *Decimal128SymbolArgsTemplate\n Double:\n id: \"Double\"\n code: 104\n callable: *constructor\n args:\n - [ *NumericType, *StringType ]\n type: *DoubleType\n attr: {}\n template: *DoubleSymbolTemplate\n argsTemplate: *DoubleSymbolArgsTemplate\n Int32:\n id: \"Int32\"\n code: 105\n callable: *constructor\n args:\n - [ *NumericType, *StringType ]\n type: *Int32Type\n attr: {}\n template: *Int32SymbolTemplate\n argsTemplate: *Int32SymbolArgsTemplate\n Long:\n id: \"Long\"\n code: 106\n callable: *constructor\n args:\n - [ *IntegerType ]\n - [ *IntegerType ]\n type: *LongType\n attr:\n MAX_VALUE:\n id: \"MAX_VALUE\"\n callable: *var\n args: null\n type: *LongType\n attr: {}\n template: *LongSymbolMaxTemplate\n argsTemplate: *LongSymbolMaxArgsTemplate\n MIN_VALUE:\n id: \"MIN_VALUE\"\n callable: *var\n args: null\n type: *LongType\n attr: {}\n template: *LongSymbolMinTemplate\n argsTemplate: *LongSymbolMinArgsTemplate\n ZERO:\n id: \"ZERO\"\n callable: *var\n args: null\n type: *LongType\n attr: {}\n template: *LongSymbolZeroTemplate\n argsTemplate: *LongSymbolZeroArgsTemplate\n ONE:\n id: \"ONE\"\n callable: *var\n args: null\n type: *LongType\n attr: {}\n template: *LongSymbolOneTemplate\n argsTemplate: *LongSymbolOneArgsTemplate\n NEG_ONE:\n id: \"NEG_ONE\"\n callable: *var\n args: null\n type: *LongType\n attr: {}\n template: *LongSymbolNegOneTemplate\n argsTemplate: *LongSymbolNegOneArgsTemplate\n fromBits:\n id: \"LongfromBits\" # Needs process method\n callable: *func\n args:\n - [ *IntegerType ]\n - [ *IntegerType ]\n type: *LongType\n attr: {}\n template: *LongSymbolFromBitsTemplate\n argsTemplate: *LongSymbolFromBitsArgsTemplate\n fromInt:\n id: \"fromInt\"\n callable: *func\n args:\n - [ *IntegerType ]\n type: *LongType\n attr: {}\n template: *LongSymbolFromIntTemplate\n argsTemplate: *LongSymbolFromIntArgsTemplate\n fromNumber:\n id: \"fromNumber\"\n callable: *func\n args:\n - [ *NumericType ]\n type: *LongType\n attr: {}\n template: *LongSymbolFromNumberTemplate\n argsTemplate: *LongSymbolFromNumberArgsTemplate\n fromString:\n id: \"fromString\"\n callable: *func\n args:\n - [ *StringType ]\n - [ *IntegerType, null ]\n type: *LongType\n attr: {}\n template: *LongSymbolFromStringTemplate\n argsTemplate: *LongSymbolFromStringArgsTemplate\n template: *LongSymbolTemplate\n argsTemplate: *LongSymbolArgsTemplate\n\nNativeSymbols:\n Number:\n id: \"Number\"\n code: 2\n callable: *constructor\n args:\n - [ *IntegerType, *StringType, null ]\n type: *NumericType\n attr: {} # TODO: no built-in number funcs added yet\n template: *NumberSymbolTemplate\n argsTemplate: *NumberSymbolArgsTemplate\n Date: # Needs emit method\n id: \"Date\"\n code: 200\n callable: *constructor\n args:\n - [ *StringType, *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n - [ *NumericType, null ]\n type: *DateType\n attr: # TODO: add more date funcs?\n now:\n id: \"now\"\n code: 200.1\n callable: *func\n args: []\n type: *DateType\n attr: {}\n template: *DateSymbolNowTemplate\n argsTemplate: *DateSymbolNowArgsTemplate\n template: *DateSymbolTemplate\n argsTemplate: *DateSymbolArgsTemplate\n ISODate: # Needs emit method\n id: \"ISODate\"\n code: 200\n callable: *constructor\n args:\n - [ *StringType, null ]\n type: *DateType\n attr:\n now:\n id: \"now\"\n callable: *constructor\n args: []\n type: *DateType\n attr: {}\n template: *DateSymbolNowTemplate\n argsTemplate: *DateSymbolNowArgsTemplate\n template: *DateSymbolTemplate\n argsTemplate: *DateSymbolArgsTemplate\n RegExp: # Needs process method\n id: \"RegExp\"\n code: 8\n callable: *constructor\n args:\n - [ *StringType, *RegexType ]\n - [ *StringType, null ]\n type: *RegExpType\n attr: {} # TODO: no built-in regex funcs added yet\n template: *RegExpSymbolTemplate\n argsTemplate: *RegExpSymbolArgsTemplate\n\n"; |
{ | ||
"name": "bson-transpilers", | ||
"version": "0.0.0-next-8ec9e3341a4516d0d09c0d9efbbb836758c48228", | ||
"version": "0.0.0-next-8fcca6264afe05c6cb224ee274816efb1ac136ef", | ||
"apiVersion": "0.0.1", | ||
"productName": "BSON Transpilers", | ||
"description": "Source to source compilers using ANTLR", | ||
@@ -17,5 +16,4 @@ "contributors": [ | ||
"precompile": "node download-antlr.js", | ||
"compile": "npm run antlr4-js && npm run antlr4-py && npm run symbol-table", | ||
"compile": "npm run antlr4-js && npm run symbol-table", | ||
"antlr4-js": "java -Xmx500M -cp './antlr-4.7.2-complete.jar:$CLASSPATH' org.antlr.v4.Tool -Dlanguage=JavaScript -lib grammars -o lib/antlr -visitor -Xexact-output-dir grammars/ECMAScript.g4", | ||
"antlr4-py": "java -Xmx500M -cp './antlr-4.7.2-complete.jar:$CLASSPATH' org.antlr.v4.Tool -Dlanguage=JavaScript -lib grammars -o lib/antlr -visitor -Xexact-output-dir grammars/Python3.g4", | ||
"symbol-table": "node compile-symbol-table.js", | ||
@@ -26,3 +24,3 @@ "pretest": "npm run compile", | ||
"test-ci": "mocha", | ||
"depcheck": "depcheck", | ||
"depcheck": "compass-scripts check-peer-deps && depcheck", | ||
"check": "npm run lint && npm run depcheck", | ||
@@ -39,11 +37,11 @@ "lint": "eslint .", | ||
"devDependencies": { | ||
"@mongodb-js/eslint-config-compass": "0.0.0-next-8fcca6264afe05c6cb224ee274816efb1ac136ef", | ||
"chai": "^4.3.4", | ||
"depcheck": "^1.4.1", | ||
"eslint": "^7.25.0", | ||
"eslint-config-mongodb-js": "^2.1.0", | ||
"mocha": "^8.4.0" | ||
"mocha": "^10.2.0" | ||
}, | ||
"dependencies": { | ||
"antlr4": "4.7.2", | ||
"bson": "^4.4.1", | ||
"bson": "^6.10.1", | ||
"js-yaml": "^3.13.1" | ||
@@ -55,3 +53,3 @@ }, | ||
}, | ||
"gitHead": "8ec9e3341a4516d0d09c0d9efbbb836758c48228" | ||
"gitHead": "8fcca6264afe05c6cb224ee274816efb1ac136ef" | ||
} |
128
README.md
# BSON-Transpilers | ||
[![npm version][1]][2] [![build status][3]][4] | ||
@@ -6,8 +7,11 @@ [![downloads][5]][6] | ||
Transpilers for building BSON documents in any language. Current support | ||
provided for `shell` `javascript` and `python` as inputs. `java`, `c#`, `node`, `shell`, `python`, `ruby` and `go` as outputs. | ||
provided for `shell` as inputs. `java`, `c#`, `node`, `shell`, `python`, `ruby` and `go` as outputs. | ||
> ⚠️ `shell` output produces code that is compatible only with legacy `mongo` shell not the new `mongosh` shell. See [COMPASS-4930](https://jira.mongodb.org/browse/COMPASS-4930) for some additional context | ||
See also the original presentation: https://drive.google.com/file/d/1jvwtR3k9oBUzIjL4z_VtpHvdWahfcjTK/view | ||
**NOTES:** | ||
1. A version of the code with support for `python` with corresponding test cases has been removed to avoid bundling and supporting unused code, however it can be still be found in https://github.com/mongodb-js/compass/tree/80cf701e44cd966207f956fac69e8233861b1cd5/packages/bson-transpilers. | ||
2. The `shell` output is disabled as is essentially the only input in use and it produces code that is compatible only with legacy `mongo` shell not the new `mongosh` shell. See [COMPASS-4930](https://jira.mongodb.org/browse/COMPASS-4930) for some additional context. | ||
# Usage | ||
@@ -18,6 +22,6 @@ | ||
const input = 'javascript'; | ||
const input = 'shell'; | ||
const output = 'java'; | ||
const string =` | ||
const string = ` | ||
{ item: "book", qty: Int32(10), tags: ["red", "blank"], dim_cm: [14, Int32("81")] }`; | ||
@@ -37,50 +41,56 @@ | ||
## API | ||
### compiledString = transpiler\[inputLang\]\[outputLang\].compile(codeString) | ||
Output a compiled string given input and output languages. | ||
- __inputLang:__ Input language of the code string. `shell` and `javascript` | ||
- **inputLang:** Input language of the code string. `shell` and `javascript` | ||
are currently supported. | ||
- __outputLang:__ The language you would like the output to be. `java`, | ||
- **outputLang:** The language you would like the output to be. `java`, | ||
`python`, `shell`, `javascript`, and `csharp` are currently supported. | ||
- __codeString:__ The code string you would like to be compiled to your | ||
- **codeString:** The code string you would like to be compiled to your | ||
selected output language. | ||
### importsString = transpiler\[inputLang\]\[outputLang\].getImports(mode, driverSyntax) | ||
Output a string containing the set of import statements for the generated code | ||
to compile. These are all the packages that the compiled code could use so that | ||
the transpiler output will be runnable. | ||
- __inputLang:__ Input language of the code string. `shell` and `javascript` | ||
- **inputLang:** Input language of the code string. `shell` and `javascript` | ||
are currently supported. | ||
- __outputLang:__ The language you would like the output to be. `java`, | ||
- **outputLang:** The language you would like the output to be. `java`, | ||
`python`, `shell`, `javascript`, and `csharp` are currently supported. | ||
- __mode:__ Either 'Query' for the `.find()` method or 'Pipeline' for `.aggregate()`. | ||
- __driverSyntax:__ Whether or not you want to include Driver Syntax into your output string. | ||
- **mode:** Either 'Query' for the `.find()` method or 'Pipeline' for `.aggregate()`. | ||
- **driverSyntax:** Whether or not you want to include Driver Syntax into your output string. | ||
### catch (error) | ||
Any transpiler errors that occur will be thrown. To catch them, wrap the | ||
`transpiler` in a `try/catch` block. | ||
- __error.message:__ Message `bson-transpilers` will send back letting you know | ||
- **error.message:** Message `bson-transpilers` will send back letting you know | ||
the transpiler error. | ||
- __error.stack:__ The usual error stacktrace. | ||
- __error.code:__ [Error code]() that `bson-transpilers` adds to the error object to | ||
- **error.stack:** The usual error stacktrace. | ||
- **error.code:** [Error code]() that `bson-transpilers` adds to the error object to | ||
help you distinguish error types. | ||
- __error.line:__ If it is a syntax error, will have the line. | ||
- __error.column:__ If it is a syntax error, will have the column. | ||
- __error.symbol:__ If it is a syntax error, will have the symbol associated with the error. | ||
- **error.line:** If it is a syntax error, will have the line. | ||
- **error.column:** If it is a syntax error, will have the column. | ||
- **error.symbol:** If it is a syntax error, will have the symbol associated with the error. | ||
### State | ||
The `CodeGenerationVisitor` class manages a global state which is bound to the `argsTemplate` functions. This state is intended to be used as a solution for the `argsTemplate` functions to communicate with the `DriverTemplate` function. For example: | ||
The `CodeGenerationVisitor` class manages a global state which is bound to the `argsTemplate` functions. This state is intended to be used as a solution for the `argsTemplate` functions to communicate with the `DriverTemplate` function. For example: | ||
```yaml | ||
ObjectIdEqualsArgsTemplate: &ObjectIdEqualsArgsTemplate !!js/function > | ||
(_) => { | ||
this.oneLineStatement = "Hello World"; | ||
return ''; | ||
} | ||
ObjectIdEqualsArgsTemplate: !!js/function &ObjectIdEqualsArgsTemplate > | ||
(_) => { | ||
this.oneLineStatement = "Hello World"; | ||
return ''; | ||
} | ||
DriverTemplate: &DriverTemplate !!js/function > | ||
(_spec) => { | ||
return this.oneLineStatement; | ||
} | ||
DriverTemplate: !!js/function &DriverTemplate > | ||
(_spec) => { | ||
return this.oneLineStatement; | ||
} | ||
``` | ||
@@ -91,10 +101,11 @@ | ||
#### DeclarationStore | ||
A more practical use-case of state is to accumulate variable declarations throughout the `argsTemplate` to be rendered by the `DriverTemplate`. That is, the motivation for using `DeclarationStore` is to prepend the driver syntax with variable declarations rather than using non-idiomatic solutions such as closures. | ||
The `DeclarationStore` class maintains an internal state concerning variable declarations. For example, | ||
A more practical use-case of state is to accumulate variable declarations throughout the `argsTemplate` to be rendered by the `DriverTemplate`. That is, the motivation for using `DeclarationStore` is to prepend the driver syntax with variable declarations rather than using non-idiomatic solutions such as closures. | ||
The `DeclarationStore` class maintains an internal state concerning variable declarations. For example, | ||
```javascript | ||
// within the args template | ||
(arg) => { | ||
return this.declarations.add("Temp", "objectID", (varName) => { | ||
return this.declarations.add('Temp', 'objectID', (varName) => { | ||
return [ | ||
@@ -104,9 +115,9 @@ `${varName}, err := primitive.ObjectIDFromHex(${arg})`, | ||
' log.Fatal(err)', | ||
'}' | ||
].join('\n') | ||
}) | ||
} | ||
'}', | ||
].join('\n'); | ||
}); | ||
}; | ||
``` | ||
Note that each use of the same variable name will result in an increment being added to the declaration statement. For example, if the variable name `objectIDForTemp` is used two times the resulting declaration statements will use `objectIDForTemp` for the first declaration and `objectID2ForTemp` for the second declaration. The `add` method returns the incremented variable name, and is therefore what would be expected as the right-hand side of the statement defined by the `argsTemplate` function. | ||
Note that each use of the same variable name will result in an increment being added to the declaration statement. For example, if the variable name `objectIDForTemp` is used two times the resulting declaration statements will use `objectIDForTemp` for the first declaration and `objectID2ForTemp` for the second declaration. The `add` method returns the incremented variable name, and is therefore what would be expected as the right-hand side of the statement defined by the `argsTemplate` function. | ||
@@ -117,9 +128,11 @@ The instance of the `DeclarationStore` constructed by the transpiler class is passed into the driver, syntax via state, for use: | ||
(spec) => { | ||
const comment = '// some comment' | ||
const client = 'client, err := mongo.Connect(context.Background(), options.Client().ApplyURI(cs.String()))' | ||
return "#{comment}\n\n#{client}\n\n${this.declarations.toString()}" | ||
} | ||
const comment = '// some comment'; | ||
const client = | ||
'client, err := mongo.Connect(context.Background(), options.Client().ApplyURI(cs.String()))'; | ||
return '#{comment}\n\n#{client}\n\n${this.declarations.toString()}'; | ||
}; | ||
``` | ||
### Errors | ||
There are a few different error classes thrown by `bson-transpilers`, each with | ||
@@ -129,3 +142,5 @@ their own error code: | ||
#### BsonTranspilersArgumentError | ||
###### code: E_BSONTRANSPILERS_ARGUMENT | ||
This will occur when you're using a method with a wrong number of arguments, or | ||
@@ -153,3 +168,5 @@ the arguments are of the wrong type. | ||
#### BsonTranspilersAttributeError | ||
###### code: E_BSONTRANSPILERS_ATTRIBUTE | ||
Will be thrown if an invalid method or property is used on a BSON object. For | ||
@@ -161,10 +178,12 @@ example, since `new DBRef()` doesn't have a method `.foo()`, transpiler will | ||
// ✘: method foo doesn't exist, so this will throw a BsonTranspilersAttributeError . | ||
new DBRef('newCollection', new ObjectId()).foo() | ||
new DBRef('newCollection', new ObjectId()).foo(); | ||
// ✔: this won't throw, since .toString() method exists | ||
new DBRef('newCollection', new ObjectId()).toString(10) | ||
new DBRef('newCollection', new ObjectId()).toString(10); | ||
``` | ||
#### BsonTranspilersSyntaxError | ||
###### code: E_BSONTRANSPILERS_SYNTAX | ||
This will throw if you have a syntax error. For example missing a colon in | ||
@@ -186,3 +205,5 @@ Object assignment, or forgetting a comma in array definition: | ||
#### BsonTranspilersTypeError | ||
###### code: E_BSONTRANSPILERS_TYPE | ||
This error will occur if a symbol is treated as the wrong type. For example, if | ||
@@ -193,9 +214,12 @@ a non-function is called: | ||
// ✘: MAX_VALUE is a constant, not a function | ||
Long.MAX_VALUE() | ||
Long.MAX_VALUE(); | ||
// ✔: MAX_VALUE without a call will not throw | ||
Long.MAX_VALUE | ||
Long.MAX_VALUE; | ||
``` | ||
#### BsonTranspilersUnimplementedError | ||
###### code: E_BSONTRANSPILERS_UNIMPLEMENTED | ||
If there is a feature in the input code that is not currently supported by the | ||
@@ -205,3 +229,5 @@ transpiler. | ||
#### BsonTranspilersRuntimeError | ||
###### code: E_BSONTRANSPILERS_RUNTIME | ||
A generic runtime error will be thrown for all errors that are not covered by the | ||
@@ -213,10 +239,12 @@ above list of errors. These are usually constructor requirements, for example | ||
// ✘: these are not proper 'RegExp()' flags, a BsonTranspilersRuntimeError will be thrown. | ||
new RegExp('ab+c', 'beep') | ||
new RegExp('ab+c', 'beep'); | ||
// ✔: 'im' are proper 'RegExp()' flags | ||
new RegExp('ab+c', 'im') | ||
new RegExp('ab+c', 'im'); | ||
``` | ||
#### BsonTranspilersInternalError | ||
###### code: E_BSONTRANSPILERS_INTERNAL | ||
In the case where something has gone wrong within compilation, and an error has | ||
@@ -226,2 +254,3 @@ occured. If you see this error, please create [an issue](https://github.com/mongodb-js/bson-transpilers/issues) on Github! | ||
# Install | ||
```shell | ||
@@ -232,2 +261,3 @@ npm install -S bson-transpilers | ||
## Contributing | ||
Head over to the readme [on contributing](./CONTRIBUTING.md) to find out more | ||
@@ -237,2 +267,3 @@ information on project structure and setting up your environment. | ||
# Authors | ||
- [aherlihy](https://github.com/aherlihy) - Anna Herlihy <herlihyap@gmail.com> | ||
@@ -243,4 +274,5 @@ - [alenakhineika](https://github.com/alenakhineika) - Alena Khineika <alena.khineika@mongodb.com> | ||
# License | ||
[Apache-2.0](https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)) | ||
[Apache-2.0](<https://tldrlegal.com/license/apache-license-2.0-(apache-2.0)>) | ||
[1]: https://img.shields.io/npm/v/bson-transpilers.svg?style=flat-square | ||
@@ -247,0 +279,0 @@ [2]: https://npmjs.org/package/bson-transpilers |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
267
5
1391101
49
16297
+ Addedbson@6.10.1(transitive)
- Removedbase64-js@1.5.1(transitive)
- Removedbson@4.7.2(transitive)
- Removedbuffer@5.7.1(transitive)
- Removedieee754@1.2.1(transitive)
Updatedbson@^6.10.1