/** * Copyright (C) 2013-2016 The Rythm Engine project * for LICENSE and other details see: * https://github.com/rythmengine/rythmengine */ package org.rythmengine.internal.parser.build_in; import org.rythmengine.exception.ParseException; import org.rythmengine.internal.CodeBuilder; import org.rythmengine.internal.IContext; import org.rythmengine.internal.TemplateParser; import org.rythmengine.internal.Token; import org.rythmengine.internal.dialect.BasicRythm; import org.rythmengine.internal.parser.BlockCodeToken; import org.rythmengine.utils.S; import com.stevesoft.pat.Regex; public class ForEachCodeToken extends BlockCodeToken { private String type; private String iterableType = "Iterable"; private String varname; private String iterable; private String joinSep; // private int openPos; // private int closePos; /** * @param type * @param varname * @param iterable * @param context * "@each String [str]: myStrList @" * ^ ^ ^ ^ * | | | | * type varname iterable endloop */ public ForEachCodeToken(String type, String varname, String iterable, IContext context, int lineNo, String joinSep) { super(null, context); line = lineNo; this.joinSep = joinSep; if (null == iterable) throw new NullPointerException(); iterable = iterable.trim(); iterable = ExpressionParser.processPositionPlaceHolder(iterable); iterable = Token.processRythmExpression(iterable, context); if (null != type) type = type.trim(); this.type = objectType(type); this.varname = null == varname ? "_" : varname.trim(); if (iterable.contains("..") || iterable.contains(" to ") || iterable.contains(" till ")) { iterable = "org.rythmengine.utils.Range.valueOf(\"" + iterable + "\")"; iterableType = "Range"; } this.iterable = iterable; //openPos = context.cursor(); IContext ctx = context; ctx.pushBreak(IContext.Break.BREAK); ctx.pushContinue(IContext.Continue.CONTINUE); CodeBuilder cb = context.getCodeBuilder(); boolean isBasic = ctx.getDialect() instanceof BasicRythm; if (S.isEmpty(type) || "Object".equals(type)) { String itrType = cb.getRenderArgType(iterable); if (null != itrType) { Regex r = new Regex(".*((?@<>))"); if (r.search(itrType)) { type = r.stringMatched(1); this.type = S.strip(type, "<", ">"); boolean key = iterable.endsWith("keySet()"); boolean val = iterable.endsWith("values()"); if (key || val) { r = new Regex("([a-zA-Z0-9\\[\\]_]+(?@<>)?)\\s*\\,\\s*([a-zA-Z0-9\\[\\]_]+(?@<>)?)"); if (r.search(this.type)) { if (key) this.type = r.stringMatched(1); else this.type = r.stringMatched(2); } else { throw new ParseException(ctx.getEngine(), ctx.getTemplateClass(), line, "Invalid for loop iterator type declaration: %s", itrType); } } } else { if (itrType.endsWith("]")) { int pos = itrType.lastIndexOf("["); this.type = itrType.substring(0, pos); } else { this.type = "java.lang.Object"; } } if (S.isEqual(this.type, this.varname)) this.varname = "_"; } else { this.type = "java.lang.Object"; } } else if (isBasic) { throw new TemplateParser.TypeDeclarationException(ctx); } if (isBasic) { ExpressionParser.assertBasic(iterable, context); context.getCodeBuilder().addRenderArgsIfNotDeclared(line, "Iterable<?>", iterable); } } private String objectType(String type) { if (null == type) return ""; if ("int".equals(type)) return "Integer"; if ("float".equals(type)) return "Float"; if ("double".equals(type)) return "Double"; if ("boolean".equals(type)) return "Boolean"; if ("char".equals(type)) return "Character"; if ("long".equals(type)) return "Long"; if ("byte".equals(type)) return "Byte"; if ("short".equals(type)) return "Integer"; return type; } @Override public void output() { String prefix = "_".equals(varname) ? "" : varname + ""; CodeBuilder cb = ctx.getCodeBuilder(); String varId = prefix + "_index"; String varIsOdd = prefix + "_isOdd"; String varSize = prefix + "_size"; String varParity = prefix + "_parity"; String varIsFirst = prefix + "_isFirst"; String varIsLast = prefix + "_isLast"; String varSep = prefix + "_sep"; String varWithSep = prefix + "__sep"; String varUtils = prefix + "_utils"; String varWithUtils = prefix + "__utils"; String varItr = cb.newVarName(); if ("java.lang.Object".equals(type)) { p("{\n__Itr ").p(varItr).p(" = __Itr.of(").p(iterable).p(");"); } else { if ("Range".equals(iterableType)) { p("{\n__Itr<").p(type).p("> ").p(varItr).p(" = __Itr.ofRange(").p(iterable).p(");"); } else { p("{\n__Itr<").p(type).p("> ").p(varItr).p(" = __Itr.valueOf(").p(iterable).p(");"); } } pline(); p("int ").p(varSize).p(" = ").p(varItr).p(".size();"); pline(); p("if (").p(varSize).p(" > 0) {"); pline(); p("int ").p(varId).p(" = 0;"); pline(); p("for(").p("?".equals(type) ? "java.lang.Object" : type).p(" ").p(varname).p(" : ").p(varItr).p(") {"); pline(); if (null != joinSep) { p("if (").p(varId).p("++ > 0) {p(").p(joinSep).p(");}"); } else { p(varId).p("++;"); } pline(); p("boolean ").p(varIsOdd).p(" = ").p(varId).p(" % 2 == 1;"); pline(); p("java.lang.String ").p(varParity).p(" = ").p(varIsOdd).p(" ? \"odd\" : \"even\";"); pline(); p("boolean ").p(varIsFirst).p(" = ").p(varId).p(" == 1;"); pline(); p("boolean ").p(varIsLast).p(" = ").p(varId).p(" >= ").p(varSize).p(";"); pline(); p("org.rythmengine.utils.RawData ").p(varSep).p(" = new org.rythmengine.utils.RawData(").p(varIsLast).p(" ? \"\" : \",\");"); pline(); /*p("org.rythmengine.utils.RawData ").p(varWithSep).p(" = new org.rythmengine.utils.RawData(org.rythmengine.utils.S.escape(").p(varname).p(")+(").p(varIsLast).p(" ? \"\" : \",\"));"); pline(); */ p("org.rythmengine.internal.LoopUtil ").p(varUtils).p(" = new org.rythmengine.internal.LoopUtil(").p(varIsFirst).p(", ").p(varIsLast).p(");"); pline(); /* p("org.rythmengine.internal.LoopUtil ").p(varWithUtils).p(" = new org.rythmengine.internal.LoopUtil(").p(varIsFirst).p(", ").p(varIsLast).p(", ").p(varname).p(");"); pline(); */ p("__pushItrVar(\"").p(varname).p("\", ").p(varname).p(");"); pline(); } @Override public String closeBlock() { return "\n\t__popItrVar();\n\t}\n}\n}\n"; } }