You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by dl...@apache.org on 2020/02/03 22:36:56 UTC

[asterixdb] branch master updated: [NO ISSUE][COMP] Improve function parsing

This is an automated email from the ASF dual-hosted git repository.

dlych pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 45de234  [NO ISSUE][COMP] Improve function parsing
45de234 is described below

commit 45de2345f100e89579dc2d0e3169c837e6a30e50
Author: Dmitry Lychagin <dm...@couchbase.com>
AuthorDate: Mon Feb 3 12:01:28 2020 -0800

    [NO ISSUE][COMP] Improve function parsing
    
    - user model changes: no
    - storage format changes: no
    - interface changes: no
    
    Details:
    - Added IParser.parseFunctionBody() method that
      parses body of a user-defined function
    - Modified FunctionParser to parse function body
      directly by calling the above method instead
      of creating "declare function" statement
    - Consolidated SQLPP and AQL FunctionParsers
      into a single common class
    
    Change-Id: I498550c90f2ba492549d15b61d7607e986b08c04
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/4846
    Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Dmitry Lychagin <dm...@couchbase.com>
    Reviewed-by: Ian Maxon <im...@uci.edu>
---
 .../compiler/provider/AqlCompilationProvider.java  |  2 +-
 .../provider/SqlppCompilationProvider.java         |  2 +-
 .../asterix/test/sqlpp/ParserTestExecutor.java     |  2 +-
 asterixdb/asterix-lang-aql/pom.xml                 |  4 -
 .../lang/aql/rewrites/AQLRewriterFactory.java      |  9 +-
 .../lang/aql/rewrites/AqlQueryRewriter.java        | 17 ++--
 asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj  | 33 +++++++-
 .../apache/asterix/lang/common/base/IParser.java   |  5 ++
 .../lang/common}/parser/FunctionParser.java        | 50 +++++-------
 .../asterix/lang/sqlpp/parser/FunctionParser.java  | 95 ----------------------
 .../sqlpp/rewrites/SqlppFunctionBodyRewriter.java  |  5 ++
 .../rewrites/SqlppFunctionBodyRewriterFactory.java |  9 +-
 .../lang/sqlpp/rewrites/SqlppQueryRewriter.java    | 16 +++-
 .../lang/sqlpp/rewrites/SqlppRewriterFactory.java  |  9 +-
 .../asterix-lang-sqlpp/src/main/javacc/SQLPP.jj    | 36 +++++++-
 15 files changed, 147 insertions(+), 147 deletions(-)

diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/AqlCompilationProvider.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/AqlCompilationProvider.java
index 548917a..662010f 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/AqlCompilationProvider.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/AqlCompilationProvider.java
@@ -42,7 +42,7 @@ public class AqlCompilationProvider implements ILangCompilationProvider {
 
     @Override
     public IRewriterFactory getRewriterFactory() {
-        return new AQLRewriterFactory();
+        return new AQLRewriterFactory(getParserFactory());
     }
 
     @Override
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
index 6451b6f..2c18d41 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/compiler/provider/SqlppCompilationProvider.java
@@ -42,7 +42,7 @@ public class SqlppCompilationProvider implements ILangCompilationProvider {
 
     @Override
     public IRewriterFactory getRewriterFactory() {
-        return new SqlppRewriterFactory();
+        return new SqlppRewriterFactory(getParserFactory());
     }
 
     @Override
diff --git a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
index 0ab41b7..c454993 100644
--- a/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
+++ b/asterixdb/asterix-app/src/test/java/org/apache/asterix/test/sqlpp/ParserTestExecutor.java
@@ -69,7 +69,7 @@ import junit.extensions.PA;
 public class ParserTestExecutor extends TestExecutor {
 
     private IParserFactory sqlppParserFactory = new SqlppParserFactory();
-    private IRewriterFactory sqlppRewriterFactory = new SqlppRewriterFactory();
+    private IRewriterFactory sqlppRewriterFactory = new SqlppRewriterFactory(sqlppParserFactory);
 
     @Override
     public void executeTest(String actualPath, TestCaseContext testCaseCtx, ProcessBuilder pb,
diff --git a/asterixdb/asterix-lang-aql/pom.xml b/asterixdb/asterix-lang-aql/pom.xml
index f202192..de36d67 100644
--- a/asterixdb/asterix-lang-aql/pom.xml
+++ b/asterixdb/asterix-lang-aql/pom.xml
@@ -154,10 +154,6 @@
       <artifactId>algebricks-common</artifactId>
     </dependency>
     <dependency>
-      <groupId>commons-io</groupId>
-      <artifactId>commons-io</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.asterix</groupId>
       <artifactId>asterix-om</artifactId>
       <version>${project.version}</version>
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AQLRewriterFactory.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AQLRewriterFactory.java
index 87885b8..0987d89 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AQLRewriterFactory.java
+++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AQLRewriterFactory.java
@@ -18,15 +18,22 @@
  */
 package org.apache.asterix.lang.aql.rewrites;
 
+import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.base.IRewriterFactory;
 import org.apache.asterix.lang.common.base.IStatementRewriter;
 
 public class AQLRewriterFactory implements IRewriterFactory {
 
+    private final IParserFactory parserFactory;
+
+    public AQLRewriterFactory(IParserFactory parserFactory) {
+        this.parserFactory = parserFactory;
+    }
+
     @Override
     public IQueryRewriter createQueryRewriter() {
-        return new AqlQueryRewriter();
+        return new AqlQueryRewriter(parserFactory);
     }
 
     @Override
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java
index 9aaf5b7..b3097dc 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java
+++ b/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/rewrites/AqlQueryRewriter.java
@@ -30,14 +30,13 @@ import org.apache.asterix.lang.aql.clause.DistinctClause;
 import org.apache.asterix.lang.aql.clause.ForClause;
 import org.apache.asterix.lang.aql.expression.FLWOGRExpression;
 import org.apache.asterix.lang.aql.expression.UnionExpr;
-import org.apache.asterix.lang.aql.parser.AQLParserFactory;
-import org.apache.asterix.lang.aql.parser.FunctionParser;
 import org.apache.asterix.lang.aql.rewrites.visitor.AqlBuiltinFunctionRewriteVisitor;
 import org.apache.asterix.lang.aql.visitor.AQLInlineUdfsVisitor;
 import org.apache.asterix.lang.aql.visitor.base.IAQLVisitor;
 import org.apache.asterix.lang.common.base.Clause;
 import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.Expression.Kind;
+import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.base.IReturningStatement;
 import org.apache.asterix.lang.common.clause.GroupbyClause;
@@ -45,6 +44,7 @@ import org.apache.asterix.lang.common.clause.LetClause;
 import org.apache.asterix.lang.common.expression.CallExpr;
 import org.apache.asterix.lang.common.expression.GbyVariableExpressionPair;
 import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.parser.FunctionParser;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
 import org.apache.asterix.lang.common.struct.Identifier;
@@ -53,16 +53,23 @@ import org.apache.asterix.lang.common.util.CommonFunctionMapUtil;
 import org.apache.asterix.lang.common.util.FunctionUtil;
 import org.apache.asterix.lang.common.visitor.GatherFunctionCallsVisitor;
 import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.metadata.entities.Function;
 import org.apache.hyracks.algebricks.common.utils.Pair;
 
 class AqlQueryRewriter implements IQueryRewriter {
 
-    private final FunctionParser functionParser = new FunctionParser(new AQLParserFactory());
+    private final IParserFactory parserFactory;
+    private final FunctionParser functionParser;
     private IReturningStatement topStatement;
     private List<FunctionDecl> declaredFunctions;
     private LangRewritingContext context;
     private MetadataProvider metadataProvider;
 
+    AqlQueryRewriter(IParserFactory parserFactory) {
+        this.parserFactory = parserFactory;
+        functionParser = new FunctionParser(Function.LANGUAGE_AQL, this.parserFactory);
+    }
+
     private void setup(List<FunctionDecl> declaredFunctions, IReturningStatement topStatement,
             MetadataProvider metadataProvider, LangRewritingContext context) {
         this.topStatement = topStatement;
@@ -127,8 +134,8 @@ class AqlQueryRewriter implements IQueryRewriter {
             declaredFunctions.addAll(storedFunctionDecls);
         }
         if (!declaredFunctions.isEmpty()) {
-            AQLInlineUdfsVisitor visitor =
-                    new AQLInlineUdfsVisitor(context, new AQLRewriterFactory(), declaredFunctions, metadataProvider);
+            AQLInlineUdfsVisitor visitor = new AQLInlineUdfsVisitor(context, new AQLRewriterFactory(parserFactory),
+                    declaredFunctions, metadataProvider);
             while (topStatement.accept(visitor, declaredFunctions)) {
                 // loop until no more changes
             }
diff --git a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
index 8094bdf..c73a1e8 100644
--- a/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
+++ b/asterixdb/asterix-lang-aql/src/main/javacc/AQL.jj
@@ -310,6 +310,26 @@ class AQLParser extends ScopeChecker implements IParser {
         return new AQLParser(text).parseExpression();
     }
 
+    @Override
+    public Expression parseFunctionBody(FunctionSignature signature, List<VarIdentifier> paramList)
+      throws CompilationException {
+        return parseImpl(new ParseFunction<Expression>() {
+            @Override
+            public Expression parse() throws ParseException {
+                DataverseName dataverse = defaultDataverse;
+                defaultDataverse = signature.getDataverseName();
+                createNewScope();
+                for (VarIdentifier var : paramList) {
+                  getCurrentScope().addNewVarSymbolToScope(var);
+                }
+                Expression functionBodyExpr = AQLParser.this.FunctionBody();
+                removeCurrentScope();
+                defaultDataverse = dataverse;
+                return functionBodyExpr;
+            }
+        });
+    }
+
     private <T> T parseImpl(ParseFunction<T> parseFunction) throws CompilationException {
         try {
             return parseFunction.parse();
@@ -731,7 +751,7 @@ CreateFunctionStatement FunctionSpecification() throws ParseException:
   {
      beginPos = token;
   }
-  functionBodyExpr = Expression() <RIGHTBRACE>
+  functionBodyExpr = FunctionBody() <RIGHTBRACE>
     {
       endPos = token;
       functionBody = extractFragment(beginPos.beginLine, beginPos.beginColumn, endPos.beginLine, endPos.beginColumn);
@@ -746,6 +766,17 @@ CreateFunctionStatement FunctionSpecification() throws ParseException:
     }
 }
 
+Expression FunctionBody() throws ParseException:
+{
+  Expression functionBodyExpr = null;
+}
+{
+  functionBodyExpr = Expression()
+  {
+    return functionBodyExpr;
+  }
+}
+
 CreateFeedStatement FeedSpecification() throws ParseException:
 {
   Pair<DataverseName,Identifier> nameComponents = null;
diff --git a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java
index 662a3f9..578d954 100644
--- a/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/base/IParser.java
@@ -22,12 +22,17 @@ import java.util.Collection;
 import java.util.List;
 
 import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.lang.common.struct.VarIdentifier;
 import org.apache.hyracks.api.exceptions.Warning;
 
 public interface IParser {
 
     List<Statement> parse() throws CompilationException;
 
+    Expression parseFunctionBody(FunctionSignature signature, List<VarIdentifier> paramList)
+            throws CompilationException;
+
     /**
      * Gets the warnings generated during parsing up to the max number argument.
      */
diff --git a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/parser/FunctionParser.java b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/FunctionParser.java
similarity index 55%
rename from asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/parser/FunctionParser.java
rename to asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/FunctionParser.java
index adaeaaf..0bd1f84 100644
--- a/asterixdb/asterix-lang-aql/src/main/java/org/apache/asterix/lang/aql/parser/FunctionParser.java
+++ b/asterixdb/asterix-lang-common/src/main/java/org/apache/asterix/lang/common/parser/FunctionParser.java
@@ -17,59 +17,51 @@
  * under the License.
  */
 
-package org.apache.asterix.lang.aql.parser;
+package org.apache.asterix.lang.common.parser;
 
+import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.exceptions.ErrorCode;
+import org.apache.asterix.common.functions.FunctionSignature;
+import org.apache.asterix.lang.common.base.Expression;
 import org.apache.asterix.lang.common.base.IParser;
 import org.apache.asterix.lang.common.base.IParserFactory;
-import org.apache.asterix.lang.common.base.Statement;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
 import org.apache.asterix.lang.common.struct.VarIdentifier;
 import org.apache.asterix.metadata.entities.Function;
-import org.apache.commons.io.input.CharSequenceReader;
 
 public class FunctionParser {
 
+    private final String language;
+
     private final IParserFactory parserFactory;
 
-    public FunctionParser(IParserFactory parserFactory) {
+    public FunctionParser(String language, IParserFactory parserFactory) {
+        this.language = language;
         this.parserFactory = parserFactory;
     }
 
     public FunctionDecl getFunctionDecl(Function function) throws CompilationException {
-        if (!function.getLanguage().equals(Function.LANGUAGE_AQL)) {
-            throw new CompilationException(ErrorCode.COMPILATION_INCOMPATIBLE_FUNCTION_LANGUAGE, Function.LANGUAGE_AQL,
+        if (!function.getLanguage().equals(language)) {
+            throw new CompilationException(ErrorCode.COMPILATION_INCOMPATIBLE_FUNCTION_LANGUAGE, language,
                     function.getLanguage());
         }
-        String functionBody = function.getFunctionBody();
-        List<String> arguments = function.getArgNames();
-        List<VarIdentifier> varIdentifiers = new ArrayList<VarIdentifier>();
 
-        StringBuilder builder = new StringBuilder();
-        builder.append(" use dataverse " + function.getDataverseName() + ";");
-        builder.append(" declare function " + function.getName().split("@")[0]);
-        builder.append("(");
-        boolean first = true;
-        for (String argument : arguments) {
-            VarIdentifier varId = new VarIdentifier(argument);
-            varIdentifiers.add(varId);
-            if (first) {
-                first = false;
-            } else {
-                builder.append(",");
-            }
-            builder.append(argument);
+        FunctionSignature signature = function.getSignature();
+
+        List<String> argNames = function.getArgNames();
+        List<VarIdentifier> paramList = new ArrayList<>(argNames.size());
+        for (String argName : argNames) {
+            paramList.add(new VarIdentifier(argName));
         }
-        builder.append("){\n").append(functionBody).append("\n}");
 
-        IParser parser = parserFactory.createParser(new CharSequenceReader(builder));
-        List<Statement> statements = parser.parse();
-        FunctionDecl decl = (FunctionDecl) statements.get(1);
-        return decl;
-    }
+        String functionBody = function.getFunctionBody();
+        IParser parser = parserFactory.createParser(new StringReader(functionBody));
+        Expression functionBodyExpr = parser.parseFunctionBody(signature, paramList);
 
+        return new FunctionDecl(signature, paramList, functionBodyExpr);
+    }
 }
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/FunctionParser.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/FunctionParser.java
deleted file mode 100644
index 9942e25..0000000
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/parser/FunctionParser.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.asterix.lang.sqlpp.parser;
-
-import java.io.StringReader;
-import java.util.List;
-
-import org.apache.asterix.common.exceptions.CompilationException;
-import org.apache.asterix.common.exceptions.ErrorCode;
-import org.apache.asterix.common.metadata.DataverseName;
-import org.apache.asterix.lang.common.base.IParser;
-import org.apache.asterix.lang.common.base.IParserFactory;
-import org.apache.asterix.lang.common.base.Statement;
-import org.apache.asterix.lang.common.statement.FunctionDecl;
-import org.apache.asterix.lang.common.struct.VarIdentifier;
-import org.apache.asterix.lang.common.util.DataverseNameUtils;
-import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil;
-import org.apache.asterix.metadata.entities.Function;
-import org.apache.asterix.om.types.IAType;
-import org.apache.hyracks.algebricks.common.utils.Pair;
-
-public class FunctionParser {
-
-    private final IParserFactory parserFactory;
-
-    public FunctionParser(IParserFactory parserFactory) {
-        this.parserFactory = parserFactory;
-    }
-
-    public FunctionDecl getFunctionDecl(Function function) throws CompilationException {
-        if (!function.getLanguage().equals(Function.LANGUAGE_SQLPP)) {
-            throw new CompilationException(ErrorCode.COMPILATION_INCOMPATIBLE_FUNCTION_LANGUAGE,
-                    Function.LANGUAGE_SQLPP, function.getLanguage());
-        }
-
-        String functionBody = function.getFunctionBody();
-        List<String> argNames = function.getArgNames();
-        List<Pair<DataverseName, IAType>> args = function.getArguments();
-
-        StringBuilder builder = new StringBuilder();
-        builder.append(" use " + DataverseNameUtils.generateDataverseName(function.getDataverseName()) + ";");
-        builder.append(" declare function " + function.getName().split("@")[0]);
-        builder.append("(");
-        for (int i = 0; i < argNames.size(); i++) {
-            String param = argNames.get(i);
-            String type = null;
-            if (args.get(i) != null) {
-                Pair<DataverseName, IAType> t = args.get(i);
-                String argToStringType = t.getFirst().getCanonicalForm() + "." + t.getSecond().getTypeName();
-                if (!"asterix.any".equalsIgnoreCase(argToStringType)) {
-                    type = argToStringType;
-                }
-            }
-            VarIdentifier varId = SqlppVariableUtil.toUserDefinedVariableName(param);
-            builder.append(varId);
-            if (type != null) {
-                builder.append(":");
-                builder.append(type);
-            }
-            builder.append(",");
-        }
-        if (argNames.size() > 0) {
-            builder.delete(builder.length() - 1, builder.length());
-        }
-        builder.append(")");
-        builder.append("{");
-        builder.append("\n");
-        builder.append(functionBody);
-        builder.append("\n");
-        builder.append("};");
-
-        IParser parser = parserFactory.createParser(new StringReader(new String(builder)));
-        List<Statement> statements = parser.parse();
-        FunctionDecl decl = (FunctionDecl) statements.get(1);
-        return decl;
-    }
-
-}
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
index bde40de..1e16b70 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriter.java
@@ -22,6 +22,7 @@ import java.util.Collection;
 import java.util.List;
 
 import org.apache.asterix.common.exceptions.CompilationException;
+import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.IReturningStatement;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
@@ -30,6 +31,10 @@ import org.apache.asterix.metadata.declared.MetadataProvider;
 
 class SqlppFunctionBodyRewriter extends SqlppQueryRewriter {
 
+    public SqlppFunctionBodyRewriter(IParserFactory parserFactory) {
+        super(parserFactory);
+    }
+
     @Override
     public void rewrite(List<FunctionDecl> declaredFunctions, IReturningStatement topStatement,
             MetadataProvider metadataProvider, LangRewritingContext context, boolean inlineUdfs,
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriterFactory.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriterFactory.java
index 900cd73..bf27464 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriterFactory.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppFunctionBodyRewriterFactory.java
@@ -18,15 +18,22 @@
  */
 package org.apache.asterix.lang.sqlpp.rewrites;
 
+import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.base.IRewriterFactory;
 import org.apache.asterix.lang.common.base.IStatementRewriter;
 
 class SqlppFunctionBodyRewriterFactory implements IRewriterFactory {
 
+    private final IParserFactory parserFactory;
+
+    public SqlppFunctionBodyRewriterFactory(IParserFactory parserFactory) {
+        this.parserFactory = parserFactory;
+    }
+
     @Override
     public IQueryRewriter createQueryRewriter() {
-        return new SqlppFunctionBodyRewriter();
+        return new SqlppFunctionBodyRewriter(parserFactory);
     }
 
     @Override
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
index 8bc319f..ccc4b26 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppQueryRewriter.java
@@ -28,11 +28,13 @@ import org.apache.asterix.common.exceptions.CompilationException;
 import org.apache.asterix.common.functions.FunctionSignature;
 import org.apache.asterix.lang.common.base.AbstractClause;
 import org.apache.asterix.lang.common.base.Expression;
+import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.base.IReturningStatement;
 import org.apache.asterix.lang.common.expression.CallExpr;
 import org.apache.asterix.lang.common.expression.ListSliceExpression;
 import org.apache.asterix.lang.common.expression.VariableExpr;
+import org.apache.asterix.lang.common.parser.FunctionParser;
 import org.apache.asterix.lang.common.rewrites.LangRewritingContext;
 import org.apache.asterix.lang.common.statement.FunctionDecl;
 import org.apache.asterix.lang.common.struct.Identifier;
@@ -56,8 +58,6 @@ import org.apache.asterix.lang.sqlpp.clause.UnnestClause;
 import org.apache.asterix.lang.sqlpp.expression.CaseExpression;
 import org.apache.asterix.lang.sqlpp.expression.SelectExpression;
 import org.apache.asterix.lang.sqlpp.expression.WindowExpression;
-import org.apache.asterix.lang.sqlpp.parser.FunctionParser;
-import org.apache.asterix.lang.sqlpp.parser.SqlppParserFactory;
 import org.apache.asterix.lang.sqlpp.rewrites.visitor.GenerateColumnNameVisitor;
 import org.apache.asterix.lang.sqlpp.rewrites.visitor.InlineColumnAliasVisitor;
 import org.apache.asterix.lang.sqlpp.rewrites.visitor.InlineWithExpressionVisitor;
@@ -78,6 +78,7 @@ import org.apache.asterix.lang.sqlpp.util.SqlppAstPrintUtil;
 import org.apache.asterix.lang.sqlpp.util.SqlppVariableUtil;
 import org.apache.asterix.lang.sqlpp.visitor.base.ISqlppVisitor;
 import org.apache.asterix.metadata.declared.MetadataProvider;
+import org.apache.asterix.metadata.entities.Function;
 import org.apache.hyracks.algebricks.common.utils.Pair;
 import org.apache.hyracks.util.LogRedactionUtil;
 import org.apache.logging.log4j.LogManager;
@@ -89,7 +90,8 @@ public class SqlppQueryRewriter implements IQueryRewriter {
 
     public static final String INLINE_WITH_OPTION = "inline_with";
     private static final boolean INLINE_WITH_OPTION_DEFAULT = true;
-    private final FunctionParser functionRepository = new FunctionParser(new SqlppParserFactory());
+    private final IParserFactory parserFactory;
+    private final FunctionParser functionRepository;
     private IReturningStatement topExpr;
     private List<FunctionDecl> declaredFunctions;
     private LangRewritingContext context;
@@ -97,6 +99,11 @@ public class SqlppQueryRewriter implements IQueryRewriter {
     private Collection<VarIdentifier> externalVars;
     private boolean isLogEnabled;
 
+    public SqlppQueryRewriter(IParserFactory parserFactory) {
+        this.parserFactory = parserFactory;
+        functionRepository = new FunctionParser(Function.LANGUAGE_SQLPP, parserFactory);
+    }
+
     protected void setup(List<FunctionDecl> declaredFunctions, IReturningStatement topExpr,
             MetadataProvider metadataProvider, LangRewritingContext context, Collection<VarIdentifier> externalVars)
             throws CompilationException {
@@ -262,7 +269,8 @@ public class SqlppQueryRewriter implements IQueryRewriter {
         declaredFunctions.addAll(usedStoredFunctionDecls);
         if (inlineUdfs && !declaredFunctions.isEmpty()) {
             SqlppInlineUdfsVisitor visitor = new SqlppInlineUdfsVisitor(context,
-                    new SqlppFunctionBodyRewriterFactory() /* the rewriter for function bodies expressions*/,
+                    new SqlppFunctionBodyRewriterFactory(
+                            parserFactory) /* the rewriter for function bodies expressions*/,
                     declaredFunctions, metadataProvider);
             while (rewriteTopExpr(visitor, declaredFunctions)) {
                 // loop until no more changes
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppRewriterFactory.java b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppRewriterFactory.java
index 64fa576..67a0243 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppRewriterFactory.java
+++ b/asterixdb/asterix-lang-sqlpp/src/main/java/org/apache/asterix/lang/sqlpp/rewrites/SqlppRewriterFactory.java
@@ -18,15 +18,22 @@
  */
 package org.apache.asterix.lang.sqlpp.rewrites;
 
+import org.apache.asterix.lang.common.base.IParserFactory;
 import org.apache.asterix.lang.common.base.IQueryRewriter;
 import org.apache.asterix.lang.common.base.IRewriterFactory;
 import org.apache.asterix.lang.common.base.IStatementRewriter;
 
 public class SqlppRewriterFactory implements IRewriterFactory {
 
+    private final IParserFactory parserFactory;
+
+    public SqlppRewriterFactory(IParserFactory parserFactory) {
+        this.parserFactory = parserFactory;
+    }
+
     @Override
     public IQueryRewriter createQueryRewriter() {
-        return new SqlppQueryRewriter();
+        return new SqlppQueryRewriter(parserFactory);
     }
 
     @Override
diff --git a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
index fcd06eb..feff5c5 100644
--- a/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
+++ b/asterixdb/asterix-lang-sqlpp/src/main/javacc/SQLPP.jj
@@ -325,6 +325,7 @@ class SQLPPParser extends ScopeChecker implements IParser {
         //st.accept(new SQLPPPrintVisitor(), 0);
     }
 
+    @Override
     public List<Statement> parse() throws CompilationException {
         return parseImpl(new ParseFunction<List<Statement>>() {
             @Override
@@ -347,6 +348,23 @@ class SQLPPParser extends ScopeChecker implements IParser {
         return new SQLPPParser(text).parseExpression();
     }
 
+    @Override
+    public Expression parseFunctionBody(FunctionSignature signature, List<VarIdentifier> paramList)
+      throws CompilationException {
+        return parseImpl(new ParseFunction<Expression>() {
+            @Override
+            public Expression parse() throws ParseException {
+                DataverseName dataverse = defaultDataverse;
+                defaultDataverse = signature.getDataverseName();
+                createNewScope();
+                Expression functionBodyExpr = SQLPPParser.this.FunctionBody();
+                removeCurrentScope();
+                defaultDataverse = dataverse;
+                return functionBodyExpr;
+            }
+        });
+    }
+
     private <T> T parseImpl(ParseFunction<T> parseFunction) throws CompilationException {
         warningCollector.clear();
         hintCollector.clear();
@@ -1079,7 +1097,7 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken) throws Parse
           createNewScope();
           beginPos = token;
       }
-      (functionBodyExpr = SelectExpression(true) | functionBodyExpr = Expression())
+      functionBodyExpr = FunctionBody()
       <RIGHTBRACE>{
           endPos = token;
           functionBody = extractFragment(beginPos.beginLine, beginPos.beginColumn, endPos.beginLine, endPos.beginColumn);
@@ -1096,11 +1114,12 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken) throws Parse
      (
         LOOKAHEAD({laIdentifier(INLINE)})
         (
-              <IDENTIFIER> <AS> {
+              <IDENTIFIER> <AS>
+              {
                   createNewScope();
                   beginPos = token;
               }
-              (functionBodyExpr = SelectExpression(true) | functionBodyExpr = Expression())
+              functionBodyExpr = FunctionBody()
               {
                   endPos = token;
                   functionBody = extractFragment(beginPos.endLine, beginPos.beginColumn+1, endPos.endLine, endPos.endColumn+1);
@@ -1137,6 +1156,17 @@ CreateFunctionStatement FunctionSpecification(Token startStmtToken) throws Parse
   )
 }
 
+Expression FunctionBody() throws ParseException:
+{
+  Expression functionBodyExpr = null;
+}
+{
+  ( functionBodyExpr = SelectExpression(true) | functionBodyExpr = Expression() )
+  {
+    return functionBodyExpr;
+  }
+}
+
 CreateFeedStatement CreateFeedStatement(Token startStmtToken) throws ParseException:
 {
   CreateFeedStatement stmt = null;