Example usage for com.google.gwt.user.rebind SourceWriter println

List of usage examples for com.google.gwt.user.rebind SourceWriter println

Introduction

In this page you can find the example usage for com.google.gwt.user.rebind SourceWriter println.

Prototype

void println(String s, Object... args);

Source Link

Document

Emit a printf-style string.

Usage

From source file:com.google.web.bindery.autobean.gwt.rebind.AutoBeanFactoryGenerator.java

License:Apache License

/**
 * Write an instance initializer block to populate the creators map.
 *//*from w ww  .  ja  v  a 2 s  . c  om*/
private void writeDynamicMethods(SourceWriter sw) {
    List<JClassType> privatePeers = new ArrayList<JClassType>();
    sw.println("@Override protected void initializeCreatorMap(%s map) {",
            JsniCreatorMap.class.getCanonicalName());
    sw.indent();
    for (AutoBeanType type : model.getAllTypes()) {
        if (type.isNoWrap()) {
            continue;
        }
        String classLiteralAccessor;
        JClassType peer = type.getPeerType();
        String peerName = ModelUtils.ensureBaseType(peer).getQualifiedSourceName();
        if (peer.isPublic()) {
            classLiteralAccessor = peerName + ".class";
        } else {
            privatePeers.add(peer);
            classLiteralAccessor = "classLit_" + peerName.replace('.', '_') + "()";
        }
        // map.add(Foo.class, getConstructors_com_foo_Bar());
        sw.println("map.add(%s, getConstructors_%s());", classLiteralAccessor, peerName.replace('.', '_'));
    }
    sw.outdent();
    sw.println("}");

    /*
     * Create a native method for each peer type that isn't public since Java
     * class literal references are scoped.
     */
    for (JClassType peer : privatePeers) {
        String peerName = ModelUtils.ensureBaseType(peer).getQualifiedSourceName();
        sw.println("private native Class<?> classLit_%s() /*-{return @%s::class;}-*/;",
                peerName.replace('.', '_'), peerName);
    }

    /*
     * Create a method that returns an array containing references to the
     * constructors.
     */
    String factoryJNIName = context.getTypeOracle().findType(AutoBeanFactory.class.getCanonicalName())
            .getJNISignature();
    for (AutoBeanType type : model.getAllTypes()) {
        String peerName = ModelUtils.ensureBaseType(type.getPeerType()).getQualifiedSourceName();
        String peerJNIName = ModelUtils.ensureBaseType(type.getPeerType()).getJNISignature();
        /*-
         * private native JsArray<JSO> getConstructors_com_foo_Bar() {
         *   return [
         *     BarProxyImpl::new(ABFactory),
         *     BarProxyImpl::new(ABFactory, DelegateType)
         *   ];
         * }
         */
        sw.println("private native %s<%s> getConstructors_%s() /*-{", JsArray.class.getCanonicalName(),
                JavaScriptObject.class.getCanonicalName(), peerName.replace('.', '_'));
        sw.indent();
        sw.println("return [");
        if (type.isSimpleBean()) {
            sw.indentln("@%s::new(%s),", type.getQualifiedSourceName(), factoryJNIName);
        } else {
            sw.indentln(",");
        }
        sw.indentln("@%s::new(%s%s)", type.getQualifiedSourceName(), factoryJNIName, peerJNIName);
        sw.println("];");
        sw.outdent();
        sw.println("}-*/;");
    }
}

From source file:com.google.web.bindery.autobean.gwt.rebind.AutoBeanFactoryGenerator.java

License:Apache License

/**
 * Create the shim instance of the AutoBean's peer type that lets us hijack
 * the method calls. Using a shim type, as opposed to making the AutoBean
 * implement the peer type directly, means that there can't be any conflicts
 * between methods in the peer type and methods declared in the AutoBean
 * implementation./*  w  ww .  ja  va 2s  .c om*/
 */
