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

'use strict'; const DSL = require('@darabonba/parser'); const { _vid, _name, _upperFirst, _setValueFunc, _isFilterType } = 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 = [ 'int8', 'int16', 'int32', 'int64', 'uint32', 'uint64', 'uint8', 'uint16', ]; class Builtin { constructor(generator, module = '', methods = []){ this.generator = generator; this.moduleName = module; methods.forEach(method => { this[method] = function(args, level, env, argHasThrowFunc) { this.generator.emit(`dara.${_upperFirst(method)}`); this.generator.visitArgs(args, level, env, argHasThrowFunc); }; }); } getInstanceName(ast) { if (ast.left.id.tag === DSL.Tag.Tag.VID) { this.generator.emit(`${_vid(ast.left.id)}`); } else { this.generator.emit(`${_name(ast.left.id)}`); } } visitExpr(args, level, env, argHasThrowFunc) { for(let i = 0; i < args.length; i++) { const expr = args[i]; if (argHasThrowFunc && argHasThrowFunc.get(i)) { this.generator.emit(argHasThrowFunc.get(i)); } else { this.generator.visitExpr(expr, level, env); } if(i !== args.length - 1) { this.generator.emit(', '); } } } } class Env extends Builtin { constructor(generator){ super(generator); } get(args, level, env, argHasThrowFunc){ this.generator.emit('os.Getenv('); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } set(args, level, env, argHasThrowFunc){ this.generator.emit(`os.Setenv(`); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } } class Logger extends Builtin { constructor(generator){ const methods = ['log', 'info', 'debug', 'error', 'warning']; super(generator, 'fmt', []); methods.forEach(method => { this[method] = function(args, level, env, argHasThrowFunc) { this.generator.builtinModule.push({ path: 'fmt' }); this.generator.emit(`fmt.Printf("[${method.toUpperCase()}] %s\\n", `); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); }; }); } error(args, level, env, argHasThrowFunc){ this.generator.emit(`dara.Fprintf(os.Stderr, "[ERROR] %s\\n", `); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } } class XML extends Builtin { constructor(generator){ const methods = ['parseXml', 'toXML']; super(generator, 'Dara', methods); } } class URL extends Builtin { constructor(generator){ const methods = ['parse', 'urlEncode', 'percentEncode', 'pathEncode']; super(generator, 'Dara', methods); } parse(args, level, env, argHasThrowFunc) { this.generator.emit(`dara.ParseURL`); this.generator.visitArgs(args, level, env, argHasThrowFunc); } } class Stream extends Builtin { constructor(generator){ const methods = ['readAsBytes', 'readAsJSON', 'readAsString', 'readAsSSE']; super(generator, 'DaraStream', methods); } } class Number extends Builtin { constructor(generator){ const methods = ['random', 'floor', 'round', 'min', 'max']; super(generator, 'DaraMath', methods); } parseInt(ast) { this.generator.emit('int('); this.getInstanceName(ast); this.generator.emit(')'); } parseLong(ast) { this.generator.emit('int64('); this.getInstanceName(ast); this.generator.emit(')'); } parseFloat(ast) { this.generator.emit('float32('); this.getInstanceName(ast); this.generator.emit(')'); } parseDouble(ast) { this.generator.emit('float64('); this.getInstanceName(ast); this.generator.emit(')'); } itol(ast) { this.generator.emit('int64('); this.getInstanceName(ast); this.generator.emit(')'); } ltoi(ast) { this.generator.emit('int('); this.getInstanceName(ast); this.generator.emit(')'); } } class JSON extends Builtin { constructor(generator){ const methods = ['stringify', 'parseJSON']; super(generator, 'DaraJSON', methods); } } 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 Bytes extends Builtin { constructor(generator){ const methods = []; super(generator, 'DaraBytes', methods); } from(args, level, env, argHasThrowFunc) { this.generator.emit(`dara.BytesFromString`); this.generator.visitArgs(args, level, env, argHasThrowFunc); } toString(ast, level){ this.generator.emit('dara.ToString('); this.getInstanceName(ast, level); this.generator.emit(')'); } toHex(ast, level){ this.generator.builtinModule.push({ path: 'encoding/hex' }); this.generator.emit('hex.EncodeToString('); this.getInstanceName(ast, level); this.generator.emit(')'); } toBase64(ast, level){ this.generator.builtinModule.push({ path: 'encoding/base64' }); this.generator.emit('base64.StdEncoding.EncodeToString('); this.getInstanceName(ast, level); this.generator.emit(')'); } toJSON(ast, level) { this.toString(ast, level); } length(ast){ this.generator.emit('len('); this.getInstanceName(ast); this.generator.emit(')'); } } class Converter extends Builtin { constructor(generator){ super(generator); this.generator = generator; integers.forEach(type => { this[type] = function(args, level) { const expr = args[0]; generator.emit(`dara.Force${_upperFirst(type)}(`); generator.visitExpr(expr, level, { pointer: false, pointerParams: [] }); generator.emit(')'); }; }); } integer(args, level, env, argHasThrowFunc) { this.generator.emit('dara.ForceInt('); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } long(args, level, env, argHasThrowFunc) { this.generator.emit('dara.ForceInt64('); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } ulong(args, level, env, argHasThrowFunc) { this.generator.emit('dara.ForceUint64('); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } float(args, level, env, argHasThrowFunc) { this.generator.emit('dara.ForceFloat32('); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } double(args, level, env, argHasThrowFunc) { this.generator.emit('dara.ForceFloat64('); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } string(args, level, env, argHasThrowFunc) { this.generator.emit('dara.ToString('); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } number(args, level, env, argHasThrowFunc) { this.generator.emit('dara.ForceInt('); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } boolean(args, level, env, argHasThrowFunc) { this.generator.emit('dara.ForceBoolean('); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } bytes(args, level, env, argHasThrowFunc) { this.generator.emit('[]byte(dara.ToString('); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit('))'); } any(args, level, env, argHasThrowFunc){ this.visitExpr(args, level, env, argHasThrowFunc); } object(args, level, env, argHasThrowFunc){ this.generator.emit(`dara.ToMap(`); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } readable(args, level, env, argHasThrowFunc){ this.generator.emit(`dara.ToReader(`); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } writable(args, level, env, argHasThrowFunc){ this.generator.emit(`dara.ToWriter(`); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } } class Func { constructor(generator){ this.generator = generator; } default(args, level, env, argHasThrowFunc) { this.generator.emit('dara.Default('); this.generator.visitExpr(args[0], level, env, argHasThrowFunc); this.generator.emit(', '); this.generator.visitExpr(args[1], level, env, argHasThrowFunc); this.generator.emit(')'); } isNull(args, level, env, argHasThrowFunc) { this.generator.emit('dara.IsNil('); this.generator.visitExpr(args[0], level, env, {pointer: true, pointerParams: []}); this.generator.emit(')'); } sleep(args, level, env, argHasThrowFunc) { this.generator.builtinModule.push({ path: 'time' }); this.generator.emit('time.Sleep(time.Duration('); this.generator.visitExpr(args[0], level, env, argHasThrowFunc); this.generator.emit(') * time.Millisecond)'); } equal(args, level, env, argHasThrowFunc) { this.generator.visitExpr(args[0], level, env, argHasThrowFunc); this.generator.emit(' == '); this.generator.visitExpr(args[1], level, env, argHasThrowFunc); } } function convertJsRegexStrToRegExp(jsRegexStr) { const matches = jsRegexStr.match(/^\/(.+)\/([gimuy]*)$/); if (!matches) { throw new Error('正则表达式格式错误应为 /pattern/flags'); } const [, pattern, flags] = matches; let goRegexStr = pattern; if (flags.includes('i')) { goRegexStr = '(?i)' + goRegexStr; } return goRegexStr; } class String extends Builtin { constructor(generator){ super(generator, 'DaraString'); } replace(ast, level, env, argHasThrowFunc) { this.generator.builtinModule.push({ path: 'regexp' }); const args = ast.args; const regex = convertJsRegexStrToRegExp(args[0].value.string); this.generator.emit(`regexp.MustCompile(\`${regex}\`).ReplaceAllString(`); this.getInstanceName(ast); this.generator.emit(', '); this.generator.visitExpr(args[1], level, env, argHasThrowFunc); this.generator.emit(')'); } contains(ast, level, env, argHasThrowFunc) { this.generator.emit(`dara.Contains(`); this.getInstanceName(ast); const args = ast.args; this.generator.emit(', '); this.generator.visitExpr(args[0], level, env, argHasThrowFunc); this.generator.emit(')'); } length(ast) { this.generator.emit(`dara.Length(`); this.getInstanceName(ast); this.generator.emit(')'); } hasPrefix(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.HasPrefix(`); this.getInstanceName(ast); this.generator.emit(', '); this.generator.visitExpr(args[0], level, env, argHasThrowFunc); this.generator.emit(')'); } hasSuffix(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.HasSuffix(`); this.getInstanceName(ast); this.generator.emit(', '); this.generator.visitExpr(args[0], level, env, argHasThrowFunc); this.generator.emit(')'); } index(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.Index(`); this.getInstanceName(ast); this.generator.emit(', '); this.generator.visitExpr(args[0], level, env, argHasThrowFunc); this.generator.emit(')'); } subString(ast, level, env, argHasThrowFunc) { const args = ast.args; this.getInstanceName(ast); this.generator.emit('['); this.generator.visitExpr(args[0], level, env, argHasThrowFunc); this.generator.emit(': '); this.generator.visitExpr(args[1], level, env, argHasThrowFunc); this.generator.emit(']'); } trim(ast) { this.generator.emit(`dara.TrimSpace(`); this.getInstanceName(ast); this.generator.emit(')'); } toLower(ast) { this.generator.emit(`dara.ToLower(`); this.getInstanceName(ast); this.generator.emit(')'); } toUpper(ast) { this.generator.emit(`dara.ToUpper(`); this.getInstanceName(ast); this.generator.emit(')'); } equals(ast, level, env, argHasThrowFunc) { this.getInstanceName(ast); const args = ast.args; const expr = args[0]; this.generator.emit(' == '); this.generator.visitExpr(expr, level, env, argHasThrowFunc); } empty(ast) { this.generator.emit('len('); this.getInstanceName(ast); this.generator.emit(')'); this.generator.emit(' == 0'); } toBytes(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit('dara.ToBytes('); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } parseInt(ast) { this.generator.builtinModule.push({ path: 'strconv' }); this.generator.emit('strconv.Atoi('); this.getInstanceName(ast); this.generator.emit(')'); } parseLong(ast) { this.generator.builtinModule.push({ path: 'strconv' }); this.generator.emit('strconv.ParseInt('); this.getInstanceName(ast); this.generator.emit(', 10, 64)'); } parseFloat(ast) { this.generator.builtinModule.push({ path: 'strconv' }); this.generator.emit('strconv.ParseFloat('); this.getInstanceName(ast); this.generator.emit(', 32)'); } parseDouble(ast) { this.generator.builtinModule.push({ path: 'strconv' }); this.generator.emit('strconv.ParseFloat('); this.getInstanceName(ast); this.generator.emit(', 64)'); } } class Array extends Builtin { constructor(generator){ super(generator, 'DaraArray'); } join(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.ArrJoin(`); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } full(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.ArrFull(&`); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } shift(ast) { this.generator.emit(`dara.ArrShift(&`); this.getInstanceName(ast); this.generator.emit(')'); } pop(ast) { this.generator.emit(`dara.ArrPop(&`); this.getInstanceName(ast); this.generator.emit(')'); } push(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.ArrPush(&`); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } unshift(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.ArrUnshift(&`); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } contains(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.ArrContains(`); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } length(ast) { this.generator.emit('len('); this.getInstanceName(ast); this.generator.emit(')'); } index(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.ArrIndex(`); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } get(ast, level, env, argHasThrowFunc) { this.getInstanceName(ast); const args = ast.args; this.generator.emit(`[`); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(`]`); } sort(ast, level, env, argHasThrowFunc) { this.generator.emit('dara.SortArr('); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(ast.args, level, env, argHasThrowFunc); this.generator.emit(').('); this.generator.emit('[]'); this.generator.visitPointerType(ast.inferred.itemType); this.generator.emit(')'); } concat(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.ConcatArr(`); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(').('); this.generator.emit('[]'); this.generator.visitPointerType(ast.inferred.itemType); this.generator.emit(')'); } append(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.ArrAppend(&`); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } remove(ast, level, env, argHasThrowFunc) { const args = ast.args; this.generator.emit(`dara.ArrRemove(&`); this.getInstanceName(ast); this.generator.emit(', '); this.visitExpr(args, level, env, argHasThrowFunc); this.generator.emit(')'); } } class Map extends Builtin { constructor(generator){ super(generator, 'DaraMap'); } length(ast) { this.generator.emit(`len(`); this.getInstanceName(ast); this.generator.emit(')'); } keySet(ast) { this.generator.emit(`dara.KeySet(`); this.getInstanceName(ast); this.generator.emit(')'); } entries(ast) { this.generator.emit(`dara.Entries(`); this.getInstanceName(ast); this.generator.emit(')'); } toJSON(ast) { this.generator.emit(`dara.Stringify(`); this.getInstanceName(ast); this.generator.emit(')'); } merge(ast, level, env, argHasThrowFunc) { this.generator.emit('dara.ToMap('); this.getInstanceName(ast); this.generator.emit(' , '); this.visitExpr(ast.args, level, env, argHasThrowFunc); this.generator.emit(')'); } } class Entry extends Builtin { key(ast) { this.getInstanceName(ast); this.generator.emit('.Key'); } value(ast) { let setValue = false; if(((ast.inferred.type === 'array' && ast.inferred.itemType.type === 'basic') || (DSL.util.isBasicType(_name(ast.inferred)) && !_isFilterType(_name(ast.inferred))))) { setValue = true; this.generator.emit(_setValueFunc(_name(ast.inferred))); } this.getInstanceName(ast); this.generator.emit('.Value'); if(ast.inferred.type !== 'basic' || ast.inferred.name !== 'any') { this.generator.emit('.('); this.generator.visitPointerType(ast.inferred); this.generator.emit(')'); } if(setValue) { this.generator.emit(')'); } } } class ModelInstance extends Builtin { toMap(ast) { this.generator.emit('dara.ToMap('); this.getInstanceName(ast); this.generator.emit(')'); } } 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); builtin['$ModelInstance'] = new ModelInstance(generator); return builtin; };