lib/builtin.js (688 lines of code) (raw):
'use strict';
const DSL = require('@darabonba/parser');
const { _getImport, _name, CORE, _snakeCase, _isDefault } = 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 (ast, level, async) {
this.generator.imports.push(_getImport(this.module));
if(async) {
this.generator.emit('await ');
}
this.generator.emit(`${this.module}.${_snakeCase(method)}`);
if(async) {
this.generator.emit('_async');
}
this.generator.visitArgs(ast.args, level);
};
});
}
getInstanceName(ast) {
if (!ast.left) {
return;
}
if (ast.left.id.tag === DSL.Tag.Tag.VID) {
this.generator.emit(`this.${_snakeCase(ast.left.id)}`);
} else {
this.generator.emit(`${_snakeCase(_name(ast.left.id)).replace('$','')}`);
}
}
getClientName() {
this.generator.imports.push(_getImport(this.module));
return this.module;
}
}
class Env extends Builtin {
constructor(generator) {
const methods = [];
super(generator, `${CORE}Env`, methods);
}
get(ast) {
this.generator.imports.push(_getImport(this.module));
this.generator.emit('os.environ.get(');
this.generator.emit(`'${ast.args[0].value.string}'`);
this.generator.emit(')');
}
set(ast) {
this.generator.imports.push(_getImport(this.module));
this.generator.emit('os.environ[');
this.generator.emit(`'${ast.args[0].value.string}'] = ${ast.args[1].left.id.lexeme} + '${ast.args[1].right.value.string}'`);
}
}
class Logger extends Builtin {
constructor(generator) {
const methods = ['critical', 'setLevel', 'format'];
super(generator, `${CORE}Logger`, methods);
}
log(ast) {
this.generator.imports.push(_getImport(this.module));
this.generator.emit('logging.log(logging.NOTSET, ');
this.generator.visitExpr(ast.args[0]);
this.generator.emit(')');
}
info(ast) {
this.generator.imports.push(_getImport(this.module));
this.generator.emit('logging.log(logging.INFO, ');
this.generator.visitExpr(ast.args[0]);
this.generator.emit(')');
}
warning(ast) {
this.generator.imports.push(_getImport(this.module));
this.generator.emit('logging.log(logging.WARNING, ');
this.generator.visitExpr(ast.args[0]);
this.generator.emit(')');
}
debug(ast) {
this.generator.imports.push(_getImport(this.module));
this.generator.emit('logging.log(logging.DEBUG, ');
this.generator.visitExpr(ast.args[0]);
this.generator.emit(')');
}
error(ast) {
this.generator.imports.push(_getImport(this.module));
this.generator.emit('logging.log(logging.ERROR, ');
this.generator.visitExpr(ast.args[0]);
this.generator.emit(')');
}
}
class XML extends Builtin {
constructor(generator) {
const methods = [ 'toXML'];
super(generator, `${CORE}XML`, methods);
}
parseXml(ast){
const clientName = this.getClientName();
this.generator.emit(`${clientName}.parse_xml(`);
this.generator.visitExpr(ast.args[0]);
if (ast.args[1].type === 'null') {
this.generator.emit(', ');
this.generator.emit('None');
} else {
this.generator.emit(', ');
this.generator.visitExpr(ast.args[1]);
}
this.generator.emit(')');
}
}
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);
}
write(ast, level, async) {
if(async) {
this.emit('awiat ');
}
this.generator.emit(`${_snakeCase(ast.left.id.lexeme)}.write${async ? '_async' : ''}(`);
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(')\n');
}
pipe(ast) {
this.generator.emit(`${_snakeCase(ast.left.id.lexeme)}.seek(0)\n`);
// this.generator.visitExpr(ast.args[0]);
// this.generator.emit(')\n');
}
}
class Number extends Builtin {
constructor(generator) {
const methods = [];
super(generator, `${CORE}Math`, methods);
}
floor(ast, level) {
this.generator.imports.push({
className: 'math',
});
this.generator.emit('math.floor(');
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(')');
}
round(ast, level) {
this.generator.emit('round(');
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(')');
}
min(ast, level) {
this.generator.emit('min(');
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(', ');
this.generator.visitExpr(ast.args[1], level);
this.generator.emit(')');
}
max(ast, level) {
this.generator.emit('max(');
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(', ');
this.generator.visitExpr(ast.args[1], level);
this.generator.emit(')');
}
parseInt(ast) {
this.generator.emit('int(');
this.getInstanceName(ast);
this.generator.emit(')');
}
parseLong(ast) {
this.generator.emit('int(');
this.getInstanceName(ast);
this.generator.emit(')');
}
parseFloat(ast) {
this.generator.emit('float(');
this.getInstanceName(ast);
this.generator.emit(')');
}
parseDouble(ast) {
this.generator.emit('float(');
this.getInstanceName(ast);
this.generator.emit(')');
}
itol(ast) {
this.getInstanceName(ast);
}
ltoi(ast) {
this.getInstanceName(ast);
}
random() {
this.generator.imports.push({
className: 'random',
});
this.generator.emit('random.random()');
}
}
class JSON extends Builtin {
constructor(generator) {
const methods = [];
super(generator, `${CORE}JSON`, methods);
}
stringify(ast, level) {
this.generator.imports.push({
aliasName: `${CORE}Core`,
className: `${CORE}Core`,
packageName: 'darabonba.core',
});
this.generator.emit(`${CORE}Core.to_json_string(`);
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(')');
}
parseJSON(ast, level) {
this.generator.imports.push({
className: 'json',
});
this.generator.emit('json.loads(');
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(')');
}
}
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 = [];
super(generator, `${CORE}Bytes`, methods);
}
from_(ast) {
const clientName = this.getClientName();
this.generator.emit(`${clientName}.from_`);
this.generator.visitArgs(ast.args);
}
toString(ast) {
this.getInstanceName(ast);
this.generator.emit('.decode(\'utf-8\')');
}
length(ast) {
this.generator.emit('len(');
this.getInstanceName(ast);
this.generator.emit(')');
}
toHex(ast){
this.getInstanceName(ast);
this.generator.emit('.hex()');
}
toBase64(ast){
this.generator.imports.push({
className: 'base64',
});
this.generator.emit('base64.b64encode(');
this.getInstanceName(ast);
this.generator.emit(').decode(\'utf-8\')');
}
toJSON(ast){
this.toString(ast);
}
}
class Converter {
constructor(generator) {
this.generator = generator;
integers.forEach(type => {
this[type] = function (ast) {
const expr = ast.args[0];
generator.emit('int(');
generator.visitExpr(expr);
generator.emit(')');
};
});
floats.forEach(type => {
this[type] = function (ast) {
const expr = ast.args[0];
generator.emit('float(');
generator.visitExpr(expr);
generator.emit(')');
};
});
}
string(ast) {
const expr = ast.args[0];
if(_isDefault(expr)) {
this.generator.visitExpr(expr);
return;
}
this.generator.emit('str(');
this.generator.visitExpr(expr);
this.generator.emit(')');
}
number(ast) {
const expr = ast.args[0];
this.generator.imports.push({
aliasName: `${CORE}Core`,
className: `${CORE}Core`,
packageName: 'darabonba.core',
});
this.generator.emit(`${CORE}Core.to_number(`);
this.generator.visitExpr(expr);
this.generator.emit(')');
}
boolean(ast) {
const expr = ast.args[0];
this.generator.emit('bool(');
this.generator.visitExpr(expr);
this.generator.emit(')');
}
bytes(ast) {
const expr = ast.args[0];
this.generator.emit('bytes(');
this.generator.visitExpr(expr);
this.generator.emit(')');
}
any(ast) {
const expr = ast.args[0];
this.generator.visitExpr(expr);
}
object(ast) {
const expr = ast.args[0];
this.generator.visitExpr(expr);
}
readable(ast) {
const expr = ast.args[0];
this.generator.imports.push(_getImport(`${CORE}Stream`));
this.generator.emit(`${CORE}Stream.to_readable(`);
this.generator.visitExpr(expr);
this.generator.emit(')');
}
writable(ast) {
const expr = ast.args[0];
this.generator.imports.push(_getImport(`${CORE}Stream`));
this.generator.emit(`${CORE}Stream.to_writable(`);
this.generator.visitExpr(expr);
this.generator.emit(')');
}
}
class Func {
constructor(generator) {
this.generator = generator;
['isNull'].forEach(method => {
this[method] = function (ast) {
const clientName = this.getClientName();
generator.emit(`${clientName}.${_snakeCase(method)}`);
generator.visitArgs(ast.args);
};
});
}
sleep(ast, level, async) {
const clientName = this.getClientName();
if(async) {
this.generator.emit('awiat ');
}
this.generator.emit(`${clientName}.sleep`);
if(async) {
this.generator.emit('_async');
}
this.generator.visitArgs(ast.args, level);
}
equal(ast) {
this.generator.visitExpr(ast.args[0]);
this.generator.emit(' == ');
this.generator.visitExpr(ast.args[1]);
}
default(ast) {
this.generator.visitExpr(ast.args[0]);
this.generator.emit(' or ');
this.generator.visitExpr(ast.args[1]);
}
getClientName() {
this.generator.imports.push({
aliasName: `${CORE}Core`,
className: `${CORE}Core`,
packageName: 'darabonba.core',
});
return `${CORE}Core`;
}
}
class String extends Builtin {
replace(ast, level) {
this.getInstanceName(ast);
const args = ast.args;
const regex = ast.args[0].value.string;
const [, extractedString, flag] = regex.match(/\/(.*?)\/(.*)/) || [];
this.generator.emit('.replace');
this.generator.emit(`('${extractedString}', `);
this.generator.visitExpr(args[1], level);
if (flag.includes('i')) {
this.generator.emit(', flags=re.IGNORECASE)');
return;
}
if (!flag.includes('g')) {
this.generator.emit(', 1)');
return;
}
this.generator.emit(')');
}
contains(ast, level) {
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(' in ');
this.getInstanceName(ast);
}
length(ast) {
this.generator.emit('len(');
this.getInstanceName(ast);
this.generator.emit(')');
}
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('.find');
this.generator.visitArgs(args, level);
}
subString(ast, level) {
this.getInstanceName(ast);
const args = ast.args;
this.generator.emit('[');
this.generator.visitExpr(args[0], level);
this.generator.emit(':');
this.generator.visitExpr(args[1], level);
this.generator.emit(']');
}
toLower(ast) {
this.getInstanceName(ast);
this.generator.emit('.lower()');
}
toUpper(ast) {
this.getInstanceName(ast);
this.generator.emit('.upper()');
}
equals(ast) {
this.getInstanceName(ast);
const expr = ast.args[0];
this.generator.emit(' == ');
this.generator.visitExpr(expr);
}
empty(ast) {
this.generator.emit('not ');
this.getInstanceName(ast);
}
toBytes(ast) {
const expr = ast.args[0];
this.getInstanceName(ast);
this.generator.emit('.encode(');
if (expr.value.string === 'utf8'){
this.generator.emit('\'utf-8\'');
}else{
this.generator.visitExpr(expr);
}
this.generator.emit(')');
}
parseInt(ast) {
this.generator.emit('int(');
this.getInstanceName(ast);
this.generator.emit(')');
}
parseLong(ast) {
this.generator.emit('int(');
this.getInstanceName(ast);
this.generator.emit(')');
}
parseFloat(ast) {
this.generator.emit('float(');
this.getInstanceName(ast);
this.generator.emit(')');
}
parseDouble(ast) {
this.generator.emit('float(');
this.getInstanceName(ast);
this.generator.emit(')');
}
trim(ast) {
this.getInstanceName(ast);
this.generator.emit('.strip()');
}
}
class Array extends Builtin {
constructor(generator) {
const methods = ['toJSON'];
super(generator, `${CORE}Array`, methods);
}
join(ast, level) {
// this.generator.emit(`'`);
this.generator.visitExpr(ast.args[0], level);
this.generator.emit('.join(');
this.getInstanceName(ast);
this.generator.emit(')');
}
contains(ast, level) {
// this.generator.emit(`if `);
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(' in ');
this.getInstanceName(ast);
}
length(ast) {
this.generator.emit('len(');
this.getInstanceName(ast);
this.generator.emit(')');
}
index(ast, level) {
this.getInstanceName(ast);
this.generator.emit('.index(');
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(')');
}
get(ast, level) {
this.getInstanceName(ast);
this.generator.emit('[');
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(']');
}
sort(ast) {
if (ast.args[0].value.string === 'acs'){
this.generator.emit('sorted(');
this.getInstanceName(ast);
this.generator.emit(')');
}else{
this.generator.emit('sorted(');
this.getInstanceName(ast);
this.generator.emit(', reverse=True');
this.generator.emit(')');
}
}
shift(ast) {
this.getInstanceName(ast);
this.generator.emit('.pop(0)');
}
pop(ast) {
this.getInstanceName(ast);
this.generator.emit('.pop()');
}
unshift(ast, level) {
this.getInstanceName(ast);
this.generator.emit('.insert(0, ');
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(')');
}
push(ast, level) {
this.getInstanceName(ast);
this.generator.emit('.insert(');
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(')');
}
concat(ast, level) {
this.getInstanceName(ast);
this.generator.emit(' + ');
this.generator.visitExpr(ast.args[0], level);
}
append(ast, level) {
this.getInstanceName(ast);
this.generator.emit('.insert(');
if (ast.args[1]) {
this.generator.visitExpr(ast.args[1], level);
this.generator.emit(', ');
}
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(')');
}
remove(ast, level) {
this.getInstanceName(ast);
this.generator.emit('.remove(');
this.generator.visitExpr(ast.args[0], level);
this.generator.emit(')');
}
}
class Map extends Builtin {
constructor(generator) {
const methods = [];
super(generator, `${CORE}Map`, methods);
}
toJSON(ast) {
this.generator.imports.push({
className: 'json',
});
this.generator.emit('json.dumps(');
this.getInstanceName(ast);
this.generator.emit(')');
}
length(ast) {
this.generator.emit('len(');
this.getInstanceName(ast);
this.generator.emit(')');
}
keySet(ast) {
this.getInstanceName(ast);
this.generator.emit('.keys()');
}
entries(ast) {
this.getInstanceName(ast);
this.generator.emit('.items()');
}
merge(ast) {
this.getInstanceName(ast);
this.generator.emit('.update(');
this.generator.visitExpr(ast.args[0]);
this.generator.emit(')');
}
}
class Entry extends Builtin {
key() {
this.generator.emit('k');
}
value() {
this.generator.emit('v');
}
}
class Date extends Builtin {
constructor(generator) {
const methods = [
// 'format', 'unix', 'diff', 'UTC', 'add', 'sub', 'hour',
// 'minute', 'second', 'dayOfYear', 'dayOfMonth', 'dayOfWeek',
// 'weekOfYear', 'weekOfMonth', 'month', 'year'
];
super(generator, `${CORE}Date`, methods);
}
format(ast) {
this.generator.emit(`${ast.left.id.lexeme}.strftime(`);
this.generator.emit('\'%Y-%m-%d %H:%M:%S\'');
this.generator.emit(')');
}
unix(ast) {
this.getInstanceName(ast);
this.generator.emit('.timestamp(');
this.generator.emit(')');
}
dayOfWeek(ast) {
this.getInstanceName(ast);
this.generator.emit('.weekday()');
}
UTC(ast) {
this.getInstanceName(ast);
this.generator.emit('.UTC()');
}
}
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;
};