private void writeShim(SourceWriter sw, AutoBeanType type) throws UnableToCompleteException {
    // private final FooImpl shim = new FooImpl() {
    sw.println("private final %1$s shim = new %1$s() {", type.getPeerType().getQualifiedSourceName());
    sw.indent();
    for (AutoBeanMethod method : type.getMethods()) {
        JMethod jmethod = method.getMethod();
        String methodName = jmethod.getName();
        JParameter[] parameters = jmethod.getParameters();
        if (isObjectMethodImplementedByShim(jmethod)) {
            // Skip any methods declared on Object, since we have special handling
            continue;
        }

        // foo, bar, baz
        StringBuilder arguments = new StringBuilder();
        {
            for (JParameter param : parameters) {
                arguments.append(",").append(param.getName());
            }
            if (arguments.length() > 0) {
                arguments = arguments.deleteCharAt(0);
            }
        }

        sw.println("public %s {", getBaseMethodDeclaration(jmethod));
        sw.indent();

        switch (method.getAction()) {
        case GET:
            /*
             * The getter call will ensure that any non-value return type is
             * definitely wrapped by an AutoBean instance.
             */
            sw.println("%s toReturn = %s.this.getWrapped().%s();",
                    ModelUtils.getQualifiedBaseSourceName(jmethod.getReturnType()), type.getSimpleSourceName(),
                    methodName);

            // Non-value types might need to be wrapped
            writeReturnWrapper(sw, type, method);
            sw.println("return toReturn;");
            break;
        case SET:
        case SET_BUILDER:
            // getWrapped().setFoo(foo);
            sw.println("%s.this.getWrapped().%s(%s);", type.getSimpleSourceName(), methodName,
                    parameters[0].getName());
            // FooAutoBean.this.set("setFoo", foo);
            sw.println("%s.this.set(\"%s\", %s);", type.getSimpleSourceName(), methodName,
                    parameters[0].getName());
            if (JBeanMethod.SET_BUILDER.equals(method.getAction())) {
                sw.println("return this;");
            }
            break;
        case CALL:
            // XXX How should freezing and calls work together?
            // sw.println("checkFrozen();");
            if (JPrimitiveType.VOID.equals(jmethod.getReturnType())) {
                // getWrapped().doFoo(params);
                sw.println("%s.this.getWrapped().%s(%s);", type.getSimpleSourceName(), methodName, arguments);
                // call("doFoo", null, params);
                sw.println("%s.this.call(\"%s\", null%s %s);", type.getSimpleSourceName(), methodName,
                        arguments.length() > 0 ? "," : "", arguments);
            } else {
                // Type toReturn = getWrapped().doFoo(params);
                sw.println("%s toReturn = %s.this.getWrapped().%s(%s);",
                        ModelUtils.ensureBaseType(jmethod.getReturnType()).getQualifiedSourceName(),
                        type.getSimpleSourceName(), methodName, arguments);
                // Non-value types might need to be wrapped
                writeReturnWrapper(sw, type, method);
                // call("doFoo", toReturn, params);
                sw.println("%s.this.call(\"%s\", toReturn%s %s);", type.getSimpleSourceName(), methodName,
                        arguments.length() > 0 ? "," : "", arguments);
                sw.println("return toReturn;");
            }
            break;
        default:
            throw new RuntimeException();
        }
        sw.outdent();
        sw.println("}");
    }

    // Delegate equals(), hashCode(), and toString() to wrapped object
    sw.println("@Override public boolean equals(Object o) {");
    sw.indentln("return this == o || getWrapped().equals(o);");
    sw.println("}");
    sw.println("@Override public int hashCode() {");
    sw.indentln("return getWrapped().hashCode();");
    sw.println("}");
    sw.println("@Override public String toString() {");
    sw.indentln("return getWrapped().toString();");
    sw.println("}");

    // End of shim field declaration and assignment
    sw.outdent();
    sw.println("};");
}

From source file:com.google.web.bindery.event.gwt.rebind.binder.EventBinderWriter.java

License:Apache License

private void writeBindMethodHeader(SourceWriter writer, String targetName) {
    writer.println("protected List<HandlerRegistration> doBindEventHandlers("
            + "final %s target, EventBus eventBus) {", targetName);
    writer.indent();/*  www .  j  a  v a 2 s .  c o  m*/
    writer.println("List<HandlerRegistration> registrations = new LinkedList<HandlerRegistration>();");
}

