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);
+    }
+
+}