/// <summary>Call a string template with args and return result. Do not convert /// to a string yet. It may need attributes that will be available after /// this is inserted into another template. /// </summary> public virtual StringTemplate getTemplateInclude(StringTemplate enclosing, String templateName, StringTemplateAST argumentsAST) { StringTemplateGroup group = enclosing.getGroup(); StringTemplate embedded = group.getEmbeddedInstanceOf(enclosing, templateName); if (embedded == null) { enclosing.error("cannot make embedded instance of " + templateName + " in template " + enclosing.getName()); return null; } embedded.setArgumentsAST(argumentsAST); evaluateArguments(embedded); return embedded; }
//throws RecognitionException public void singleTemplateArg(AST _t, StringTemplate embedded, IDictionary argumentContext ) { antlr.stringtemplate.language.StringTemplateAST singleTemplateArg_AST_in = (antlr.stringtemplate.language.StringTemplateAST)_t; Object e = null; try { // for error handling AST __t41 = _t; antlr.stringtemplate.language.StringTemplateAST tmp22_AST_in = (_t==ASTNULL) ? null : (antlr.stringtemplate.language.StringTemplateAST)_t; match((AST)_t,SINGLEVALUEARG); _t = _t.getFirstChild(); e=expr(_t); _t = retTree_; _t = __t41; _t = _t.getNextSibling(); if ( e!=null ) { String soleArgName = null; // find the sole defined formal argument for embedded bool error = false; IDictionary formalArgs = embedded.getFormalArguments(); if ( formalArgs!=null ) { ICollection argNames = formalArgs.Keys; if ( argNames.Count==1 ) { string[] argNamesArray = new string[argNames.Count]; argNames.CopyTo(argNamesArray,0); soleArgName = argNamesArray[0]; //System.out.println("sole formal arg of "+embedded.getName()+" is "+soleArgName); } else { error=true; } } else { error=true; } if ( error ) { self.error("template "+embedded.getName()+ " must have exactly one formal arg in template context "+ self.getEnclosingInstanceStackString()); } else { self.rawSetArgumentAttribute(embedded,argumentContext,soleArgName,e); } } } catch (RecognitionException ex) { reportError(ex); if (null != _t) { _t = _t.getNextSibling(); } } retTree_ = _t; }
/// <summary> /// Evaluate an argument list within the context of the enclosing /// template but store the values in the context of self, the /// new embedded template. For example, bold(item=item) means /// that bold.item should get the value of enclosing.item. /// </summary> protected internal virtual void evaluateArguments(StringTemplate self) { StringTemplateAST argumentsAST = self.getArgumentsAST(); if (argumentsAST == null || argumentsAST.getFirstChild() == null) { // return immediately if missing tree or no actual args return ; } // Evaluate args in the context of the enclosing template, but we // need the predefined args like 'it', 'attr', and 'i' to be // available as well so we put a dummy ST between the enclosing // context and the embedded context. The dummy has the predefined // context as does the embedded. StringTemplate enclosing = self.getEnclosingInstance(); StringTemplate argContextST = new StringTemplate(self.getGroup(), ""); argContextST.setName("<invoke "+self.getName()+" arg context>"); argContextST.setEnclosingInstance(enclosing); argContextST.setArgumentContext(self.getArgumentContext()); ActionEvaluator eval = new ActionEvaluator(argContextST, this, null); try { // using any initial argument context (such as when obj is set), // evaluate the arg list like bold(item=obj). Since we pass // in any existing arg context, that context gets filled with // new values. With bold(item=obj), context becomes: // {[obj=...],[item=...]}. IDictionary ac = eval.argList(argumentsAST, self, self.getArgumentContext()); self.setArgumentContext(ac); } catch (RecognitionException re) { self.error("can't evaluate tree: " + argumentsAST.ToStringList(), re); } }
protected void setSoleFormalArgumentToIthValue(StringTemplate embedded, IDictionary argumentContext, Object ithValue) { IDictionary formalArgs = embedded.getFormalArguments(); if ( formalArgs!=null ) { String soleArgName = null; bool isAnonymous = embedded.getName().Equals(StringTemplate.ANONYMOUS_ST_NAME); if ( formalArgs.Count==1 || (isAnonymous&&formalArgs.Count>0) ) { if ( isAnonymous && formalArgs.Count>1 ) { embedded.error("too many arguments on {...} template: "+formalArgs); } // if exactly 1 arg or anonymous, give that the value of // "it" as a convenience like they said // $list:template(arg=it)$ ICollection argNames = formalArgs.Keys; string[] argNamesArray = new string[argNames.Count]; argNames.CopyTo(argNamesArray,0); soleArgName = argNamesArray[0]; argumentContext[soleArgName] = ithValue; } } }
/// <summary> /// Argument evaluation such as foo(x=y), x must /// be checked against foo's argument list not this's (which is /// the enclosing context). So far, only eval.g uses arg self as /// something other than "this". /// </summary> public virtual void rawSetArgumentAttribute(StringTemplate embedded, IDictionary attributes, String name, Object value) { if ( embedded.formalArguments!=FormalArgument.UNKNOWN && embedded.getFormalArgument(name)==null ) { throw new ArgumentOutOfRangeException("template "+embedded.getName()+ " has no such attribute: "+name+ " in template context "+ getEnclosingInstanceStackString()); } if ( value == null ) { return; } attributes[name] = value; }