From source file:com.google.web.bindery.event.gwt.rebind.binder.EventBinderWriter.java

License:Apache License

private void writeHandlerForBindMethod(EventHandler annotation, SourceWriter writer, JMethod method,
        TypeOracle typeOracle) throws UnableToCompleteException {
    JClassType eventParameter = null;/*from ww  w.j  a va  2s  .com*/
    if (method.getParameterTypes().length == 1) {
        eventParameter = method.getParameterTypes()[0].isClassOrInterface();
    }
    if (annotation.handles().length == 0 && !isAConcreteGenericEvent(eventParameter)) {
        logger.log(Type.ERROR,
                "Method " + method.getName()
                        + " annotated with @EventHandler without event classes must have exactly "
                        + "one argument of a concrete type assignable to GenericEvent");
        throw new UnableToCompleteException();
    }

    List<String> eventTypes = new ArrayList<String>();
    if (annotation.handles().length != 0) {
        for (Class<? extends GenericEvent> event : annotation.handles()) {
            String eventTypeName = event.getCanonicalName();
            JClassType eventClassType = typeOracle.findType(eventTypeName);
            if (eventClassType == null) {
                logger.log(Type.ERROR, "Can't resolve " + eventTypeName);
                throw new UnableToCompleteException();
            }
            if (eventParameter != null && !eventClassType.isAssignableTo(eventParameter)) {
                logger.log(Type.ERROR, "Event " + eventTypeName + " isn't assignable to "
                        + eventParameter.getName() + " in method: " + method.getName());
                throw new UnableToCompleteException();
            }
            eventTypes.add(eventClassType.getQualifiedSourceName());
        }
    } else {
        eventTypes.add(eventParameter.getQualifiedSourceName());
    }

    for (String eventType : eventTypes) {
        writer.println("bind(eventBus, registrations, %s.class, new GenericEventHandler() {", eventType);
        if (eventParameter != null) {
            writer.indentln("public void handleEvent(GenericEvent event) { target.%s((%s) event); }",
                    method.getName(), eventType);
        } else {
            writer.indentln("public void handleEvent(GenericEvent event) { target.%s(); }", method.getName());
        }
        writer.println("});");
    }
}

From source file:com.google.web.bindery.requestfactory.gwt.rebind.RequestFactoryGenerator.java

License:Apache License

private void writeTypeMap(SourceWriter sw) {
    sw.println("private static final %1$s<String, Class<?>> tokensToTypes" + " = new %1$s<String, Class<?>>();",
            HashMap.class.getCanonicalName());
    sw.println("private static final %1$s<Class<?>, String> typesToTokens" + " = new %1$s<Class<?>, String>();",
            HashMap.class.getCanonicalName());
    sw.println("private static final %1$s<Class<?>> entityProxyTypes = new %1$s<Class<?>>();",
            HashSet.class.getCanonicalName());
    sw.println("private static final %1$s<Class<?>> valueProxyTypes = new %1$s<Class<?>>();",
            HashSet.class.getCanonicalName());
    sw.println("static {");
    sw.indent();//from  w  ww  .j  a va 2 s.  co  m
    for (EntityProxyModel type : model.getAllProxyModels()) {
        // tokensToTypes.put("Foo", Foo.class);
        sw.println("tokensToTypes.put(\"%s\", %s.class);", OperationKey.hash(type.getQualifiedBinaryName()),
                type.getQualifiedSourceName());
        // typesToTokens.put(Foo.class, Foo);
        sw.println("typesToTokens.put(%s.class, \"%s\");", type.getQualifiedSourceName(),
                OperationKey.hash(type.getQualifiedBinaryName()));
        // fooProxyTypes.add(MyFooProxy.class);
        sw.println("%s.add(%s.class);",
                type.getType().equals(Type.ENTITY) ? "entityProxyTypes" : "valueProxyTypes",
                type.getQualifiedSourceName());
    }
    sw.outdent();
    sw.println("}");

    // Write instance methods
    sw.println("@Override public String getFactoryTypeToken() {");
    sw.indentln("return \"%s\";", model.getFactoryType().getQualifiedBinaryName());
    sw.println("}");
    sw.println("@Override protected Class getTypeFromToken(String typeToken) {");
    sw.indentln("return tokensToTypes.get(typeToken);");
    sw.println("}");
    sw.println("@Override protected String getTypeToken(Class type) {");
    sw.indentln("return typesToTokens.get(type);");
    sw.println("}");
    sw.println("@Override public boolean isEntityType(Class<?> type) {");
    sw.indentln("return entityProxyTypes.contains(type);");
    sw.println("}");
    sw.println("@Override public boolean isValueType(Class<?> type) {");
    sw.indentln("return valueProxyTypes.contains(type);");
    sw.println("}");
}

