lib/builtin.js (501 lines of code) (raw):

'use strict'; const DSL = require('@darabonba/parser'); const { _vid, _name, _isDefault, CORE } = require('./helper'); const types = [ 'integer', 'int8', 'int16', 'int32', 'int64', 'long', 'ulong', 'string', 'uint8', 'uint16', 'uint32', 'uint64', 'number', 'float', 'double', 'boolean', 'bytes', 'readable', 'writable', 'object', 'any' ]; const integers = [ 'integer', 'int8', 'int16', 'int32', 'int64', 'long', 'ulong', 'uint8', 'uint16', 'uint32', 'uint64' ]; const floats = ['float', 'double']; class Builtin { constructor(generator, module = '', methods = []){ this.generator = generator; this.module = module; methods.forEach(method => { this[method] = function(args, level) { this.generator.emit(`${this.module}.${method}`); this.generator.visitArgs(args, level); }; }); } getInstanceName(ast) { if (ast.left.id.tag === DSL.Tag.Tag.VID) { this.generator.emit(`this.${_vid(ast.left.id)}`); } else { this.generator.emit(`${_name(ast.left.id)}`); } } } class Env extends Builtin { constructor(generator){ super(generator, 'process.env'); } get(args){ const key = args[0]; this.generator.emit(`${this.module }[`); this.generator.visitExpr(key); this.generator.emit(']'); } set(args){ const key = args[0]; this.generator.emit(`${this.module }[`); this.generator.visitExpr(key); this.generator.emit('] = '); const value = args[1]; this.generator.visitExpr(value); } } class Logger extends Builtin { constructor(generator){ const methods = ['log', 'info', 'debug', 'error']; super(generator, 'console', methods); } warning(args, level){ this.generator.emit(`${this.module}.warn`); this.generator.visitArgs(args, level); } } class XML extends Builtin { constructor(generator){ const methods = ['parseXml', 'toXML']; super(generator, `${CORE}.XML`, methods); } } class URL extends Builtin { constructor(generator){ const methods = ['parse', 'urlEncode', 'percentEncode', 'pathEncode']; super(generator, `${CORE}.URL`, methods); } } class Stream extends Builtin { constructor(generator){ const methods = ['readAsBytes', 'readAsJSON', 'readAsString', 'readAsSSE']; super(generator, `${CORE}.Stream`, methods); } } class Number extends Builtin { constructor(generator){ const methods = ['random', 'floor', 'round', 'min', 'max']; super(generator, 'Math', methods); } parseInt(ast) { this.generator.emit('parseInt(`${'); this.getInstanceName(ast); this.generator.emit('}`)'); } parseLong(ast) { this.generator.emit('parseInt(`${'); this.getInstanceName(ast); this.generator.emit('}`)'); } parseFloat(ast) { this.generator.emit('parseFloat(`${'); this.getInstanceName(ast); this.generator.emit('}`)'); } parseDouble(ast) { this.generator.emit('parseFloat(`${'); this.getInstanceName(ast); this.generator.emit('}`)'); } itol(ast) { this.getInstanceName(ast); } ltoi(ast) { this.getInstanceName(ast); } } class JSON extends Builtin { constructor(generator){ const methods = []; super(generator, 'JSON', methods); } stringify(args) { const expr = args[0]; this.generator.emit('typeof '); this.generator.visitExpr(expr); this.generator.emit(' === "string" ? '); this.generator.visitExpr(expr); this.generator.emit(' : '); this.generator.emit('JSON.stringify('); this.generator.visitExpr(expr); this.generator.emit(')'); } parseJSON(args, level){ this.generator.emit(`${this.module }.parse`); this.generator.visitArgs(args, level); } } class Form extends Builtin { constructor(generator){ const methods = ['toFormString', 'getBoundary', 'toFileForm']; super(generator, `${CORE}.Form`, methods); } } class File extends Builtin { constructor(generator){ const methods = ['createReadStream', 'createWriteStream', 'exists']; super(generator, `${CORE}.File`, methods); } } class Bytes extends Builtin { constructor(generator){ const methods = ['from']; super(generator, 'Buffer', methods); } toString(ast, level, type = 'utf8'){ this.getInstanceName(ast, level); this.generator.emit(`.toString("${type}")`); } toHex(ast, level){ this.toString(ast, level, 'hex'); } toBase64(ast, level){ this.toString(ast, level, 'base64'); } toJSON(ast, level) { this.toString(ast, level); } length(ast){ this.getInstanceName(ast); this.generator.emit('.length'); } } class Converter { constructor(generator){ this.generator = generator; integers.forEach(type => { this[type] = function(args) { const expr = args[0]; if(_isDefault(expr)) { generator.visitExpr(expr); return; } generator.emit('parseInt('); generator.visitExpr(expr); generator.emit(')'); }; }); floats.forEach(type => { this[type] = function(args) { const expr = args[0]; if(_isDefault(expr)) { generator.visitExpr(expr); return; } generator.emit('parseFloat('); generator.visitExpr(expr); generator.emit(')'); }; }); } string(args) { const expr = args[0]; if(_isDefault(expr)) { this.generator.visitExpr(expr); return; } this.generator.emit('String('); this.generator.visitExpr(expr); this.generator.emit(')'); } number(args) { const expr = args[0]; if(_isDefault(expr)) { this.generator.visitExpr(expr); return; } this.generator.emit('Number('); this.generator.visitExpr(expr); this.generator.emit(')'); } boolean(args) { const expr = args[0]; if(_isDefault(expr)) { this.generator.visitExpr(expr); return; } this.generator.emit('Boolean('); this.generator.visitExpr(expr); this.generator.emit(')'); } bytes(args) { const expr = args[0]; this.generator.emit('Buffer.from('); this.generator.visitExpr(expr); this.generator.emit(')'); } any(args){ const expr = args[0]; this.generator.visitExpr(expr); } object(args){ const expr = args[0]; this.generator.visitExpr(expr); } readable(args){ const expr = args[0]; this.generator.usedTypes.push('Readable'); this.generator.visitExpr(expr); this.generator.emit(' instanceof Readable ? '); this.generator.visitExpr(expr); this.generator.emit(' : '); this.generator.emit('Readable.from('); this.generator.visitExpr(expr); this.generator.emit(')'); } writable(args){ const expr = args[0]; this.generator.visitExpr(expr); this.generator.usedTypes.push('Writable'); this.generator.emit(' instanceof Writable ? '); this.generator.visitExpr(expr); this.generator.emit(' : '); this.generator.emit('Writable.from('); this.generator.visitExpr(expr); this.generator.emit(')'); } } class Func { constructor(generator){ this.generator = generator; ['sleep', 'isNull'].forEach(method => { this[method] = function(args) { generator.emit(`$dara.${method}`); generator.visitArgs(args); }; }); } equal(args){ this.generator.visitExpr(args[0]); this.generator.emit(' === '); this.generator.visitExpr(args[1]); } default(args){ this.generator.visitExpr(args[0]); this.generator.emit(' || '); this.generator.visitExpr(args[1]); } } class String extends Builtin { replace(ast, level) { this.getInstanceName(ast); const args = ast.args; const regex = args[0].value.string; this.generator.emit('.replace'); this.generator.emit(`(${regex}, `); this.generator.visitExpr(args[1], level); this.generator.emit(')'); } contains(ast, level) { this.getInstanceName(ast); const args = ast.args; this.generator.emit('.includes'); this.generator.visitArgs(args, level); } length(ast) { this.getInstanceName(ast); this.generator.emit('.length'); } hasPrefix(ast, level) { this.getInstanceName(ast); const args = ast.args; this.generator.emit('.startsWith'); this.generator.visitArgs(args, level); } hasSuffix(ast, level) { this.getInstanceName(ast); const args = ast.args; this.generator.emit('.endsWith'); this.generator.visitArgs(args, level); } index(ast, level) { this.getInstanceName(ast); const args = ast.args; this.generator.emit('.indexOf'); this.generator.visitArgs(args, level); } subString(ast, level) { this.getInstanceName(ast); const args = ast.args; this.generator.emit('.slice'); this.generator.visitArgs(args, level); } toLower(ast) { this.getInstanceName(ast); this.generator.emit('.toLowerCase'); this.generator.emit('()'); } toUpper(ast) { this.getInstanceName(ast); this.generator.emit('.toUpperCase'); this.generator.emit('()'); } equals(ast) { this.getInstanceName(ast); const args = ast.args; const expr = args[0]; this.generator.emit(' == '); this.generator.visitExpr(expr); } empty(ast) { this.generator.emit('!'); this.getInstanceName(ast); } toBytes(ast) { const args = ast.args; const expr = args[0]; this.generator.emit('Buffer.from('); this.getInstanceName(ast); this.generator.emit(', '); this.generator.visitExpr(expr); this.generator.emit(')'); } parseInt(ast) { this.generator.emit('parseInt('); this.getInstanceName(ast); this.generator.emit(')'); } parseLong(ast) { this.generator.emit('parseInt('); this.getInstanceName(ast); this.generator.emit(')'); } parseFloat(ast) { this.generator.emit('parseFloat('); this.getInstanceName(ast); this.generator.emit(')'); } parseDouble(ast) { this.generator.emit('parseFloat('); this.getInstanceName(ast); this.generator.emit(')'); } } class Array extends Builtin { contains(ast, level) { this.getInstanceName(ast); const args = ast.args; this.generator.emit('.includes'); this.generator.visitArgs(args, level); } length(ast) { this.getInstanceName(ast); this.generator.emit('.length'); } index(ast, level) { this.getInstanceName(ast); const args = ast.args; this.generator.emit('.indexOf'); this.generator.visitArgs(args, level); } get(ast, level) { this.getInstanceName(ast); const args = ast.args; this.generator.emit(`[`); const expr = args[0]; this.generator.visitExpr(expr, level); this.generator.emit(`]`); } sort(ast) { this.generator.emit(`${CORE}.sort(`); this.getInstanceName(ast); this.generator.emit(', '); this.generator.visitExpr(ast.args[0]); this.generator.emit(')'); } append(ast) { this.getInstanceName(ast); const position = ast.args[1]; const value = ast.args[0]; this.generator.emit('.splice('); this.generator.visitExpr(position); this.generator.emit(', 0, '); this.generator.visitExpr(value); this.generator.emit(')'); } remove(ast) { this.getInstanceName(ast); const value = ast.args[0]; this.generator.emit('.splice('); this.getInstanceName(ast); this.generator.emit('.indexOf('); this.generator.visitExpr(value); this.generator.emit('), 1)'); } } class Map extends Builtin { length(ast) { this.generator.emit('Object.keys('); this.getInstanceName(ast); this.generator.emit(')'); this.generator.emit('.length'); } keySet(ast) { this.generator.emit('Object.keys('); this.getInstanceName(ast); this.generator.emit(')'); } entries(ast) { this.generator.emit('Object.entries('); this.getInstanceName(ast); this.generator.emit(')'); } toJSON(ast) { this.generator.emit('JSON.stringify('); this.getInstanceName(ast); this.generator.emit(')'); } merge(ast) { this.generator.emit('$dara.merge('); this.getInstanceName(ast); this.generator.emit(' , '); this.generator.visitExpr(ast.args[0]); this.generator.emit(')'); } } class Entry extends Builtin { key(ast) { this.getInstanceName(ast); this.generator.emit('[0]'); } value(ast) { this.getInstanceName(ast); this.generator.emit('[1]'); } } module.exports = (generator) => { const builtin = {}; builtin['$Env'] = new Env(generator); builtin['$Logger'] = new Logger(generator); builtin['$XML'] = new XML(generator); builtin['$URL'] = new URL(generator); builtin['$Stream'] = new Stream(generator); builtin['$Number'] = new Number(generator); builtin['$JSON'] = new JSON(generator); builtin['$Form'] = new Form(generator); builtin['$File'] = new File(generator); builtin['$Bytes'] = new Bytes(generator); const converter = new Converter(generator); types.map(type => { builtin[`$${type}`] = converter; }); const func = new Func(generator); builtin['$isNull'] = func; builtin['$sleep'] = func; builtin['$default'] = func; builtin['$equal'] = func; builtin['$String'] = new String(generator); builtin['$Array'] = new Array(generator); builtin['$Date'] = new Date(generator); builtin['$Map'] = new Map(generator); builtin['$Entry'] = new Entry(generator); return builtin; };