@extjs/sencha-cmd-linux-32
Version:
Productivity and performance optimization tool for building applications with Sencha Ext JS and Sencha Touch.
787 lines (651 loc) • 20.1 kB
JavaScript
"use strict";
var Fashion = require('./Base.js'),
Base = Fashion.Base;
var Type = require('./type/Type.js');
var List = require('./type/List.js');
var Bool = require('./type/Bool.js');
var Color = require('./type/Color.js');
var ColorRGBA = require('./type/ColorRGBA.js');
var Text = require('./type/Text.js');
var Literal = require('./type/Literal.js');
var Statics = require('./type/Statics.js');
var TypeVisitor = require('./type/TypeVisitor.js');
var Types = require('./type/Types.js');
class Scope {
constructor(prev) {
this.prev = prev;
this.map = {};
this.sourceInfo = null;
}
get(name) {
var map = this.map,
prev = this,
value;
while (map) {
value = map[name];
if (value) {
return value;
}
prev = prev.prev;
map = prev && prev.map;
}
return value;
}
has(name) {
//return name in this.map;
var map = this.map,
prev = this;
while (map) {
if (name in map) {
return true;
}
prev = prev.prev;
map = prev && prev.map;
}
return false;
}
put(name, value) {
this.map[name] = value;
return value;
}
addEntries(names) {
if (this.prev) {
this.prev.addEntries(names);
}
for (var name in this.map) {
names[name] = this.map[name];
}
}
getEntries(entries) {
entries = entries || {};
this.addEntries(entries);
return entries;
}
getSourceInfo() {
return this.sourceInfo;
}
getCallStack(stack) {
stack = stack || [];
if (this.sourceInfo) {
stack.push(this.sourceInfo);
}
if (this.prev) {
this.prev.getCallStack(stack);
}
return stack;
}
}
Fashion.apply(Scope.prototype, {
$isScope: true,
map: undefined,
prev: undefined,
// placeholder used to track what to reset the _currentScope to,
resetScope: undefined
});
class Runtime extends Base {
constructor(config) {
super(config);
var me = this;
me.mixins = {};
me.functions = {};
me.processors = [];
me.registered = {
runtime: me,
box: Statics.boxType,
unbox: Statics.unboxType,
isArray: function (array) {
return Array.isArray(array);
},
getRuntime: function () {
return this.runtime;
},
handleArgs: function (args, keys) {
var scope = {},
index = 0,
key;
for (var a = 0; a < args.length; a++) {
var arg = args[a];
if (arg === undefined) {
continue;
}
// Named arguments
if (arg === true || arg === false) {
scope[keys[index]] = arg;
index++;
}
else if (arg.type === undefined) {
for (key in arg) {
scope[key.replace(/^\$/, '')] = arg[key];
}
}
// Required arguments
else {
key = keys[index];
if (key instanceof Array) {
key = key[0];
scope[key] = scope[key] || new List();
scope[key].add(arg);
}
else {
scope[key] = arg;
index++;
}
}
}
return scope;
},
sliceArgs: function (args, start, end) {
return this.getRuntime().sliceArgs(args, start, end).items;
},
tailArgs: function (start, args) {
var tail = Array.prototype.slice.call(args, start);
if (tail.length == 1 && this.isArray(tail)) {
tail = tail[0];
}
return tail;
}
};
}
bool(value) {
return new Bool(value);
}
color(name) {
var rgb = Color.map[name],
color = new ColorRGBA(rgb[0], rgb[1], rgb[2], rgb[3]);
color.stringified = name;
return color;
}
quote(value) {
if (value.type === 'string') {
return value;
}
return new Text(value.toString());
}
unquote(value) {
if (value.$isFashionType) {
return value.unquote();
}
return new Literal(value.toString());
}
not(expression) {
return this.box(this.unbox(expression) == false);
}
operate(operation, left, right) {
if (left == null || left.$isFashionNull) {
if (operation != '==' && operation != '!=') {
return Literal.Null;
}
}
if (right == null || right .$isFashionNull) {
if (operation != '==' && operation != '!=') {
return Literal.Null;
}
}
return left.operate(operation, right);
}
reset() {
this._currentScope = null;
this._currentCallStackScope = this.createCallStackScope();
this._globalScope = this.createScope();
this._dynamics = {};
}
run(code, metadata) {
this.load(code);
this.compile(code);
return this.execute(metadata);
}
createTypesBlock (types) {
types = types || this.types;
var keys = Object.getOwnPropertyNames(types),
buff = [],
name;
for (var i = 0; i < keys.length; i++) {
name = keys[i];
buff.push(name + ' = Types.' + name);
buff.push("__" + name + ' = ' + name);
}
if (buff.length === 0) {
return '';
}
return 'var ' + buff.join(',\n ') + ';\n';
}
createMethodBlock (proto) {
proto = proto || this.constructor.prototype;
var buff = [],
keys, name;
while(proto) {
keys = Object.getOwnPropertyNames(proto);
for (var i = 0; i < keys.length; i++) {
name = keys[i];
if (typeof proto[name] === 'function') {
buff.push("__rt_" + name + ' = __rt.' + name + '.bind(__rt)');
}
}
proto = Object.getPrototypeOf(proto);
}
if (buff.length === 0) {
return '';
}
return 'var ' + buff.join(',\n ') + ';\n';
}
createPropertyBlock() {
var keys = Object.getOwnPropertyNames(this),
buff = [],
name;
for (var i = 0; i < keys.length; i++) {
name = keys[i];
buff.push("__rt_" + name + ' = __rt.' + name);
}
if (buff.length === 0) {
return '';
}
return 'var ' + buff.join(',\n ') + ';\n';
}
createPrefixedFunctionBody(code) {
code = this.createTypesBlock() +
this.createMethodBlock() +
this.createPropertyBlock() +
code;
return code;
}
createWrappedFn(code) {
return new Function('Types', '__rt', '__gs', '__udf', '__dyn', this.createPrefixedFunctionBody(code));
}
callWrappedFn(fn, dynamics) {
return fn(Fashion, this, this._globalScope, undefined, dynamics || {});
}
compile(code) {
var me = this,
theFn;
//code = '"use strict";\n' + code;
this.code = code;
new Function();
theFn = this.createWrappedFn(code);
this.fn = function (rt, overrides, dyn) {
var runtime = rt || me,
dynamics = dyn || {};
runtime.reset();
if (overrides) {
if (overrides.$isScope) {
runtime._globalScope = overrides;
} else {
runtime._globalScope.map = overrides;
}
}
if (dyn) {
runtime._dynamics = dyn;
}
runtime._currentScope = runtime._globalScope;
runtime._scopeStack = [runtime._currentScope];
try {
theFn(me.types, runtime, runtime._globalScope, undefined, dynamics);
}
catch (err) {
Fashion.raiseAt(err.message || err, null, runtime.getCallStack());
}
return runtime._globalScope;
};
return this.fn;
}
execute(metadata) {
return this.fn(this, metadata);
}
load(code) {
this.code = code;
return this;
}
registerProcessor(proc) {
this.processors.push(new TypeVisitor(proc));
}
register(methods) {
if (methods['dynamic']) {
Fashion.error('Cannot register javascript function named "dynamic"');
delete methods['dynamic'];
}
if (methods['require']) {
Fashion.error('Cannot register javascript function named "require"');
delete methods['require'];
}
Fashion.apply(this.registered, methods);
}
isRegistered(name) {
name = this.reserved[name] ? '__' + name : name;
return !!this.registered[name];
}
getGlobalScope() {
return this._globalScope;
}
getCurrentScope() {
return this._currentScope;
}
getRegisteredFunctions() {
return this.registered;
}
getFunctions() {
return this.functions;
}
getMixins() {
return this.mixins;
}
createScope(scope) {
var currScope = scope || this._currentScope,
newScope = new Scope(currScope);
return this.pushScope(newScope);
}
pushScope(scope) {
scope.resetScope = this._currentScope;
this._currentScope = scope;
return scope;
}
popScope() {
this._currentScope = this._currentScope.resetScope;
return this._currentScope;
}
createCallStackScope(scope) {
var currScope = scope || this._currentCallStackScope,
newScope = new Scope(currScope);
return this.pushCallStackScope(newScope);
}
pushCallStackScope(scope) {
scope.resetScope = this._currentCallStackScope;
this._currentCallStackScope = scope;
return scope;
}
popCallStackScope() {
this._currentCallStackScope = this._currentCallStackScope.resetScope;
return this._currentCallStackScope;
}
getCallStack() {
if (this._currentCallStackScope) {
return this._currentCallStackScope.getCallStack();
}
return null;
}
pushSourceInfo(info) {
if (this._currentCallStackScope) {
this._currentCallStackScope.sourceInfo = info;
}
return true;
}
getSourceInfo() {
var stack = this._currentCallStackScope,
info = stack && stack.sourceInfo;
if (info && info.length) {
return {
lineNumber: info[0],
file: info[1]
};
}
return null;
}
get(name) {
var scope = this.getScopeForName(name),
res = scope.map[name];
if (typeof res === 'undefined') {
if (!(name in scope.map)) {
Fashion.raiseAt('Reference to undeclared variable : ' + name, null, this.getCallStack());
}
}
return this.box(res);
}
getScopeForName (jsName) {
var scope = this._currentScope;
while (scope) {
if (jsName in scope.map) {
return scope;
}
scope = scope.prev;
}
return this._currentScope;
}
getDefault(val) {
if (val == null || typeof val === 'undefined') { // === null || undefined
return undefined;
}
if (val.$isFashionNull) {
if (this.constructor.allowNullDefaults) {
return val;
}
return undefined;
}
return this.box(val);
}
getGlobalDefault(jsName) {
var obj = this._globalScope.get(jsName);
return this.getDefault(obj);
}
getLocalDefault(jsName) {
var obj = this._currentScope.get(jsName);
return this.getDefault(obj);
}
setGlobal(jsName, value, astNodeId) {
var currScope = this._globalScope;
if (!value || !value.$isFashionLiteral) {
value = this.box(value);
}
value.ast = value.ast || this.getAstNode(astNodeId);
currScope.map[jsName] = value;
return value;
}
setDynamic(name, value, astNodeId) {
var jsName = Fashion.getJsName(name),
currScope = this._globalScope,
newValue;
if (!value || !value.$isFashionLiteral) {
value = this.box(value);
}
value.ast = value.ast || this.getAstNode(astNodeId);
if (value.$referenceName || value.$constant) {
newValue = value.clone();
newValue.$previousReference = value;
value = newValue;
value.ast = this.getAstNode(astNodeId);
}
else {
value.$referenceName = name;
}
currScope.map[jsName] = value;
return value;
}
setScoped (jsName, value) {
var currScope = this.getScopeForName(jsName);
if (!value || !value.$isFashionLiteral) {
value = this.box(value);
}
currScope.map[jsName] = value;
return value;
}
set (jsName, value) {
var currScope = this._currentScope;
if (!value || !value.$isFashionLiteral) {
value = this.box(value);
}
currScope.map[jsName] = value;
return value;
}
getDocs(id) {
if (this.docCache) {
return this.docCache.get(id);
}
}
getString(id) {
if (this.stringCache) {
return this.stringCache.get(id);
}
}
getAstNode(id) {
if (this.nodeCache) {
return this.nodeCache.get(id);
}
}
applySpread(arg) {
arg.spread = true;
return arg;
}
sliceArgs(args, start, end) {
start = start || 0;
end = end || args.length;
var filtered = [],
newArgs = [],
separator = ', ',
spread, a, arg;
for (a = start; a < end; a++) {
arg = args[a];
if (!arg) {
if (!spread) {
filtered.push(arg);
}
continue;
}
if (arg.spread && arg.$isFashionList) {
if (spread) {
filtered.push(spread);
}
spread = arg;
separator = spread.separator || separator;
} else {
filtered.push(arg);
}
}
for (a = 0; a < filtered.length; a++) {
arg = filtered[a];
separator = (arg && arg.splatSeparator) || separator;
newArgs.push(filtered[a]);
}
if (spread) {
newArgs.push.apply(newArgs, spread.items);
}
return new List(newArgs, separator);
}
applySpreadArgs(args, name) {
var newArgs = [],
hadSpread = false,
offset = 0,
arg, a, item, i, items, key, map, defaults, proc, param, paramName;
proc = this.context && this.context.preprocessor;
if (proc) {
defaults = proc.mixinDeclarations[name];
if (defaults) {
offset = 1;
}
else {
defaults = proc.functionDeclarations[name]
}
defaults = defaults && defaults.parameters;
}
for (a = 0; a < args.length; a++) {
arg = args[a];
if (arg && arg.spread && arg.$isFashionMap && defaults) {
items = arg.items;
map = {};
for (key in arg.map) {
map['$' + Fashion.getJsName(key)] = arg.map[key];
}
for (var p = 0; p < defaults.length; p++) {
param = defaults[p];
paramName = Fashion.getJsName(param.name);
if (paramName in map) {
newArgs.push(items[map[paramName]]);
delete map[paramName];
}
else if (!param.varArgs) {
newArgs.push(undefined);
}
}
for (key in map) {
item = items[map[key]];
newArgs.push(item);
}
hadSpread = true;
}
else if (arg && arg.spread && arg.$isFashionList) {
items = arg.getItems();
for (i = 0; i < items.length; i++) {
item = items[i];
item && (item.splatSeparator = arg.separator);
newArgs.push(item);
}
hadSpread = true;
} else if (arg || !hadSpread) {
newArgs.push(arg);
}
// clear the flag indicating the spread argument
// so subsequent calls using this same variable will not
// be contaminated
arg && (arg.spread = undefined);
}
var misisngParams = this.context && this.context.missingParameters;
if (misisngParams && (misisngParams == 'error')) {
if (defaults) {
for (var d = 0; d < defaults.length; d++) {
if (!defaults[d].hasOwnProperty('default') && !defaults[d].varArgs) {
if (newArgs[d + offset] === undefined) {
Fashion.raiseAt("No value supplied for argument : " + defaults[d].name, null, this.getCallStack());
}
}
}
}
}
return newArgs;
}
warn(arg) {
Fashion.warn(arg, this.getSourceInfo());
}
error(arg) {
Fashion.raiseAt(arg, null, this.getCallStack());
}
debug() {
Fashion.debug.apply(Fashion, arguments);
}
setCaches (transpiler) {
this.docCache = transpiler.docCache;
this.stringCache = transpiler.stringCache;
this.nodeCache = transpiler.nodeCache;
}
copyRuntimeState (runtime) {
this._dynamics = runtime._dynamics;
this.registered = runtime.registered;
this.functions = runtime.functions;
this.mixins = runtime.mixins;
}
test (val) {
val = this.unbox(val);
if (val == null || val === false) {
return false;
}
return true;
}
and (a, b) {
if (this.test(a)) {
return b;
}
return a;
}
or (a, b) {
if (this.test(a)) {
return a;
}
return b;
}
}
Fashion.apply(Runtime.prototype, {
box: Type.box,
unbox: Type.unbox,
Scope: Scope,
isFashionRuntime: true,
functions: null,
code: null,
fn: null,
stringCache: null,
docCache: null,
types: Types,
_globalScope: null,
_currentScope: null,
_dynamics: null,
context: null,
reserved: {
'if': true,
'else': true
}
});
module.exports = Runtime;