From source file:com.msco.mil.server.com.sencha.gxt.explorer.rebind.SampleGenerator.java

License:sencha.com license

@Override
public String generate(TreeLogger logger, GeneratorContext context, String typeName)
        throws UnableToCompleteException {
    // Get access to metadata about the type to be generated
    TypeOracle oracle = context.getTypeOracle();
    JClassType toGenerate = oracle.findType(typeName).isClass();

    // Get the name of the new type
    String packageName = toGenerate.getPackage().getName();
    String simpleSourceName = toGenerate.getName().replace('.', '_') + "Impl";
    PrintWriter pw = context.tryCreate(logger, packageName, simpleSourceName);
    if (pw == null) {
        return packageName + "." + simpleSourceName;
    }//  w  ww  . j a  v a  2  s.  co  m

    // Generate an HTML file resource for every example and write the source
    JClassType[] types = oracle.getTypes();

    // Build a ResourceOracle capable of reading java files
    sourceOracle = new ResourceOracleImpl(logger.branch(Type.DEBUG, "Gathering sources"));

    // Clean up these prefixes to not have filters
    PathPrefixSet prefixes = ((ResourceOracleImpl) context.getResourcesOracle()).getPathPrefixes();
    sourceOracle.setPathPrefixes(new PathPrefixSet());
    for (PathPrefix p : prefixes.values()) {
        sourceOracle.getPathPrefixes().add(new PathPrefix(p.getPrefix(), null));
    }
    ResourceOracleImpl.refresh(logger, sourceOracle);

    // Load the header and footer HTML content
    try {
        String slashyPackageName = getClass().getPackage().getName().replace('.', '/');
        javaHeader = Utility.getFileFromClassPath(slashyPackageName + "/header.html");
        footer = Utility.getFileFromClassPath(slashyPackageName + "/footer.html");
    } catch (IOException e) {
        logger.log(Type.ERROR, "Header or Footer failed to be read", e);
        throw new UnableToCompleteException();
    }

    // Find all examples, annotated with @Detail
    Set<ExampleDetailModel> examples = new HashSet<ExampleDetailModel>();
    Map<String, List<ExampleDetailModel>> hierarchy = new HashMap<String, List<ExampleDetailModel>>();

    Set<SourceModel> exampleSources = new HashSet<SourceModel>();
    for (JClassType type : types) {
        Example.Detail detail = type.getAnnotation(Example.Detail.class);
        if (detail != null) {
            ExampleDetailModel example = new ExampleDetailModel(logger, context, type, detail);

            // Collect sources to be built into html
            exampleSources.addAll(example.getAllSources());

            List<ExampleDetailModel> exampleList = hierarchy.get(detail.category());
            if (exampleList == null) {
                exampleList = new ArrayList<ExampleDetailModel>();
                hierarchy.put(detail.category(), exampleList);
            }
            examples.add(example);
            exampleList.add(example);
        }
    }

    // Sort folders, sort within those folders
    List<String> folders = new ArrayList<String>(hierarchy.keySet());
    Collections.sort(folders);
    for (List<ExampleDetailModel> contents : hierarchy.values()) {
        Collections.sort(contents);
    }

    // Actually build source for each type
    for (SourceModel type : exampleSources) {
        TreeLogger l = logger.branch(Type.DEBUG, "Writing HTML file for " + type.getName());

        // attempt to create the output file
        if (type.getType() == FileType.JAVA) {
            writeTypeToHtml(l, context, type.getJClassType());
        } else {
            writeFileToHtml(l, context, type.getPath());
        }
    }

    // Start making the class, with basic imports
    ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(packageName, simpleSourceName);
    factory.setSuperclass(typeName);
    factory.addImport(Name.getSourceNameForClass(Category.class));
    factory.addImport(Name.getSourceNameForClass(ImageResource.class));
    factory.addImport(Name.getSourceNameForClass(GWT.class));
    factory.addImport(Name.getSourceNameForClass(Example.class));
    factory.addImport(Name.getSourceNameForClass(Source.class));
    factory.addImport(Name.getSourceNameForClass(Source.FileType.class));
    SourceWriter sw = factory.createSourceWriter(context, pw);

    // Write the ctor
    sw.println("public %1$s() {", simpleSourceName);
    sw.indent();
    // Declare variables that will be used
    sw.println("Category c;");
    sw.println("ImageResource icon;");
    sw.println("Example e;");
    sw.println("Source dir;");
    Set<String> names = new HashSet<String>();
    Map<JClassType, String> bundles = new HashMap<JClassType, String>();
    for (String folder : folders) {
        // TODO escape name
        sw.println("c = new Category(\"%1$s\");", folder);
        for (ExampleDetailModel example : hierarchy.get(folder)) {
            // make sure the bundle to be used exists
            if (!bundles.containsKey(example.getClientBundleType())) {
                String bundleName = getNextName("bundle", names);
                sw.println("%1$s %2$s = GWT.create(%1$s.class);",
                        example.getClientBundleType().getQualifiedSourceName(), bundleName);

                bundles.put(example.getClientBundleType(), bundleName);
            }

            // write out the example, adding it to the current category
            writeExample(sw, bundles.get(example.getClientBundleType()), example);
        }
        sw.println("categories.add(c);");
    }
    sw.outdent();
    sw.println("}");// end ctor

    sw.commit(logger);

    return factory.getCreatedClassName();
}

