@script name="XglCompiler" hide="y">
Implements the XGL Compiler
(c) SAP AG 2003-2006. All rights reserved.
#CACHE[OFF]
function XglCompiler() {
this.scenarioCompiler = new XglScenarioCompiler();
this.processCompiler = new XglProcessCompiler();
}
XglCompiler.prototype.compileUnit = function(unit, out, debugMode) {
if (ISA(unit,'gml2:Process','gml2:BlackProcess')) {
var compiler = this.processCompiler;
} else {
var compiler = this.scenarioCompiler;
}
compiler.unit = unit;
compiler.out = out;
compiler.debugMode = debugMode;
compiler.damageScope = debugMode ? #[XGL_DAMAGE_FULL] : unit.xglDirty;
if (compiler.damageScope==#[XGL_DAMAGE_NONE]) return;
try {
compiler.compileHeader();
compiler.compileBody();
compiler.compileFooter();
compiler.translate();
if (!debugMode && out.errorsCount==0) unit.clearXglDirty();
} catch(e) {
out.error('#TEXT[XMSG_CP_ERR_INTERNAL]' + e.description);
}
}
XglCompiler.prototype.compileHeader = function() {
var out=this.out, unit=this.unit;
this.root = unit.root;
this.units = {};
this.unitsCounter = 0;
this.xglver = '2.2';
this.xg_ns = 'http:/'+'/www.sap.com/visualcomposer/2006/xgl' + this.xglver;
this.rnt_ns = 'http:/'+'/www.sap.com/visualcomposer/2006/runtime';
this.dbg_ns = 'http:/'+'/www.sap.com/visualcomposer/2008/debugger';
this.xns = {xg:this.xg_ns};
this.rns = {rnt:this.rnt_ns};
this.dns = {dbg:this.dbg_ns};
this.nsBookmark = null;
this.de = $ENV.dynexp;
this.de.resetTranslations();
RULE('setDynExpContext',unit);
this.index = {
nodes:{},
infosets:{},
infoshapes:{},
infoset_holders:{},
interactors:{},
processors:{},
infoactors:{},
operators:{},
relays:{},
enums:{},
actions:{},
specific_events:{},
generic_events:{},
post_plans:[],
palettes:{},
systems:{},
roles:{},
references:{},
popups:{},
propsMetadata:{}
}
this.getUnitAlias(unit);
var urn = unit.urn || unit.id;
var folder = out.createFolder(null, urn);
var xglfile = out.createFile(folder, urn, 'xgl');
folder.caption = (unit.name||urn);
xglfile.caption = (unit.name||urn) + '.xgl';
folder.hint = 'Folder: '+urn;
xglfile.hint = 'File: '+urn+'.xgl';
var tagName = 'xg:' + unit.Class.metadata.xgl.type;
var props = this.getProps(unit,'',{urn:1,description:1});
props.simple['timestamp'] = (new Date()).getTime();
this.printSimpleProps(tagName,props.simple,props.complex);
this.nsBookmark = out.getBookmark();
this.printComplexProps(props.complex);
out.beginTag('rnt:Implementations');
var rntData={runtimeMode:'new'}, empty=true;
if (ISA(unit,'gml2:BlackBox')) {
for (var k in unit.runtimeData) rntData[k] = unit.runtimeData[k];
} else {
rntData.runtimeVersion = this.xglver;
rntData.runtimeEngine = 'XGL';
}
for (var param in rntData) {
empty = false;
var prefix = param.substring(0,param.indexOf(':'));
if(!prefix || (prefix in this.rns)) continue;
var ns = this.rnt_ns + '/' + prefix;
this.rns[prefix] = ns;
}
if (!empty) out.addTag('rnt:Implementation',rntData);
out.endTag();
if (ISA(unit, 'gml2:Scenario')) {
out.beginTag('xg:ExceptionHandlers');
if (unit.msgErrorLevel != 'none') out.addTag('xg:DisplayException',{severity:unit.msgErrorLevel,output:'message'});
if (unit.statusErrorLevel != 'none') out.addTag('xg:DisplayException',{severity:unit.statusErrorLevel,output:'status'});
if (unit.logErrorLevel != 'none') out.addTag('xg:DisplayException',{severity:unit.logErrorLevel,output:'logfile'});
if (unit.promptErrorLevel != 'none') out.addTag('xg:DisplayException',{severity:unit.promptErrorLevel,output:'prompt'});
out.endTag();
}
}
XglCompiler.prototype.compileBody = function() {
// override this method on subclasses
}
XglCompiler.prototype.compileFooter = function() {
var out=this.out;
this.printNSList();
out.endTag();
}
XglCompiler.prototype.translate = function() {
var out=this.out, de=this.de, urn = this.unit.urn || this.unit.id, locale = $ENV.model.getDCInfoProperty(this.unit.impl_location,$ENV.model.MASTER_LANGUAGE) || 'en';
var xlffile = out.createFile(urn, urn, 'xlf');
xlffile.caption = (this.unit.name||urn)+ '.xlf';
xlffile.hint = 'File: '+urn+'.xlf';
out.beginTag('xliff',{version:'1.1'});
out.beginTag('file',{'source-language':locale,datatype:'javaPropertyResourceBundle'});
out.beginTag('header');
out.addTag('skl');
out.addTag('phase-group');
out.beginTag('s2x',{xmlns:'http:/'+'/www.sap.com'});
out.beginTag('dtr');
out.addTag('sc');
out.endTag(); //dtr
out.beginTag('giltDirectives');
out.addTag('develContact',null,'sapuser@sap.com');
out.addTag('domain',null,'Cross Applications');
out.addTag('originalLocale',{'xml:lang':locale});
out.addTag('maxLength',null,'255');
out.endTag(); //giltDirectives
out.endTag(); //s2x
out.endTag(); //header
out.beginTag('body');
translateBody();
out.endTag(); //body
out.endTag(); //file
out.endTag(); //xliff
function translateBody() {
var R = {};
for (var k in de.translations['user']) {
var node = de.translations['user'][k];
classifyNode(node);
}
for (var k in de.translations['default']) {
var node = de.translations['default'][k];
classifyNode(node);
}
for (var k in R) {
out.beginTag('group',{restype:k});
var nodes = R[k], node;
for (var i=0,len=nodes.length; i0) {
props.precedents = step.precedents.join(' ');
}
switch (step.type) {
case 'Invalidate':
props.targets = step.targets;
if (this.debugMode) addDebugInfo(step,node,props);
out.addTag('xg:Invalidate',props);
break;
case 'Map':
addFlowCondition(step,node,props);
var mapping = step.map;
props.source = mapping.sourceInfoset;
props.target = mapping.targetInfoset;
if (this.debugMode) addDebugInfo(step,node,props);
out.beginTag('xg:Map',props);
this.printAssigns(mapping,holder,desc);
out.endTag();
break;
case 'Copy':
addFlowCondition(step,node,props);
props.source = holders[node.source.id];
props.target = holders[node.target.id];
if (this.debugMode) addDebugInfo(step,node,props);
out.addTag('xg:Copy',props);
break;
case 'Trans':
addFlowCondition(step,node,props);
var sparent=node.source.parent, tparent=node.target.parent;
props.source = this.getElementId(sparent);
props.target = this.getElementId(tparent);
if (this.debugMode) addDebugInfo(step,node,props);
out.addTag('xg:Trans',props);
break;
case 'Eval':
props.source = this.getElementId(node);
if (this.debugMode) addDebugInfo(step,node,props);
out.addTag('xg:Eval',props);
break;
}
}
out.endTag();
}
out.endTag();
function addFlowCondition(step,node,props) {
if (step.type == 'Map') {
if (node.assignMode && node.assignMode != 'all') props.assignMode = node.assignMode;
if (node.selectMode && node.selectMode != 'current') props.selectMode = node.selectMode;
} else if (step.type == 'Copy') {
if (node.selectMode && node.selectMode != 'all') props.selectMode = node.selectMode;
}
if (node.guard && node.guard+'' != 'true') {
RULE('setDynExpContext', compiler.unit, node);
var guard = compiler.parseExpr(node.guard,'Boolean',node,'guard',node,'Guard condition');
if (guard !== null) props.guard = guard;
}
}
function addDebugInfo(step,node,props) {
var participants = {}, infosets = compiler.index.infosets;
if (!ISEMPTY(node)) participants[node.id] = true;
if (step.type == 'Invalidate') {
var targets = KEYS2OBJ(step.targets);
for (var set in targets) {
var partners = infosets[set].partners;
for (var k in partners) participants[k] = true;
}
} else if (step.type == 'Eval') {
if (node.id in holders) {
var set = holders[node.id];
var partners = infosets[set].partners;
for (var k in partners) participants[k] = true;
}
}
props['dbg:participants'] = OBJ2KEYS(participants);
}
}
//===============================================================
//+++++++++++++++++++++ RESOURCES Methods +++++++++++++++++++++++
//===============================================================
XglCompiler.prototype.compileImages = function() {
}
XglCompiler.prototype.compilePalettes = function() {
var out=this.out, palettes=this.index.palettes;
out.beginTag('xg:Palettes');
for (var k in palettes) {
var palette = $ENV.palettes.getPalette(k);
out.beginTag('xg:Palette',{name:k});
for (var i=0,len=palette.length; i',' ' + N.join(' ') + '>');
}
XglCompiler.prototype.parseExpr = function(expr,type,elem,prop,view_elem,view_prop,scope,ignore_cache) {
var de = this.de, out = this.out, type = type || 'String';
if (this.damageScope <= #[XGL_DAMAGE_DATA] && !ignore_cache) {
var cache = NVL(elem.xglDECache[prop]);
if (cache !== null) {
this.loadTranslationState(cache);
return cache.val;
}
}
expr = NVL(expr,'') + '';
de.setExpectedType(type);
de.setTranslationScope(scope||'');
de.parse(de.clearExprComments(expr));
if (de.error) {
out.error('#TEXT[XMSG_CP_ERR_METADATA_COMPILE]'.replace('{0}', view_prop) + ' - ' + de.error, view_elem);
if (!ignore_cache) delete elem.xglDECache[prop];
return null;
}
var val = de.xglPrint();
if (!ignore_cache) {
var cache = {val:val, custom:{}};
this.cacheTranslationState(cache);
elem.xglDECache[prop] = cache;
}
return val;
}
XglCompiler.prototype.translateExpr = function(expr,exprType,transType,elem,prop,view_elem,view_prop,scope,ignore_cache) {
var out = this.out, de = this.de, tval = expr, ttype;
if (!expr) return '';
var isExpr = !ISNULL(exprType);
if (isExpr) {
var val = this.parseExpr(expr,exprType,elem,prop,view_elem,view_prop,scope,ignore_cache);
if (val === null) return null;
if (!de.isLiteral) return val;
tval = (de.tree && de.tree.value) || expr;
}
ttype = transType;
if (!transType) return (isExpr? val : expr);
if (typeof transType == 'function') {
try {
ttype = transType(elem,prop);
} catch (e) {
out.error('#TEXT[XMSG_CP_ERR_METADATA_TRANSLATE]'+' "'+view_prop+'"',view_elem);
if (!ignore_cache) elem.invalidateXglDECache(prop);
return null;
}
}
var trans_expr = '=TRANSLATE("'+tval.replace(/\\/g,'\\\\').replace(/\"/g,'\\"')+'","'+ttype+'")';
if (!ignore_cache) elem.invalidateXglDECache(prop);
return this.parseExpr(trans_expr,'String',elem,prop,view_elem,view_prop,scope,ignore_cache);
}
XglCompiler.prototype.cacheTranslationState = function(cacheRecord) {
if (cacheRecord === null) return;
var de = this.de, custom = cacheRecord.custom, keys = {}, found = false;
for (var key in de.translationKeys) {
found = true;
var rec = de.translationKeys[key];
keys[key] = {key:rec.key, text:rec.text, tType:rec.tType, scope:rec.scope};
}
if (found) {
if (!ISEMPTY(custom['keys'])) {
var curr_keys = custom['keys'];
for (var k in curr_keys) keys[k] = curr_keys[k];
}
custom['keys'] = keys;
}
custom['isLiteral'] = de.isLiteral;
}
XglCompiler.prototype.loadTranslationState = function(cacheRecord) {
if (cacheRecord === null) return;
var de = this.de, custom = cacheRecord.custom, keys = custom.keys;
if (!ISEMPTY(keys)) {
for (var key in keys) {
var rec = keys[key];
de.addTranslationKey(rec.key, rec.text, rec.tType, rec.scope);
}
}
if ('isLiteral' in custom) de.isLiteral = custom['isLiteral'];
}
XglCompiler.prototype.extractReference = function(elem, silent) {
var index=this.index;
var targetComponent = elem.targetComponent || '';
if (!targetComponent) {
if(!silent && !this.debugMode) this.out.error('#TEXT[XMSG_MISSING_REF]'.replace('{0}', '' + elem.name + ''),elem);
return '';
}
var component = targetComponent.getComponent();
if(targetComponent.interfaceChecksum != (component && component.interfaceChecksum) ){
var cp = $ENV.createObject('core.gml2:ConflictProvider');
cp.compareComponents(component, component, elem);
if( cp.hasErrors() || cp.hasWarnings() )
this.out.warning( '#TEXT[YMSG_OUT_OFF_SYNC_INTERFACE]'.replace('{0}',elem.name), elem);
}
index.references[targetComponent.id] = {object:targetComponent};
return targetComponent.id;
}
XglCompiler.prototype.extractInfosets = function(node) {
var index=this.index, out=this.out, compiler=this;
var holders=index.infoset_holders, infoshapes=index.infoshapes, infosets=index.infosets;
var elem = node.object, synthetic=BOOL(node.synthetic);
if (ISA(elem,'gml2:DataBoundInteractor')) {
if (!elem.isValidViewNode()) {
out.error('#TEXT[XMSG_CP_ERR_INVALID_VIEWNODE]'+' "'+elem.viewNode+'"',elem);
return;
}
var set = createInfoview(elem);
var base = createBaseInfoset(elem);
node.set = set;
holders[elem.id] = base;
infosets[set].base = base;
for (var k in elem.plugs) {
var plug = elem.plugs[k];
var pset = (ISA(plug,'gml2:PlugIn')? base : set);
holders[plug.id] = pset;
}
} else if (ISA(elem,'gml2:CompositeInteractor','gml2:Infoactor','gml2:GotoView','gml2:BasicStep')) {
for (var k in elem.plugs) {
var plug = elem.plugs[k], pset;
if (!ISA(plug,'dev:IInfoset')) continue;
if (ISA(plug,'gml2:DTPlugIO')) {
var res = plug.checkBoundInfosets();
if (!this.validateResults(res,elem)) continue;
if (plug.infosetOwner == 'outer' && elem.getBindInLink(plug)) pset = plug.getInfosetId();
else pset = createOwnInfoset(plug,true);
}
else pset = createOwnInfoset(plug,true);
holders[plug.id] = pset;
}
} else if (ISA(elem,'gml2:Operator')) {
var isShapeHolder = this.isShapeHolder(elem);
var set = createOwnInfoset(elem,isShapeHolder);
node.set = set;
holders[elem.id] = set;
var inPlugs = elem.getSourceInfosets();
for (var k in elem.plugs) {
var plug = elem.plugs[k];
if (ISA(plug,'gml2:PlugOut')) holders[plug.id] = set;
else {
if (!(plug.id in inPlugs)) continue;
if (synthetic) holders[plug.id] = set;
else {
// verify whether this plug should hold an infoset of its own
var iholder = inPlugs[plug.id], ownSet = false;
for (var l in plug.links) {
var link = plug.links[l];
if (!this.skipCopyStep(link)) {
ownSet = true;
break;
}
}
var iset = (ownSet? createFictiveInfoset(plug,iholder) : iholder.getInfosetId());
holders[plug.id] = iset;
}
}
}
} else if (ISA(elem,'gml2:Port')) {
var set = createOwnInfoset(elem,true);
node.set = set;
holders[elem.id] = set;
for (var k in elem.plugs) {
var plug = elem.plugs[k];
holders[plug.id] = set;
}
} else if (ISA(elem,'gml2:DynamicEnum')) {
var set = createOwnInfoset(elem,true);
node.set = set;
holders[elem.id] = set;
for (var k in elem.plugs) {
var plug = elem.plugs[k];
if (!ISA(plug,'dev:IInfoset')) continue;
var pset = createOwnInfoset(plug,true);
holders[plug.id] = pset;
}
}
function createOwnInfoset(elem, isShapeHolder) {
var infosetId = elem.getInfosetId();
if (infosetId in infosets) return infosetId;
var data = null;
if (ISA(elem,'gml2:PInitBlock')) {
var res = elem.buildInitBlock();
if (compiler.validateResults(res,elem)) data = res.results;
}
var set = {id:infosetId,type:'S',data:data,holder:elem,partners:{}};
set.partners[elem.id] = true;
attachInfoshape(elem,set,isShapeHolder);
infosets[infosetId] = set;
return infosetId;
}
function createBaseInfoset(elem) {
var infosetId = elem.getBaseInfosetId();
if (infosetId in infosets) return infosetId;
var baseElemId = infosetId.replace('_BASE','');
if (baseElemId != elem.id) return infosetId;
var set = {id:infosetId,type:'B',data:null,holder:elem,partners:{}};
set.partners[elem.id] = true;
attachInfoshape(elem,set);
infosets[infosetId] = set;
return infosetId;
}
function createInfoview(elem) {
var infosetId = elem.getInfosetId();
if (infosetId in infosets) return infosetId;
var set = {id:infosetId,type:'V',data:null,holder:elem,partners:{}};
set.partners[elem.id] = true;
var source = elem.getSourceViewId();
set.source = source;
set.viewNode = elem.getViewName();
var vfields = {};
for (var k in elem.fields) {
var field = elem.fields[k];
if (field.kind == 'V') vfields[k] = field;
}
set.vfields = vfields;
if (elem.hasOwnProperty('cursorReset')) set.cursorReset = elem.cursorReset;
if (elem.hasFilterStep()) createFilterStep();
attachInfoshape(elem,set,true);
infosets[infosetId] = set;
return infosetId;
function createFilterStep() {
var res = elem.buildFilterClauses(), clauses = res.results;
if (!compiler.validateResults(res,elem)) return;
set.filter = clauses;
}
}
function createFictiveInfoset(elem,holder) { // used for OPPlugIn
var infosetId = elem.id;
if (infosetId in infosets) return infosetId;
var set = {id:infosetId,type:'S',data:null,holder:elem,partners:{}};
set.partners[elem.id] = true;
var isShapeHolder = compiler.isShapeHolder(elem);
var infoshape = holder.getInfoshape();
var shapeId = compiler.getElementId(infoshape);
if (isShapeHolder) infoshapes[shapeId] = {object:infoshape,holder:holder};
set.shapeId = shapeId;
infosets[infosetId] = set;
return infosetId;
}
function attachInfoshape(elem,infoset,isShapeHolder) {
var type = infoset.type, infosetId = infoset.id, shapeId = '';
var infoshape = ((type == 'B') ? elem.getBaseInfoshape() : elem.isa('#NS[DataBoundInteractor]') ? elem.getFlatInfoshape() : elem.getInfoshape());
if (infoshape) {
shapeId = compiler.getElementId(infoshape);
if (isShapeHolder) infoshapes[shapeId] = {object:infoshape,holder:elem};
} else {
shapeId = compiler.getUnitAlias(elem.unit) + '_' + infosetId;
var shape = '';
if (elem.cardinality) shape = elem.cardinality;
else shape = (ISA(elem,'gml2:FormView')? '1..1' : '0..n');
infoshapes[shapeId] = {object:shape,holder:elem};
}
infoset.shapeId = shapeId;
}
}
XglCompiler.prototype.getInfosets = function(elems,excluders) {
var I = {}, E = {}, holders=this.index.infoset_holders;
if (!ISEMPTY(excluders)) E = this.getInfosets(excluders);
for (var k in elems) {
elem = elems[k];
if (ISA(elem,'gml2:DataStore')) continue;
if (elem.id in holders) {
var set = holders[elem.id];
if (!(set in E)) I[set] = true;
}
else {
for (var p in elem.plugs) {
var plug = elem.plugs[p];
if (ISA(plug,'gml2:CGPlugIn','gml2:DTPlugIO')) continue;
if (plug.id in holders) {
var set = holders[plug.id];
if (!(set in E)) I[set] = true;
}
}
}
}
return I;
}
XglCompiler.prototype.printAssigns = function(mapping,holder,desc) {
var out=this.out, index=this.index, de=this.de, compiler=this;
var assigns=mapping.assigns, contextSet=mapping.sourceInfoset, contextElem=null;
if (contextSet in index.infosets) contextElem = index.infosets[contextSet].holder;
var prop = desc || 'map';
RULE('setDynExpContext', this.unit, contextElem, prop);
for (var k in assigns) {
var assign = assigns[k];
if (ISA(assign,'gml2:NodeAssign')) printNodeAssign(assign);
else printFieldAssign(assign);
}
de.clearRelativeNode();
function printNodeAssign(assign) {
var assignType = LOWER(assign.type) || 'copy';
var tagName = (assignType=='copy'? 'xg:CopyNode' : 'xg:MapNode');
var contextNode = (assign.GetSourceNodeFullName() || null);
de.setRelativeNode(contextNode);
var props = {sourceNode:assign.from,targetNode:assign.to};
if (assign.selectMode && assign.selectMode != 'all') props.selectMode = assign.selectMode;
if (assign.guard && assign.guard+'' != 'true') {
var guard = compiler.parseExpr(assign.guard,'Boolean',assign,'guard',holder,'Guard condition');
if (guard !== null) props.guard = guard;
}
out.beginTag(tagName,props);
var nodeAssignArr = [];
for (var a in assign.assigns) {
var childAssign = assign.assigns[a];
if (ISA(childAssign,'gml2:NodeAssign')) nodeAssignArr.push(childAssign);
else {
if (assignType == 'copy') continue;
printFieldAssign(childAssign);
}
}
for (var i=0 ; i < nodeAssignArr.length ; i++) printNodeAssign(nodeAssignArr[i]);
out.endTag();
}
function printFieldAssign(assign) {
if (ISA(holder,'gml2:SwitchOp')) out.addTag('xg:Assign',{field:assign.to,value:assign.from});
else {
var val = compiler.parseExpr(assign.from,assign.exprType,assign,'from',holder,'Mapping');
if (val !== null) out.addTag('xg:Assign',{field:assign.to,value:val});
}
}
}
XglCompiler.prototype.skipCopyStep = function(link) {
var skip = true;
var guard = link.guard && link.guard+''!='true';
var select = link.selectMode && link.selectMode!='all';
if (guard || select) skip = false;
return skip;
}
XglCompiler.prototype.isShapeHolder = function(elem) {
if (ISA(elem,'gml2:IShapeTransform')) return true;
else if (ISA(elem,'gml2:IValueTransform')) {
var predecessor = elem.getPredecessor();
var infoshape = (predecessor && ISA(predecessor,'gml2:DataBoundInteractor')? predecessor.getInfoshape() : null);
return ISA(infoshape,'gml2:Cluster');
} else if (ISA(elem,'gml2:OPPlugIn')) {
var predecessor = this.getPlugPredecessor(elem);
var infoshape = (predecessor && ISA(predecessor,'gml2:DataBoundInteractor')? predecessor.getInfoshape() : null);
return ISA(infoshape,'gml2:Cluster') && ISA(elem.parent,'gml2:IShapeTransform');
}
return true;
}
XglCompiler.prototype.getPlugPredecessor = function(plug) {
var link = null;
for (var l in plug.links) {
link = plug.links[l];
break;
}
if (!link) return null;
var predecessor = link.source && link.source.parent || null;
return (predecessor && predecessor.isa('#NS[PComponentUsage]')? link.source : predecessor);
}
XglCompiler.prototype.validateResults = function(results,elem) {
var out = this.out;
if (results.warnings) {
var warnings = results.warnings;
if (typeof warnings == 'string') {
out.warning(warnings,elem);
}
var warnNum = warnings.length || 0;
if (warnNum > 0) {
for (var i=0; i 0) {
for (var i=0; i