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

'use strict'; const DSL = require('@darabonba/parser'); const { _vid, _name, _string } = 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']; const BuiltinModule = { DaraBuiltin: { namespace: 'AlibabaCloud\\Dara\\Util', className: 'Utils', }, DaraString: { namespace: 'AlibabaCloud\\Dara\\Util', className: 'StringUtil', }, DaraMath: { namespace: 'AlibabaCloud\\Dara\\Util', className: 'MathUtil', }, DaraStream: { namespace: 'AlibabaCloud\\Dara\\Util', className: 'StreamUtil', }, DaraConsole: { namespace: 'AlibabaCloud\\Dara\\Util', className: 'Console', }, DaraXML: { namespace: 'AlibabaCloud\\Dara\\Util', className: 'XML', }, DaraURL: { namespace: 'AlibabaCloud\\Dara', className: 'Url', }, DaraForm: { namespace: 'AlibabaCloud\\Dara\\Util', className: 'FormUtil', }, DaraFile: { namespace: 'AlibabaCloud\\Dara', className: 'File', }, DaraBytes: { namespace: 'AlibabaCloud\\Dara\\Util', className: 'BytesUtil', }, DaraDate: { namespace: 'AlibabaCloud\\Dara', className: 'Date', }, }; class Builtin { constructor(generator, aliasId = 'DaraBuiltin', methods = []){ this.generator = generator; this.module = module; this.aliasId = aliasId; methods.forEach(method => { this[method] = function(args, level) { const clientName = this.getClientName(); this.generator.emit(`${clientName}::${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)}`); } } getClientName() { if(!this.generator.moduleClass.has(this.aliasId)) { const { namespace, className } = BuiltinModule[this.aliasId]; this.generator.moduleClass.set(this.aliasId, { namespace, className, aliasName: this.generator.getAliasName(namespace, className, 'Dara') }); } return this.generator.getRealClientName(this.aliasId); } } class Env extends Builtin { constructor(generator){ super(generator); } get(args){ const key = args[0]; this.generator.emit('getenv('); this.generator.visitExpr(key); this.generator.emit(')'); } set(args){ const key = args[0]; this.generator.emit('putenv('); if(key.type === 'string') { this.generator.emit(`'${_string(key.value)}=`); } else { this.generator.visitExpr(key); this.generator.emit('.\'='); } const value = args[1]; if(value.type === 'string') { this.generator.emit(`${_string(value.value)}'`); } else { this.generator.emit('\'.'); this.generator.visitExpr(value); } this.generator.emit(')'); } } class Logger extends Builtin { constructor(generator){ const methods = ['log', 'info', 'debug', 'error', 'warning']; super(generator, 'DaraConsole', methods); } } class XML extends Builtin { constructor(generator){ const methods = ['parseXml', 'toXML']; super(generator, 'DaraXML', methods); } } class URL extends Builtin { constructor(generator){ const methods = ['parse', 'urlEncode', 'percentEncode', 'pathEncode']; super(generator, 'DaraURL', methods); } } class Stream extends Builtin { constructor(generator){ const methods = ['readAsBytes', 'readAsJSON', 'readAsString', 'readAsSSE', 'streamFor']; super(generator, 'DaraStream', methods); } } class Number extends Builtin { constructor(generator){ const methods = ['random']; super(generator, 'DaraMath', methods); } floor(args) { this.generator.emit('floor'); this.generator.visitArgs(args); } round(args) { this.generator.emit('round'); this.generator.visitArgs(args); } min(args) { this.generator.emit('min'); this.generator.visitArgs(args); } max(args) { this.generator.emit('max'); this.generator.visitArgs(args); } parseInt(ast) { this.generator.emit('intval(\'\'.'); this.getInstanceName(ast); this.generator.emit(')'); } parseLong(ast) { this.generator.emit('intval(\'\'.'); this.getInstanceName(ast); this.generator.emit(')'); } parseFloat(ast) { this.generator.emit('floatval(\'\'.'); this.getInstanceName(ast); this.generator.emit(')'); } parseDouble(ast) { this.generator.emit('floatval(\'\'.'); this.getInstanceName(ast); this.generator.emit(')'); } itol(ast) { this.getInstanceName(ast); } ltoi(ast) { this.getInstanceName(ast); } } class JSON extends Builtin { stringify(args, level) { const expr = args[0]; this.generator.emit('json_encode('); this.generator.visitExpr(expr, level); if(expr.inferred && expr.inferred.type === 'model') { this.generator.emit('->toArray()'); } this.generator.emit(', JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES)'); } parseJSON(args, level){ const expr = args[0]; this.generator.emit('json_decode('); this.generator.visitExpr(expr, level); this.generator.emit(', true)'); } } class Form extends Builtin { constructor(generator){ const methods = ['toFormString', 'getBoundary', 'toFileForm']; super(generator, 'DaraForm', methods); } } class File extends Builtin { constructor(generator){ const methods = ['createReadStream', 'createWriteStream', 'exists']; super(generator, 'DaraFile', methods); } } class DaraDate extends Builtin { constructor(generator){ const methods = [ 'format', 'unix', 'diff', 'UTC', 'add', 'sub', 'hour', 'minute', 'second', 'dayOfYear', 'dayOfMonth', 'dayOfWeek', 'weekOfYear', 'weekOfMonth', 'month', 'year' ]; super(generator, 'DaraDate', methods); } } class Bytes extends Builtin { constructor(generator){ super(generator, 'DaraBytes'); } from(args) { const clientName = this.getClientName(); this.generator.emit(`${clientName}::from`); this.generator.visitArgs(args); } toString(ast) { const clientName = this.getClientName(); this.generator.emit(`${clientName}::toString(`); this.getInstanceName(ast); this.generator.emit(')'); } toHex(ast) { const clientName = this.getClientName(); this.generator.emit('bin2hex('); this.generator.emit(`${clientName}::toString(`); this.getInstanceName(ast); this.generator.emit('))'); } toBase64(ast) { const clientName = this.getClientName(); this.generator.emit('base64_encode('); this.generator.emit(`${clientName}::toString(`); this.getInstanceName(ast); this.generator.emit('))'); } toJSON(ast) { const clientName = this.getClientName(); this.generator.emit(`${clientName}::toString(`); this.getInstanceName(ast); this.generator.emit(')'); } length(ast){ this.generator.emit('strlen('); this.getInstanceName(ast); this.generator.emit(')'); } } class Converter { constructor(generator){ this.generator = generator; this.stream = new Stream(generator); integers.forEach(type => { this[type] = function(args) { const expr = args[0]; generator.emit('intval('); generator.visitExpr(expr); generator.emit(')'); }; }); floats.forEach(type => { this[type] = function(args) { const expr = args[0]; generator.emit('floatval('); generator.visitExpr(expr); generator.emit(')'); }; }); } string(args) { const expr = args[0]; this.generator.emit('\'\'.'); this.generator.visitExpr(expr); } number(args) { const expr = args[0]; this.generator.emit('('); this.generator.visitExpr(expr); this.generator.emit(' + 0)'); } boolean(args) { const expr = args[0]; this.generator.emit('boolval('); this.generator.visitExpr(expr); this.generator.emit(')'); } bytes(args) { const expr = args[0]; this.generator.emit('unpack(\'C*\', '); 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){ this.stream.streamFor(args); } writable(args){ this.stream.streamFor(args); } } class Func { constructor(generator){ this.generator = generator; } isNull(args) { this.generator.emit('is_null'); this.generator.visitArgs(args); } sleep(args) { this.generator.emit('usleep('); const expr = args[0]; this.generator.visitExpr(expr); this.generator.emit(' * 1000)'); } equal(args){ this.generator.visitExpr(args[0]); this.generator.emit(' === '); this.generator.visitExpr(args[1]); } default(args){ this.generator.emit('('); this.generator.visitExpr(args[0]); this.generator.emit(' ? '); this.generator.visitExpr(args[0]); this.generator.emit(' : '); this.generator.visitExpr(args[1]); this.generator.emit(')'); } } class String extends Builtin { constructor(generator, methods = []){ super(generator, 'DaraString', methods); } split(ast, level) { this.generator.emit('explode('); this.getInstanceName(ast); const args = ast.args; this.generator.emit(', '); const expr = args[0]; this.generator.visitExpr(expr, level); this.generator.emit(')'); } replace(ast, level) { const args = ast.args; const regex = args[0]; this.generator.emit('preg_replace('); this.generator.visitExpr(regex, level); this.generator.emit(', '); this.generator.visitExpr(args[1], level); this.generator.emit(', '); this.getInstanceName(ast); this.generator.emit(')'); } contains(ast, level) { this.generator.emit('false !== strpos('); this.getInstanceName(ast); const args = ast.args; this.generator.emit(', '); const expr = args[0]; this.generator.visitExpr(expr, level); this.generator.emit(')'); } length(ast) { this.generator.emit('strlen('); this.getInstanceName(ast); this.generator.emit(')'); } hasPrefix(ast, level) { const clientName = this.getClientName(); const args = ast.args; this.generator.emit(`${clientName}::hasPrefix(`); this.getInstanceName(ast); this.generator.emit(', '); const expr = args[0]; this.generator.visitExpr(expr, level); this.generator.emit(')'); } hasSuffix(ast, level) { const clientName = this.getClientName(); const args = ast.args; this.generator.emit(`${clientName}::hasSuffix(`); this.getInstanceName(ast); this.generator.emit(', '); const expr = args[0]; this.generator.visitExpr(expr, level); this.generator.emit(')'); } index(ast, level) { this.generator.emit('strpos('); this.getInstanceName(ast); const args = ast.args; this.generator.emit(', '); const expr = args[0]; this.generator.visitExpr(expr, level); this.generator.emit(')'); } subString(ast, level) { this.generator.emit('substr('); this.getInstanceName(ast); const args = ast.args; this.generator.emit(', '); const start = args[0]; this.generator.visitExpr(start, level); this.generator.emit(', '); const end = args[1]; this.generator.visitExpr(end, level); this.generator.emit(')'); } toLower(ast) { this.generator.emit('strtolower('); this.getInstanceName(ast); this.generator.emit(')'); } toUpper(ast) { this.generator.emit('strtoupper('); this.getInstanceName(ast); this.generator.emit(')'); } equals(ast) { this.getInstanceName(ast); const args = ast.args; const expr = args[0]; this.generator.emit(' === '); this.generator.visitExpr(expr); } trim(ast) { this.generator.emit('trim('); this.getInstanceName(ast); this.generator.emit(')'); } empty_(ast) { this.generator.emit('empty('); this.getInstanceName(ast); this.generator.emit(')'); } toBytes(ast) { const clientName = this.getClientName(); this.generator.emit(`${clientName}::toBytes(`); this.getInstanceName(ast); const args = ast.args; const expr = args[0]; this.generator.emit(', '); this.generator.visitExpr(expr); this.generator.emit(')'); } parseInt(ast) { this.generator.emit('intval('); this.getInstanceName(ast); this.generator.emit(')'); } parseLong(ast) { this.generator.emit('intval('); this.getInstanceName(ast); this.generator.emit(')'); } parseFloat(ast) { this.generator.emit('floatval('); this.getInstanceName(ast); this.generator.emit(')'); } parseDouble(ast) { this.generator.emit('floatval('); this.getInstanceName(ast); this.generator.emit(')'); } } class Array extends Builtin { join(ast ,level) { const args = ast.args; this.generator.emit('implode('); const expr = args[0]; this.generator.visitExpr(expr, level); this.generator.emit(', '); this.getInstanceName(ast); this.generator.emit(')'); } full(ast, level) { const args = ast.args; const expr = args[0]; this.generator.emit('array_map(function($item) {\n', level); this.generator.emit('return ', level + 1); this.generator.visitExpr(expr); this.generator.emit('\n'); this.generator.emit('}, ', level); this.getInstanceName(ast); this.generator.emit(')'); } shift(ast) { this.generator.emit('array_shift('); this.getInstanceName(ast); this.generator.emit(')'); } pop(ast) { this.generator.emit('array_pop('); this.getInstanceName(ast); this.generator.emit(')'); } push(ast) { const args = ast.args; const expr = args[0]; this.generator.emit('array_pop('); this.getInstanceName(ast); this.generator.emit(', '); this.generator.visitExpr(expr); this.generator.emit(')'); } unshift(ast) { const args = ast.args; const expr = args[0]; this.generator.emit('array_unshift('); this.getInstanceName(ast); this.generator.emit(', '); this.generator.visitExpr(expr); this.generator.emit(')'); } contains(ast, level) { const args = ast.args; this.generator.emit('\\in_array('); const expr = args[0]; this.generator.visitExpr(expr, level); this.generator.emit(', '); this.getInstanceName(ast); this.generator.emit(')'); } concat(ast, level) { const args = ast.args; this.generator.emit('array_merge('); const expr = args[0]; this.generator.visitExpr(expr, level); this.generator.emit(', '); this.getInstanceName(ast); this.generator.emit(')'); } length(ast) { this.generator.emit('\\count('); this.getInstanceName(ast); this.generator.emit(')'); } index(ast, level) { const args = ast.args; this.generator.emit('array_search('); const expr = args[0]; this.generator.visitExpr(expr, level); this.generator.emit(', '); this.getInstanceName(ast); this.generator.emit(')'); } 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) { const order = _string(ast.args[0].value); if(order.toLowerCase() === 'asc') { this.generator.emit('sort('); } else if(order.toLowerCase() === 'desc'){ this.generator.emit('rsort('); } else { throw Error('un-impelemented'); } this.getInstanceName(ast); this.generator.emit(')'); } append(ast) { const position = ast.args[1]; const value = ast.args[0]; this.generator.emit('array_splice('); this.getInstanceName(ast); this.generator.emit(', '); this.generator.visitExpr(position); this.generator.emit(', 0, '); this.generator.visitExpr(value); this.generator.emit(')'); } remove(ast) { const value = ast.args[0]; this.generator.emit('array_splice('); this.getInstanceName(ast); this.generator.emit(', array_search('); this.generator.visitExpr(value); this.generator.emit(', '); this.getInstanceName(ast); this.generator.emit('), 1)'); } } class Map extends Builtin { length(ast) { this.generator.emit('\\count('); this.getInstanceName(ast); this.generator.emit(')'); } keySet(ast) { this.generator.emit('array_keys('); this.getInstanceName(ast); this.generator.emit(')'); } entries(ast) { this.generator.emit('array_map(null, '); this.generator.emit('array_keys('); this.getInstanceName(ast); this.generator.emit('), '); this.generator.emit('array_values('); this.getInstanceName(ast); this.generator.emit('))'); } toJSON(ast) { this.generator.emit('json_encode('); this.getInstanceName(ast); this.generator.emit(', JSON_UNESCAPED_UNICODE + JSON_UNESCAPED_SLASHES)'); } merge(ast) { this.generator.emit('array_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 DaraDate(generator); builtin['$Map'] = new Map(generator); builtin['$Entry'] = new Entry(generator); return builtin; };