You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@freemarker.apache.org by dd...@apache.org on 2017/05/14 10:53:23 UTC
[40/51] [partial] incubator-freemarker git commit: Migrated from Ant
to Gradle, and modularized the project. This is an incomplete migration;
there are some TODO-s in the build scripts, and release related tasks are
still missing. What works: Building th
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
new file mode 100644
index 0000000..0420d64
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsForStringsRegexp.java
@@ -0,0 +1,322 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.freemarker.core.model.TemplateBooleanModel;
+import org.apache.freemarker.core.model.TemplateCollectionModel;
+import org.apache.freemarker.core.model.TemplateMethodModel;
+import org.apache.freemarker.core.model.TemplateModel;
+import org.apache.freemarker.core.model.TemplateModelException;
+import org.apache.freemarker.core.model.TemplateModelIterator;
+import org.apache.freemarker.core.model.TemplateScalarModel;
+import org.apache.freemarker.core.model.TemplateSequenceModel;
+import org.apache.freemarker.core.model.impl.SimpleScalar;
+import org.apache.freemarker.core.util._StringUtil;
+
+
+/**
+ * Contains the string built-ins that correspond to basic regular expressions operations.
+ */
+class BuiltInsForStringsRegexp {
+
+ static class groupsBI extends ASTExpBuiltIn {
+ @Override
+ TemplateModel _eval(Environment env) throws TemplateException {
+ TemplateModel targetModel = target.eval(env);
+ assertNonNull(targetModel, env);
+ if (targetModel instanceof RegexMatchModel) {
+ return ((RegexMatchModel) targetModel).getGroups();
+ } else if (targetModel instanceof RegexMatchModel.MatchWithGroups) {
+ return new NativeStringArraySequence(((RegexMatchModel.MatchWithGroups) targetModel).groups);
+
+ } else {
+ throw new UnexpectedTypeException(target, targetModel,
+ "regular expression matcher",
+ new Class[] { RegexMatchModel.class, RegexMatchModel.MatchWithGroups.class },
+ env);
+ }
+ }
+ }
+
+ static class matchesBI extends BuiltInForString {
+ class MatcherBuilder implements TemplateMethodModel {
+
+ String matchString;
+
+ MatcherBuilder(String matchString) throws TemplateModelException {
+ this.matchString = matchString;
+ }
+
+ @Override
+ public Object exec(List args) throws TemplateModelException {
+ int argCnt = args.size();
+ checkMethodArgCount(argCnt, 1, 2);
+
+ String patternString = (String) args.get(0);
+ long flags = argCnt > 1 ? RegexpHelper.parseFlagString((String) args.get(1)) : 0;
+ if ((flags & RegexpHelper.RE_FLAG_FIRST_ONLY) != 0) {
+ RegexpHelper.logFlagWarning("?" + key + " doesn't support the \"f\" flag.");
+ }
+ Pattern pattern = RegexpHelper.getPattern(patternString, (int) flags);
+ return new RegexMatchModel(pattern, matchString);
+ }
+ }
+
+ @Override
+ TemplateModel calculateResult(String s, Environment env) throws TemplateModelException {
+ return new MatcherBuilder(s);
+ }
+
+ }
+
+ static class replace_reBI extends BuiltInForString {
+
+ class ReplaceMethod implements TemplateMethodModel {
+ private String s;
+
+ ReplaceMethod(String s) {
+ this.s = s;
+ }
+
+ @Override
+ public Object exec(List args) throws TemplateModelException {
+ int argCnt = args.size();
+ checkMethodArgCount(argCnt, 2, 3);
+ String arg1 = (String) args.get(0);
+ String arg2 = (String) args.get(1);
+ long flags = argCnt > 2 ? RegexpHelper.parseFlagString((String) args.get(2)) : 0;
+ String result;
+ if ((flags & RegexpHelper.RE_FLAG_REGEXP) == 0) {
+ RegexpHelper.checkNonRegexpFlags("replace", flags);
+ result = _StringUtil.replace(s, arg1, arg2,
+ (flags & RegexpHelper.RE_FLAG_CASE_INSENSITIVE) != 0,
+ (flags & RegexpHelper.RE_FLAG_FIRST_ONLY) != 0);
+ } else {
+ Pattern pattern = RegexpHelper.getPattern(arg1, (int) flags);
+ Matcher matcher = pattern.matcher(s);
+ result = (flags & RegexpHelper.RE_FLAG_FIRST_ONLY) != 0
+ ? matcher.replaceFirst(arg2)
+ : matcher.replaceAll(arg2);
+ }
+ return new SimpleScalar(result);
+ }
+
+ }
+
+ @Override
+ TemplateModel calculateResult(String s, Environment env) throws TemplateModelException {
+ return new ReplaceMethod(s);
+ }
+
+ }
+
+ // Represents the match
+
+ static class RegexMatchModel
+ implements TemplateBooleanModel, TemplateCollectionModel, TemplateSequenceModel {
+ static class MatchWithGroups implements TemplateScalarModel {
+ final String matchedInputPart;
+ final String[] groups;
+
+ MatchWithGroups(String input, Matcher matcher) {
+ matchedInputPart = input.substring(matcher.start(), matcher.end());
+ final int grpCount = matcher.groupCount() + 1;
+ groups = new String[grpCount];
+ for (int i = 0; i < grpCount; i++) {
+ groups[i] = matcher.group(i);
+ }
+ }
+
+ @Override
+ public String getAsString() {
+ return matchedInputPart;
+ }
+ }
+ final Pattern pattern;
+
+ final String input;
+ private Matcher firedEntireInputMatcher;
+ private Boolean entireInputMatched;
+
+ private TemplateSequenceModel entireInputMatchGroups;
+
+ private ArrayList matchingInputParts;
+
+ RegexMatchModel(Pattern pattern, String input) {
+ this.pattern = pattern;
+ this.input = input;
+ }
+
+ @Override
+ public TemplateModel get(int i) throws TemplateModelException {
+ ArrayList matchingInputParts = this.matchingInputParts;
+ if (matchingInputParts == null) {
+ matchingInputParts = getMatchingInputPartsAndStoreResults();
+ }
+ return (TemplateModel) matchingInputParts.get(i);
+ }
+
+ @Override
+ public boolean getAsBoolean() {
+ Boolean result = entireInputMatched;
+ return result != null ? result.booleanValue() : isEntrieInputMatchesAndStoreResults();
+ }
+
+ TemplateModel getGroups() {
+ TemplateSequenceModel entireInputMatchGroups = this.entireInputMatchGroups;
+ if (entireInputMatchGroups == null) {
+ Matcher t = firedEntireInputMatcher;
+ if (t == null) {
+ isEntrieInputMatchesAndStoreResults();
+ t = firedEntireInputMatcher;
+ }
+ final Matcher firedEntireInputMatcher = t;
+
+ entireInputMatchGroups = new TemplateSequenceModel() {
+
+ @Override
+ public TemplateModel get(int i) throws TemplateModelException {
+ try {
+ // Avoid IndexOutOfBoundsException:
+ if (i > firedEntireInputMatcher.groupCount()) {
+ return null;
+ }
+
+ return new SimpleScalar(firedEntireInputMatcher.group(i));
+ } catch (Exception e) {
+ throw new _TemplateModelException(e, "Failed to read match group");
+ }
+ }
+
+ @Override
+ public int size() throws TemplateModelException {
+ try {
+ return firedEntireInputMatcher.groupCount() + 1;
+ } catch (Exception e) {
+ throw new _TemplateModelException(e, "Failed to get match group count");
+ }
+ }
+
+ };
+ this.entireInputMatchGroups = entireInputMatchGroups;
+ }
+ return entireInputMatchGroups;
+ }
+
+ private ArrayList getMatchingInputPartsAndStoreResults() throws TemplateModelException {
+ ArrayList matchingInputParts = new ArrayList();
+
+ Matcher matcher = pattern.matcher(input);
+ while (matcher.find()) {
+ matchingInputParts.add(new MatchWithGroups(input, matcher));
+ }
+
+ this.matchingInputParts = matchingInputParts;
+ return matchingInputParts;
+ }
+
+ private boolean isEntrieInputMatchesAndStoreResults() {
+ Matcher matcher = pattern.matcher(input);
+ boolean matches = matcher.matches();
+ firedEntireInputMatcher = matcher;
+ entireInputMatched = Boolean.valueOf(matches);
+ return matches;
+ }
+
+ @Override
+ public TemplateModelIterator iterator() {
+ final ArrayList matchingInputParts = this.matchingInputParts;
+ if (matchingInputParts == null) {
+ final Matcher matcher = pattern.matcher(input);
+ return new TemplateModelIterator() {
+
+ private int nextIdx = 0;
+ boolean hasFindInfo = matcher.find();
+
+ @Override
+ public boolean hasNext() {
+ final ArrayList matchingInputParts = RegexMatchModel.this.matchingInputParts;
+ if (matchingInputParts == null) {
+ return hasFindInfo;
+ } else {
+ return nextIdx < matchingInputParts.size();
+ }
+ }
+
+ @Override
+ public TemplateModel next() throws TemplateModelException {
+ final ArrayList matchingInputParts = RegexMatchModel.this.matchingInputParts;
+ if (matchingInputParts == null) {
+ if (!hasFindInfo) throw new _TemplateModelException("There were no more matches");
+ MatchWithGroups result = new MatchWithGroups(input, matcher);
+ nextIdx++;
+ hasFindInfo = matcher.find();
+ return result;
+ } else {
+ try {
+ return (TemplateModel) matchingInputParts.get(nextIdx++);
+ } catch (IndexOutOfBoundsException e) {
+ throw new _TemplateModelException(e, "There were no more matches");
+ }
+ }
+ }
+
+ };
+ } else {
+ return new TemplateModelIterator() {
+
+ private int nextIdx = 0;
+
+ @Override
+ public boolean hasNext() {
+ return nextIdx < matchingInputParts.size();
+ }
+
+ @Override
+ public TemplateModel next() throws TemplateModelException {
+ try {
+ return (TemplateModel) matchingInputParts.get(nextIdx++);
+ } catch (IndexOutOfBoundsException e) {
+ throw new _TemplateModelException(e, "There were no more matches");
+ }
+ }
+ };
+ }
+ }
+
+ @Override
+ public int size() throws TemplateModelException {
+ ArrayList matchingInputParts = this.matchingInputParts;
+ if (matchingInputParts == null) {
+ matchingInputParts = getMatchingInputPartsAndStoreResults();
+ }
+ return matchingInputParts.size();
+ }
+ }
+
+ // Can't be instantiated
+ private BuiltInsForStringsRegexp() { }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsWithParseTimeParameters.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsWithParseTimeParameters.java b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsWithParseTimeParameters.java
new file mode 100644
index 0000000..1126410
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/BuiltInsWithParseTimeParameters.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.freemarker.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.freemarker.core.model.TemplateModel;
+
+
+final class BuiltInsWithParseTimeParameters {
+
+ /**
+ * Behaves similarly to the ternary operator of Java.
+ */
+ static class then_BI extends BuiltInWithParseTimeParameters {
+
+ private ASTExpression whenTrueExp;
+ private ASTExpression whenFalseExp;
+
+ @Override
+ TemplateModel _eval(Environment env) throws TemplateException {
+ boolean lho = target.evalToBoolean(env);
+ return (lho ? whenTrueExp : whenFalseExp).evalToNonMissing(env);
+ }
+
+ @Override
+ void bindToParameters(List parameters, Token openParen, Token closeParen) throws ParseException {
+ if (parameters.size() != 2) {
+ throw newArgumentCountException("requires exactly 2", openParen, closeParen);
+ }
+ whenTrueExp = (ASTExpression) parameters.get(0);
+ whenFalseExp = (ASTExpression) parameters.get(1);
+ }
+
+ @Override
+ protected ASTExpression getArgumentParameterValue(final int argIdx) {
+ switch (argIdx) {
+ case 0: return whenTrueExp;
+ case 1: return whenFalseExp;
+ default: throw new IndexOutOfBoundsException();
+ }
+ }
+
+ @Override
+ protected int getArgumentsCount() {
+ return 2;
+ }
+
+ @Override
+ protected List getArgumentsAsList() {
+ ArrayList args = new ArrayList(2);
+ args.add(whenTrueExp);
+ args.add(whenFalseExp);
+ return args;
+ }
+
+ @Override
+ protected void cloneArguments(ASTExpression cloneExp, String replacedIdentifier,
+ ASTExpression replacement, ReplacemenetState replacementState) {
+ then_BI clone = (then_BI) cloneExp;
+ clone.whenTrueExp = whenTrueExp.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState);
+ clone.whenFalseExp = whenFalseExp.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState);
+ }
+
+ }
+
+ private BuiltInsWithParseTimeParameters() {
+ // Not to be instantiated
+ }
+
+ static class switch_BI extends BuiltInWithParseTimeParameters {
+
+ private List/*<ASTExpression>*/ parameters;
+
+ @Override
+ void bindToParameters(List parameters, Token openParen, Token closeParen) throws ParseException {
+ if (parameters.size() < 2) {
+ throw newArgumentCountException("must have at least 2", openParen, closeParen);
+ }
+ this.parameters = parameters;
+ }
+
+ @Override
+ protected List getArgumentsAsList() {
+ return parameters;
+ }
+
+ @Override
+ protected int getArgumentsCount() {
+ return parameters.size();
+ }
+
+ @Override
+ protected ASTExpression getArgumentParameterValue(int argIdx) {
+ return (ASTExpression) parameters.get(argIdx);
+ }
+
+ @Override
+ protected void cloneArguments(ASTExpression clone, String replacedIdentifier, ASTExpression replacement,
+ ReplacemenetState replacementState) {
+ ArrayList parametersClone = new ArrayList(parameters.size());
+ for (int i = 0; i < parameters.size(); i++) {
+ parametersClone.add(((ASTExpression) parameters.get(i))
+ .deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState));
+ }
+ ((switch_BI) clone).parameters = parametersClone;
+ }
+
+ @Override
+ TemplateModel _eval(Environment env) throws TemplateException {
+ TemplateModel targetValue = target.evalToNonMissing(env);
+
+ List parameters = this.parameters;
+ int paramCnt = parameters.size();
+ for (int i = 0; i + 1 < paramCnt; i += 2) {
+ ASTExpression caseExp = (ASTExpression) parameters.get(i);
+ TemplateModel caseValue = caseExp.evalToNonMissing(env);
+ if (_EvalUtil.compare(
+ targetValue, target,
+ _EvalUtil.CMP_OP_EQUALS, "==",
+ caseValue, caseExp,
+ this, true,
+ false, false, false,
+ env)) {
+ return ((ASTExpression) parameters.get(i + 1)).evalToNonMissing(env);
+ }
+ }
+
+ if (paramCnt % 2 == 0) {
+ throw new _MiscTemplateException(target,
+ "The value before ?", key, "(case1, value1, case2, value2, ...) didn't match any of the "
+ + "case parameters, and there was no default value parameter (an additional last parameter) "
+ + "eithter. ");
+ }
+ return ((ASTExpression) parameters.get(paramCnt - 1)).evalToNonMissing(env);
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/3fd56062/freemarker-core/src/main/java/org/apache/freemarker/core/CallPlaceCustomDataInitializationException.java
----------------------------------------------------------------------
diff --git a/freemarker-core/src/main/java/org/apache/freemarker/core/CallPlaceCustomDataInitializationException.java b/freemarker-core/src/main/java/org/apache/freemarker/core/CallPlaceCustomDataInitializationException.java
new file mode 100644
index 0000000..ffaa2b0
--- /dev/null
+++ b/freemarker-core/src/main/java/org/apache/freemarker/core/CallPlaceCustomDataInitializationException.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.freemarker.core;
+
+/**
+ * Thrown by {@link DirectiveCallPlace#getOrCreateCustomData(Object, org.apache.freemarker.core.util.ObjectFactory)}
+ *
+ * @since 2.3.22
+ */
+public class CallPlaceCustomDataInitializationException extends Exception {
+
+ public CallPlaceCustomDataInitializationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}