From source file:com.rhizospherejs.gwt.rebind.MappingWriter.java

License:Open Source License

private void writeMetaModelFactoryImpl(SourceWriter sw) {
    sw.println("private static final class %sMetaModelFactory extends MetaModelFactory {", modelClassName);
    sw.indent();/*from   ww w .j av  a  2  s . c o m*/

    sw.println("public %sMetaModelFactory() {", modelClassName);
    sw.indentln("super();");
    sw.println("}");
    sw.println();

    sw.println("public %sMetaModelFactory(%s attrBuilder) {", modelClassName,
            BridgeCapabilities.METAMODEL_ATTRIBUTE_BUILDER_CLASS);
    sw.indentln("super(attrBuilder);");
    sw.println("}");
    sw.println();

    sw.println("@Override");
    sw.println("protected void fillMetaModelAttributes("
            + "RhizosphereMetaModel metaModel, AttributeBuilder attrBuilder) {");
    sw.indent();

    sw.println("Attribute attr;");
    sw.println("AttributeDescriptor descriptor;");
    sw.println("RhizosphereKind kind;");
    for (MappableMethod modelMethod : inspector.getMappableModelMethods()) {
        if (!modelMethod.contributesToMetaModel()) {
            continue;
        }
        String labelParameter = modelMethod.getAttributeLabel() != null
                ? "\"" + modelMethod.getAttributeLabel() + "\""
                : "null";
        sw.println("attr = metaModel.newAttribute(\"%s\");", modelMethod.getAttributeName());
        sw.println("descriptor = new %s();", modelMethod.getAttributeDescriptorClassName());
        sw.println("kind = RhizosphereKind.valueOf(RhizosphereKind.class, \"%s\");",
                bridgeCapabilities.getBridgeMethod(modelMethod.getReturnType()).getRhizosphereKind().name());
        sw.println("attrBuilder.fillAttribute(attr, descriptor, \"%s\", %s, kind);",
                modelMethod.getAttributeName(), labelParameter);
        sw.println();
    }

    sw.outdent();
    sw.println("}");

    sw.outdent();
    sw.println("}");
}

From source file:com.sencha.gxt.core.rebind.BindingPropertyGenerator.java

License:sencha.com license

@Override
public String generate(TreeLogger logger, GeneratorContext context, String typeName)
        throws UnableToCompleteException {
    TypeOracle oracle = context.getTypeOracle();

    JClassType toGenerate = oracle.findType(typeName).isInterface();
    if (toGenerate == null) {
        logger.log(Type.ERROR, typeName + " is not an interface");
        throw new UnableToCompleteException();
    }/*from   w  ww.j  a  va 2  s .c o  m*/

    PropertyName annotation = toGenerate.getAnnotation(PropertyName.class);
    if (annotation == null) {
        logger.log(Type.ERROR, "Cannot generate with a @PropertyName anntation on the type");
        throw new UnableToCompleteException();
    }

    String propertyName = annotation.value();
    SelectionProperty property;
    String value;
    try {
        property = context.getPropertyOracle().getSelectionProperty(logger, propertyName);
        value = property.getCurrentValue();
    } catch (BadPropertyValueException e) {
        logger.log(Type.ERROR, "Error occured loading property: ", e);
        throw new UnableToCompleteException();
    }
    String packageName = toGenerate.getPackage().getName();
    String simpleSourceName = toGenerate.getName().replace('.', '_') + "_" + value;
    PrintWriter pw = context.tryCreate(logger, packageName, simpleSourceName);
    if (pw == null) {
        return packageName + "." + simpleSourceName;
    }

    ClassSourceFileComposerFactory factory = new ClassSourceFileComposerFactory(packageName, simpleSourceName);
    factory.addImplementedInterface(typeName);
    SourceWriter sw = factory.createSourceWriter(context, pw);

    for (JMethod method : toGenerate.getMethods()) {
        if (method.getReturnType().isPrimitive() != JPrimitiveType.BOOLEAN && !method.getReturnType().isClass()
                .getQualifiedSourceName().equals(Name.getSourceNameForClass(Boolean.class))) {
            logger.log(Type.ERROR, "Methods must return boolean or Boolean");
            throw new UnableToCompleteException();
        }
        sw.println("%1$s {", method.getReadableDeclaration(false, true, true, true, true));

        PropertyValue val = method.getAnnotation(PropertyValue.class);
        if (val == null) {
            logger.log(Type.ERROR, "Method must have a @PropertyValue annotation");
            throw new UnableToCompleteException();
        }

        if (!property.getPossibleValues().contains(val.value()) && val.warn()) {
            logger.log(Type.WARN,
                    "Value '" + val
                            + "' is not present in the current set of possible values for selection property "
                            + propertyName);
        }
        sw.indentln("return %1$b;", val.value().equals(value));

        sw.println("}");
    }

    sw.commit(logger);

    return factory.getCreatedClassName();
}

From source file:com.sencha.gxt.core.rebind.SafeHtmlTemplatesCreator.java

License:sencha.com license

@Override
protected void create(SourceWriter sw) throws UnableToCompleteException {
    for (String method : methodNames) {
        sw.println("@Template(\"%1$s\")", escape(templates.get(method)));
        sw.println("SafeHtml %1$s(%2$s);", method, makeArgs(paramLists.get(method)));
    }//from ww w  .  java 2s  .  co  m
}

From source file:com.sencha.gxt.core.rebind.XTemplatesGenerator.java

License:sencha.com license

/**
 * Handles a given template chunk container by creating a method in the
 * safeHtmlTemplates impl//from   ww w  .  jav a2  s  .  com
 * 
 * @param sw the current sourcewriter
 * @param wrapper the chunk container to act recursively on
 * @param safeHtml creator to add new SafeHtml calls to
 * @param scopeContext current scope to make method calls to
 * @param invokables
 * @throws UnableToCompleteException
 */
private void buildSafeHtmlTemplates(String safeHtmlVar, SourceWriter sw, ContainerTemplateChunk wrapper,
        SafeHtmlTemplatesCreator safeHtml, Context scopeContext, MethodCollector invokables)
        throws UnableToCompleteException {

    // debugging section to see what is about to be printed
    sw.beginJavaDocComment();
    sw.print(wrapper.toString());
    sw.endJavaDocComment();

    // make a new interface method for this content
    StringBuilder sb = new StringBuilder();
    List<String> paramTypes = new ArrayList<String>();
    List<String> params = new ArrayList<String>();

    // write out children to local vars or to the template
    int argCount = 0;
    for (TemplateChunk chunk : wrapper.children) {
        if (chunk instanceof ContentChunk) {
            ContentChunk contentChunk = (ContentChunk) chunk;
            // build up the template
            if (contentChunk.type == ContentType.LITERAL) {
                sb.append(contentChunk.content);
            } else if (contentChunk.type == ContentType.CODE) {
                sb.append("{").append(argCount++).append("}");
                paramTypes.add("java.lang.String");
                StringBuffer expr = new StringBuffer("\"\" + (");

                // parse out the quoted string literals first
                Matcher str = Pattern.compile("\"[^\"]+\"").matcher(contentChunk.content);
                TreeLogger code = logger.branch(Type.DEBUG,
                        "Parsing code segment: \"" + contentChunk.content + "\"");
                int lastMatchEnd = 0;
                while (str.find()) {
                    int begin = str.start(), end = str.end();
                    String escapedString = str.group();
                    String unmatched = contentChunk.content.substring(lastMatchEnd, begin);

                    appendCodeBlockOperatorOrIdentifier(scopeContext, expr, code, unmatched);

                    expr.append(escapedString);
                    lastMatchEnd = end;
                }

                //finish rest of non-string-lit expression
                appendCodeBlockOperatorOrIdentifier(scopeContext, expr, code,
                        contentChunk.content.substring(lastMatchEnd));

                params.add(expr.append(")").toString());
                code.log(Type.DEBUG, "Final compiled expression: " + expr);
            } else if (contentChunk.type == ContentType.REFERENCE) {
                sb.append("{").append(argCount++).append("}");

                JType argType = scopeContext.getType(contentChunk.content);
                if (argType == null) {
                    logger.log(Type.ERROR, "Reference could not be found: '" + contentChunk.content
                            + "'. Please fix the expression in your template.");
                    throw new UnableToCompleteException();
                }
                paramTypes.add(argType.getParameterizedQualifiedSourceName());
                params.add(scopeContext.deref(contentChunk.content));

            } else {
                assert false : "Content type not supported + " + contentChunk.type;
            }

        } else if (chunk instanceof ControlChunk) {
            ControlChunk controlChunk = (ControlChunk) chunk;
            // build logic, get scoped name
            boolean hasIf = controlChunk.controls.containsKey("if");
            boolean hasFor = controlChunk.controls.containsKey("for");

            if (!hasIf && !hasFor) {
                logger.log(Type.ERROR, "<tpl> tag did not define a 'for' or 'if' attribute!");
                throw new UnableToCompleteException();
            }

            // declare a sub-template, and stash content in there, interleaving it
            // into the current template
            String subTemplate = scopeContext.declareLocalVariable("subTemplate");
            String templateInBlock = scopeContext.declareLocalVariable("innerTemplate");
            sb.append("{").append(argCount++).append("}");
            paramTypes.add("com.google.gwt.safehtml.shared.SafeHtml");
            params.add(subTemplate);
            sw.println("SafeHtml %1$s;", subTemplate);
            sw.println("SafeHtmlBuilder %1$s_builder = new SafeHtmlBuilder();", subTemplate);

            // find the context that should be passed to the child template
            final Context childScope;

            // if we have both for and if, if needs to wrap the for
            if (hasIf) {
                ConditionParser p = new ConditionParser(logger);
                List<Token> tokens = p.parse(controlChunk.controls.get("if"));
                StringBuilder condition = new StringBuilder();
                for (Token t : tokens) {
                    switch (t.type) {
                    case ExpressionLiteral:
                        condition.append(t.contents);
                        break;
                    case MethodInvocation:
                        Matcher invoke = Pattern.compile("([a-zA-Z0-9\\._]+)\\:([a-zA-Z0-9_]+)\\(([^\\)]*)\\)")
                                .matcher(t.contents);
                        invoke.matches();
                        String deref = scopeContext.deref(invoke.group(1));
                        String methodName = invoke.group(2);
                        String args = "";
                        for (String a : invoke.group(3).split(",")) {
                            String possible = scopeContext.deref(a);
                            args += possible == null ? a : possible;
                        }

                        condition.append(invokables.getMethodInvocation(methodName, deref, args));
                        break;
                    case Reference:
                        condition.append("(").append(scopeContext.deref(t.contents)).append(")");
                        break;
                    default:
                        logger.log(Type.ERROR, "Unexpected token type: " + t.type);
                        throw new UnableToCompleteException();
                    }
                }
                sw.println("if (%1$s) {", condition.toString());
                sw.indent();
            }
            // if there is a for, print it out, and change scope
            if (hasFor) {
                String loopRef = controlChunk.controls.get("for");

                JType collectionType = scopeContext.getType(loopRef);
                if (collectionType == null) {
                    logger.log(Type.ERROR, "Reference in 'for' attribute could not be found: '" + loopRef
                            + "'. Please fix the expression in your template.");
                    throw new UnableToCompleteException();
                }
                final JType localType;// type accessed within the loop
                final String localAccessor;// expr to access looped instance, where
                                           // %1$s is the loop obj, and %2$s is the
                                           // int index
                if (collectionType.isArray() != null) {
                    localType = collectionType.isArray().getComponentType();
                    localAccessor = "%1$s[%2$s]";
                } else {// List subtype
                    localType = ModelUtils.findParameterizationOf(listInterface,
                            collectionType.isClassOrInterface())[0];
                    localAccessor = "%1$s.get(%2$s)";
                }

                String loopVar = scopeContext.declareLocalVariable("i");
                // make sure the collection isnt null
                sw.println("if (%1$s != null) {", scopeContext.deref(loopRef));
                sw.indent();
                sw.println("for (int %1$s = 0; %1$s < %2$s; %1$s++) {", loopVar,
                        scopeContext.derefCount(loopRef));
                String itemExpr = String.format(localAccessor, scopeContext.deref(loopRef), loopVar);
                childScope = new Context(scopeContext, itemExpr, localType);
                childScope.setCountVar(loopVar);
                sw.indent();
            } else {
                // if no for, use the same scope as the outer content
                childScope = scopeContext;
            }
            // generate a subtemplate, insert that
            sw.println("SafeHtml %1$s;", templateInBlock);
            buildSafeHtmlTemplates(templateInBlock, sw, controlChunk, safeHtml, childScope, invokables);
            sw.println("%1$s_builder.append(%2$s);", subTemplate, templateInBlock);

            // close up the blocks
            if (hasFor) {
                sw.outdent();
                sw.println("}");
                sw.outdent();
                sw.println("}");
            }
            if (hasIf) {
                sw.outdent();
                sw.println("}");
            }

            sw.println("%1$s = %1$s_builder.toSafeHtml();", subTemplate);

        } else {
            assert false : "Unsupported chunk type: " + chunk.getClass();
        }
    }

    String methodName = safeHtml.addTemplate(sb.toString(), paramTypes);
    sw.beginJavaDocComment();
    sw.println("safehtml content:");
    sw.indent();
    sw.println(sb.toString());
    sw.outdent();
    sw.println("params:");
    sw.indent();
    sw.print(args(params));
    sw.outdent();
    sw.endJavaDocComment();
    sw.println("%4$s = %1$s.%2$s(%3$s);", safeHtml.getInstanceExpression(), methodName, args(params),
            safeHtmlVar);
}