diff --git a/sqlTranslate/.idea/workspace.xml b/sqlTranslate/.idea/workspace.xml
index c8f8f17a4..3306e3462 100644
--- a/sqlTranslate/.idea/workspace.xml
+++ b/sqlTranslate/.idea/workspace.xml
@@ -4,18 +4,20 @@
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
@@ -113,13 +115,6 @@
1723106789329
-
- 1726065430463
-
-
-
- 1726065430463
-
1726066806993
@@ -456,7 +451,14 @@
1726561299659
-
+
+ 1726583392370
+
+
+
+ 1726583392370
+
+
@@ -471,7 +473,6 @@
-
@@ -496,7 +497,8 @@
-
+
+
diff --git a/sqlTranslate/src/main/java/Generator/OpenGaussGenerator.java b/sqlTranslate/src/main/java/Generator/OpenGaussGenerator.java
index a00185ee6..764d557f1 100644
--- a/sqlTranslate/src/main/java/Generator/OpenGaussGenerator.java
+++ b/sqlTranslate/src/main/java/Generator/OpenGaussGenerator.java
@@ -1,6 +1,6 @@
package Generator;
-import Interface.ColumnType;
+import Interface.DataType;
import Lexer.OracleLexer;
import Lexer.Token;
import Parser.AST.ASTNode;
@@ -15,6 +15,10 @@ import Parser.AST.Drop.DropNode;
import Parser.AST.Drop.DropOptionNode;
import Parser.AST.Exception.ExceptionActionNode;
import Parser.AST.Exception.ExceptionNode;
+import Parser.AST.Function.FunctionColumnNode;
+import Parser.AST.Function.FunctionEndNode;
+import Parser.AST.Function.FunctionNode;
+import Parser.AST.Function.FunctionRetDefNode;
import Parser.AST.Insert.InsertNode;
import Parser.AST.Join.JoinConditionNode;
import Parser.AST.Join.JoinSourceTabNode;
@@ -82,6 +86,9 @@ public class OpenGaussGenerator {
else if (node instanceof ProcedureNode) {
return GenProcedureSQL(node);
}
+ else if (node instanceof FunctionNode) {
+ return GenFunctionSQL(node);
+ }
else {
try {
throw new GenerateFailedException("Root node:" + node.getClass() + "(Unsupported node type!)");
@@ -154,7 +161,12 @@ public class OpenGaussGenerator {
private String GenProcedureSQL(ASTNode node) {
visitPL(node);
- System.out.println(node.getASTString());
+// System.out.println(node.getASTString());
+ return node.toQueryString();
+ }
+
+ private String GenFunctionSQL(ASTNode node) {
+ visitFunc(node);
return node.toQueryString();
}
@@ -271,6 +283,25 @@ public class OpenGaussGenerator {
visitPL(child);
}
}
+
+ private void visitFunc(ASTNode node) {
+ if (node instanceof FunctionRetDefNode) {
+ PLConvert(node);
+ }
+ else if (node instanceof ExceptionNode) {
+ visitException(node);
+ }
+ else if (node instanceof FunctionColumnNode) {
+ ColumnTypeConvert((FunctionColumnNode) node);
+ }
+ else if (node instanceof FunctionEndNode) {
+ PLConvert(node);
+ }
+ for (ASTNode child : node.getChildren()) {
+ visitFunc(child);
+ }
+ }
+
private void PLConvert(ASTNode node) {
if (node.checkExistsByRegex("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
String printObj = "";
@@ -359,10 +390,36 @@ public class OpenGaussGenerator {
tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
node.setTokens(tokens);
}
+ if (node instanceof FunctionEndNode) {
+ List tokens = new ArrayList<>();
+ tokens.add(new Token(Token.TokenType.KEYWORD, "END"));
+ tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
+ tokens.add(new Token(Token.TokenType.KEYWORD, "$$"));
+ tokens.add(new Token(Token.TokenType.KEYWORD, "LANGUAGE"));
+ tokens.add(new Token(Token.TokenType.KEYWORD, "plpgsql"));
+ tokens.add(new Token(Token.TokenType.SYMBOL, ";"));
+ node.setTokens(tokens);
+ }
+ if (node instanceof FunctionRetDefNode) {
+ List tokens = new ArrayList<>();
+ for (Token token: node.getTokens()) {
+ if (token.hasType(Token.TokenType.KEYWORD) && token.getValue().equalsIgnoreCase("RETURN")) {
+ tokens.add(new Token(Token.TokenType.KEYWORD, "RETURNS"));
+ }
+ else if (token.hasType(Token.TokenType.KEYWORD) && token.getValue().equalsIgnoreCase("IS")) {
+ tokens.add(new Token(Token.TokenType.KEYWORD, "AS"));
+ tokens.add(new Token(Token.TokenType.KEYWORD, "$$"));
+ }
+ else {
+ tokens.add(token);
+ }
+ }
+ node.setTokens(tokens);
+ }
}
- private void ColumnTypeConvert(ColumnType node) {
+ private void ColumnTypeConvert(DataType node) {
// type convert
if (node.getType().getValue().equalsIgnoreCase("NUMBER")) {
node.setType(new Token(Token.TokenType.KEYWORD, "NUMERIC"));
diff --git a/sqlTranslate/src/main/java/Interface/ColumnType.java b/sqlTranslate/src/main/java/Interface/DataType.java
similarity index 82%
rename from sqlTranslate/src/main/java/Interface/ColumnType.java
rename to sqlTranslate/src/main/java/Interface/DataType.java
index 1e82d1016..2174d4a8e 100644
--- a/sqlTranslate/src/main/java/Interface/ColumnType.java
+++ b/sqlTranslate/src/main/java/Interface/DataType.java
@@ -2,7 +2,7 @@ package Interface;
import Lexer.Token;
-public interface ColumnType {
+public interface DataType {
Token getType();
void setType(Token type);
void ResetTokensbyNameTypeConstraint();
diff --git a/sqlTranslate/src/main/java/Lexer/OracleLexer.java b/sqlTranslate/src/main/java/Lexer/OracleLexer.java
index 6f63c9604..5f0c77948 100644
--- a/sqlTranslate/src/main/java/Lexer/OracleLexer.java
+++ b/sqlTranslate/src/main/java/Lexer/OracleLexer.java
@@ -37,6 +37,8 @@ public class OracleLexer {
, "EXCEPTION", "SQLERRM", "ZERO_DIVIDE", "INVALID_NUMBER", "OTHERS"
// Procedure
, "PROCEDURE", "IS", "IN", "OUT", "$$", "COMMIT", "ROLLBACK", "EXEC", "EXECUTE"
+ // function
+ , "FUNCTION", "RETURN"
};
private static final Pattern TOKEN_PATTERN = Pattern.compile(
"(NUMBER\\(.*?\\))|" + // NUMBER() function
@@ -55,6 +57,7 @@ public class OracleLexer {
"(MIN\\(.*?\\))|" + // MIN() function
"(\\|\\|\\s*'.*?'\\s*\\|\\|)|" + // || '*' ||
"(DBMS_OUTPUT.PUT_LINE\\(.*?\\))|" + // DBMS_OUTPUT.PUT_LINE() function
+ "(LENGTH\\(.*?\\))|" + // LENGTH() function
"(NOT NULL)|" +
"(PRIMARY KEY)|" +
@@ -177,6 +180,9 @@ public class OracleLexer {
} else if (tokenValue.matches("(?i)DBMS_OUTPUT.PUT_LINE\\(.*?\\)")) {
// RAW() function, CASE_INSENSITIVE
return new Token(Token.TokenType.KEYWORD, tokenValue);
+ } else if (tokenValue.matches("(?i)LENGTH\\(.*?\\)")) {
+ // RAW() function, CASE_INSENSITIVE
+ return new Token(Token.TokenType.KEYWORD, tokenValue);
}
else if (isKeyword(tokenValue)) {
diff --git a/sqlTranslate/src/main/java/Main.java b/sqlTranslate/src/main/java/Main.java
index 1f62f6ff3..5952be8f8 100644
--- a/sqlTranslate/src/main/java/Main.java
+++ b/sqlTranslate/src/main/java/Main.java
@@ -60,33 +60,40 @@ public class Main {
// " DBMS_OUTPUT.PUT_LINE('Caught an exception: Invalid number');\n" +
// " WHEN OTHERS THEN\n" +
// " DBMS_OUTPUT.PUT_LINE('Caught an exception: ' || SQLERRM);";
- String sql = "CREATE OR REPLACE PROCEDURE update_salary (\n" +
- " employee_id IN NUMBER,\n" +
- " new_salary IN OUT NUMBER\n" +
- " ) IS\n" +
- " v_employee employees%ROWTYPE;\n" +
- " BEGIN\n" +
- " SELECT * INTO v_employee FROM employees WHERE employee_id = employee_id;\n" +
- "\n" +
- " IF new_salary < 3000 THEN\n" +
- " new_salary := new_salary * 1.1;\n" +
- " ELSE\n" +
- " new_salary := new_salary * 1.05;\n" +
- " END IF;\n" +
- "\n" +
- " UPDATE employees SET salary = new_salary WHERE employee_id = employee_id;\n" +
- " COMMIT;\n" +
- "\n" +
- " DBMS_OUTPUT.PUT_LINE('Updated Salary: ' || new_salary);\n" +
- " EXCEPTION\n" +
- " WHEN NO_DATA_FOUND THEN\n" +
- " DBMS_OUTPUT.PUT_LINE('Employee not found.');\n" +
- " WHEN TOO_MANY_ROWS THEN\n" +
- " DBMS_OUTPUT.PUT_LINE('Multiple employees found.');\n" +
- " WHEN OTHERS THEN\n" +
- " DBMS_OUTPUT.PUT_LINE('An error occurred: ' || SQLERRM);\n" +
- " END update_salary;\n" +
- " /";
+// String sql = "CREATE OR REPLACE PROCEDURE update_salary (\n" +
+// " employee_id IN NUMBER,\n" +
+// " new_salary IN OUT NUMBER\n" +
+// " ) IS\n" +
+// " v_employee employees%ROWTYPE;\n" +
+// " BEGIN\n" +
+// " SELECT * INTO v_employee FROM employees WHERE employee_id = employee_id;\n" +
+// "\n" +
+// " IF new_salary < 3000 THEN\n" +
+// " new_salary := new_salary * 1.1;\n" +
+// " ELSE\n" +
+// " new_salary := new_salary * 1.05;\n" +
+// " END IF;\n" +
+// "\n" +
+// " UPDATE employees SET salary = new_salary WHERE employee_id = employee_id;\n" +
+// " COMMIT;\n" +
+// "\n" +
+// " DBMS_OUTPUT.PUT_LINE('Updated Salary: ' || new_salary);\n" +
+// " EXCEPTION\n" +
+// " WHEN NO_DATA_FOUND THEN\n" +
+// " DBMS_OUTPUT.PUT_LINE('Employee not found.');\n" +
+// " WHEN TOO_MANY_ROWS THEN\n" +
+// " DBMS_OUTPUT.PUT_LINE('Multiple employees found.');\n" +
+// " WHEN OTHERS THEN\n" +
+// " DBMS_OUTPUT.PUT_LINE('An error occurred: ' || SQLERRM);\n" +
+// " END update_salary;\n" +
+// " /";
+ String sql = "CREATE OR REPLACE FUNCTION string_length (\n" +
+ " input_string VARCHAR2\n" +
+ ") RETURN NUMBER IS\n" +
+ "BEGIN\n" +
+ " RETURN LENGTH(input_string);\n" +
+ "END;\n" +
+ "/";
OracleLexer lexer = new OracleLexer(sql);
lexer.printTokens();
OracleParser parser = new OracleParser(lexer);
diff --git a/sqlTranslate/src/main/java/Parser/AST/AlterTable/AlterAddColumnNode.java b/sqlTranslate/src/main/java/Parser/AST/AlterTable/AlterAddColumnNode.java
index 0eb23739e..ccd44a30b 100644
--- a/sqlTranslate/src/main/java/Parser/AST/AlterTable/AlterAddColumnNode.java
+++ b/sqlTranslate/src/main/java/Parser/AST/AlterTable/AlterAddColumnNode.java
@@ -1,13 +1,13 @@
package Parser.AST.AlterTable;
-import Interface.ColumnType;
+import Interface.DataType;
import Lexer.Token;
import Parser.AST.ASTNode;
import java.util.ArrayList;
import java.util.List;
-public class AlterAddColumnNode extends ASTNode implements ColumnType {
+public class AlterAddColumnNode extends ASTNode implements DataType {
private Token name;
private Token type;
private List constraint;
diff --git a/sqlTranslate/src/main/java/Parser/AST/AlterTable/AlterModifyColumnNode.java b/sqlTranslate/src/main/java/Parser/AST/AlterTable/AlterModifyColumnNode.java
index 495b174d9..2ff319ba1 100644
--- a/sqlTranslate/src/main/java/Parser/AST/AlterTable/AlterModifyColumnNode.java
+++ b/sqlTranslate/src/main/java/Parser/AST/AlterTable/AlterModifyColumnNode.java
@@ -1,13 +1,13 @@
package Parser.AST.AlterTable;
-import Interface.ColumnType;
+import Interface.DataType;
import Lexer.Token;
import Parser.AST.ASTNode;
import java.util.ArrayList;
import java.util.List;
-public class AlterModifyColumnNode extends ASTNode implements ColumnType {
+public class AlterModifyColumnNode extends ASTNode implements DataType {
private Token name;
private Token type;
diff --git a/sqlTranslate/src/main/java/Parser/AST/CreateTable/ColumnNode.java b/sqlTranslate/src/main/java/Parser/AST/CreateTable/ColumnNode.java
index bd6a1e346..1bd8ad177 100644
--- a/sqlTranslate/src/main/java/Parser/AST/CreateTable/ColumnNode.java
+++ b/sqlTranslate/src/main/java/Parser/AST/CreateTable/ColumnNode.java
@@ -1,13 +1,13 @@
package Parser.AST.CreateTable;
-import Interface.ColumnType;
+import Interface.DataType;
import Lexer.Token;
import Parser.AST.ASTNode;
import java.util.ArrayList;
import java.util.List;
-public class ColumnNode extends ASTNode implements ColumnType {
+public class ColumnNode extends ASTNode implements DataType {
private Token name;
private Token type;
private List constraint;
diff --git a/sqlTranslate/src/main/java/Parser/AST/Function/FunctionColumnNode.java b/sqlTranslate/src/main/java/Parser/AST/Function/FunctionColumnNode.java
index b00eaca4b..0cefba2bc 100644
--- a/sqlTranslate/src/main/java/Parser/AST/Function/FunctionColumnNode.java
+++ b/sqlTranslate/src/main/java/Parser/AST/Function/FunctionColumnNode.java
@@ -1,14 +1,13 @@
package Parser.AST.Function;
-import Interface.ColumnType;
+import Interface.DataType;
import Lexer.Token;
import Parser.AST.ASTNode;
-import Parser.AST.Procedure.ProcedureColumnNode;
import java.util.ArrayList;
import java.util.List;
-public class FunctionColumnNode extends ASTNode implements ColumnType {
+public class FunctionColumnNode extends ASTNode implements DataType {
private Token name;
private Token type;
private List constraint;
@@ -16,6 +15,7 @@ public class FunctionColumnNode extends ASTNode implements ColumnType {
public FunctionColumnNode() {
super();
setTokens(new ArrayList<>());
+ setInOut(new ArrayList<>());
}
public FunctionColumnNode(ASTNode node) {
diff --git a/sqlTranslate/src/main/java/Parser/AST/Function/FunctionNameNode.java b/sqlTranslate/src/main/java/Parser/AST/Function/FunctionNameNode.java
index e7fd6e639..f5defc464 100644
--- a/sqlTranslate/src/main/java/Parser/AST/Function/FunctionNameNode.java
+++ b/sqlTranslate/src/main/java/Parser/AST/Function/FunctionNameNode.java
@@ -22,7 +22,7 @@ public class FunctionNameNode extends ASTNode {
@Override
public void visit(ASTNode node, StringBuilder queryString) {
- queryString.append(toString() + " ");
+ queryString.append(toString() + " ( ");
for (ASTNode child : node.getChildren()) {
child.visit(child, queryString);
}
diff --git a/sqlTranslate/src/main/java/Parser/AST/Function/FunctionRetDefNode.java b/sqlTranslate/src/main/java/Parser/AST/Function/FunctionRetDefNode.java
index 6d33b6a01..dd0b294a5 100644
--- a/sqlTranslate/src/main/java/Parser/AST/Function/FunctionRetDefNode.java
+++ b/sqlTranslate/src/main/java/Parser/AST/Function/FunctionRetDefNode.java
@@ -1,12 +1,14 @@
package Parser.AST.Function;
+import Interface.DataType;
import Lexer.Token;
import Parser.AST.ASTNode;
import java.util.ArrayList;
import java.util.List;
-public class FunctionRetDefNode extends ASTNode {
+public class FunctionRetDefNode extends ASTNode implements DataType {
+ private Token type;
public FunctionRetDefNode() {
super();
setTokens(new ArrayList<>());
@@ -22,9 +24,28 @@ public class FunctionRetDefNode extends ASTNode {
@Override
public void visit(ASTNode node, StringBuilder queryString) {
- queryString.append(toString() + " ");
+ queryString.append(") " + toString() + " ");
for (ASTNode child : node.getChildren()) {
child.visit(child, queryString);
}
}
+
+ @Override
+ public Token getType() {
+ return type;
+ }
+
+ @Override
+ public void setType(Token type) {
+ this.type = type;
+ }
+
+ @Override
+ public void ResetTokensbyNameTypeConstraint() {
+ List tokens = new ArrayList<>();
+ tokens.add(new Token(Token.TokenType.KEYWORD, "RETURN"));
+ tokens.add(type);
+ tokens.add(new Token(Token.TokenType.KEYWORD, "IS"));
+ setTokens(tokens);
+ }
}
diff --git a/sqlTranslate/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java b/sqlTranslate/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java
index e158fe8a1..38a1b5aad 100644
--- a/sqlTranslate/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java
+++ b/sqlTranslate/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java
@@ -1,14 +1,13 @@
package Parser.AST.Procedure;
-import Interface.ColumnType;
+import Interface.DataType;
import Lexer.Token;
import Parser.AST.ASTNode;
-import Parser.AST.CreateTable.CRTEndNode;
import java.util.ArrayList;
import java.util.List;
-public class ProcedureColumnNode extends ASTNode implements ColumnType {
+public class ProcedureColumnNode extends ASTNode implements DataType {
private Token name;
private Token type;
private List constraint;
diff --git a/sqlTranslate/src/main/java/Parser/OracleParser.java b/sqlTranslate/src/main/java/Parser/OracleParser.java
index 4677e7980..c71d21eff 100644
--- a/sqlTranslate/src/main/java/Parser/OracleParser.java
+++ b/sqlTranslate/src/main/java/Parser/OracleParser.java
@@ -19,6 +19,7 @@ import Parser.AST.Drop.DropObjNameNode;
import Parser.AST.Drop.DropNode;
import Parser.AST.Drop.DropOptionNode;
import Parser.AST.Exception.*;
+import Parser.AST.Function.*;
import Parser.AST.IFELSIF.*;
import Parser.AST.Insert.InsertDataNode;
import Parser.AST.Insert.InsertEndNode;
@@ -80,6 +81,12 @@ public class OracleParser {
)
{
return parseProcedure(lexer.getTokens());
+ } else if (
+ (lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("FUNCTION"))
+ || (lexer.getTokens().get(0).getValue().equalsIgnoreCase("CREATE") && lexer.getTokens().get(1).getValue().equalsIgnoreCase("OR") && lexer.getTokens().get(2).getValue().equalsIgnoreCase("REPLACE") && lexer.getTokens().get(3).getValue().equalsIgnoreCase("FUNCTION"))
+ )
+ {
+ return parseFunction(lexer.getTokens());
}
else {
try {
@@ -1859,7 +1866,8 @@ public class OracleParser {
childNode = new ProcedureEndNode();
for (int j = index; j < parseTokens.size(); j++) {
childNode.addToken(parseTokens.get(j));
- if (parseTokens.get(j).hasType(Token.TokenType.EOF)) {
+ if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
+ i = j;
break;
}
}
@@ -1872,7 +1880,8 @@ public class OracleParser {
ASTNode childNode = new ProcedureEndNode();
for (int j = i; j < parseTokens.size(); j++) {
childNode.addToken(parseTokens.get(j));
- if (parseTokens.get(j).hasType(Token.TokenType.EOF)) {
+ if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
+ i = j;
break;
}
}
@@ -1897,4 +1906,240 @@ public class OracleParser {
return root;
}
+ /**
+ * Create FUNCTION
+ * Grammar: CREATE OR REPLACE FUNCTION function_name (
+ * parameter1 [IN | OUT] datatype1 ,
+ * parameter2 [IN | OUT] datatype2 ,
+ * ...
+ * ) RETURN return_datatype IS
+ * BEGIN
+ * -- function body
+ * RETURN result;
+ * END;
+ * /
+ * Example: CREATE OR REPLACE FUNCTION string_length (
+ * input_string VARCHAR2
+ * ) RETURN NUMBER IS
+ * BEGIN
+ * RETURN LENGTH(input_string);
+ * END;
+ * /
+ */
+ private ASTNode parseFunction(List parseTokens) {
+ ASTNode root = new FunctionNode();
+ ASTNode currentNode = root;
+ for (int i = 0; i < parseTokens.size(); i++) {
+ // CREATE [OR REPLACE] FUNCTION
+ if (root.getTokens().isEmpty()) {
+ for (int j = i; j < parseTokens.size(); j++) {
+ root.addToken(parseTokens.get(j));
+ if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("FUNCTION")) {
+ i = j;
+ break;
+ }
+ }
+ }
+ // match function name
+ else if (currentNode == root && parseTokens.get(i).hasType(Token.TokenType.IDENTIFIER)) {
+ ASTNode childNode = new FunctionNameNode();
+ childNode.addToken(parseTokens.get(i));
+ currentNode.addChild(childNode);
+ currentNode = childNode;
+ i++;
+ }
+ // match parameters
+ else if (currentNode instanceof FunctionNameNode && parseTokens.get(i).hasType(Token.TokenType.IDENTIFIER)) {
+ for (int ii = i; ii < parseTokens.size(); ii++) {
+ if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("RETURN")) {
+ i = ii - 1;
+ break;
+ }
+ List tokens = new ArrayList<>();
+ FunctionColumnNode child = new FunctionColumnNode();
+ child.setName(parseTokens.get(ii));
+ tokens.add(parseTokens.get(ii));
+ List constraint = new ArrayList<>();
+ boolean typeMatch = false;
+ int typeIdx = -1;
+ for (int j = ii + 1; j < parseTokens.size(); j++) {
+ if (!typeMatch && !(parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))))
+ {
+ child.setType(parseTokens.get(j));
+ typeMatch = true;
+ typeIdx = j;
+ }
+ if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))) {
+ child.addInOut(parseTokens.get(j));
+ }
+ // Check () or REFERENCES other_table(other_column)
+ if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) &&
+ (parseTokens.get(j).getValue().equalsIgnoreCase("REFERENCES")
+ || parseTokens.get(j).getValue().equalsIgnoreCase("CHECK"))) {
+ tokens.add(parseTokens.get(j));
+ if (!(parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))))
+ constraint.add(parseTokens.get(j));
+ Stack stack = new Stack<>();
+ for (int k = j + 1; k < parseTokens.size(); k++) {
+ tokens.add(parseTokens.get(k));
+ if (!(parseTokens.get(k).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(k).getValue().equalsIgnoreCase("IN") || parseTokens.get(k).getValue().equalsIgnoreCase("OUT"))))
+ constraint.add(parseTokens.get(k));
+ if (parseTokens.get(k).getValue().equals("(")) {
+ stack.push("(");
+ for (int t = k + 1; t < parseTokens.size(); t++) {
+ tokens.add(parseTokens.get(t));
+ if (!(parseTokens.get(t).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(t).getValue().equalsIgnoreCase("IN") || parseTokens.get(t).getValue().equalsIgnoreCase("OUT"))))
+ constraint.add(parseTokens.get(t));
+ if (parseTokens.get(t).getValue().equals("(")) {
+ stack.push("(");
+ } else if (parseTokens.get(t).getValue().equals(")")) {
+ stack.pop();
+ if (stack.empty()) {
+ ii = t;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ if ((parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(",")) ||
+ (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(")"))) {
+ ii = j;
+ break;
+ }
+ tokens.add(parseTokens.get(j));
+ if (typeMatch && j != typeIdx) {
+ if (!(parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && (parseTokens.get(j).getValue().equalsIgnoreCase("IN") || parseTokens.get(j).getValue().equalsIgnoreCase("OUT"))))
+ constraint.add(parseTokens.get(j));
+ }
+ }
+ child.setTokens(tokens);
+ child.setConstraint(constraint);
+ currentNode.addChild(child);
+ currentNode = child;
+ }
+ }
+ // match return definition
+ else if (currentNode instanceof FunctionColumnNode && parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("RETURN")) {
+ FunctionRetDefNode childNode = new FunctionRetDefNode();
+ for (int j = i; j < parseTokens.size(); j++) {
+ if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("RETURN")) {
+ childNode.addToken(parseTokens.get(j));
+ }
+ else if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equals("IS")) {
+ childNode.addToken(parseTokens.get(j));
+ i = j;
+ break;
+ }
+ else {
+ childNode.addToken(parseTokens.get(j));
+ childNode.setType(parseTokens.get(j));
+ }
+ }
+ currentNode.addChild(childNode);
+ currentNode = childNode;
+ }
+ // match function begin
+ else if (currentNode instanceof FunctionRetDefNode && parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("BEGIN")) {
+ ASTNode childNode = new FunctionBeginNode();
+ childNode.addToken(parseTokens.get(i));
+ currentNode.addChild(childNode);
+ currentNode = childNode;
+ }
+ // match function body
+ else if (currentNode instanceof FunctionBeginNode) {
+ for (int ii = i; ii < parseTokens.size(); ii++) {
+ if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("END")) {
+ i = ii - 1;
+ break;
+ }
+ else if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("EXCEPTION")) {
+ i = ii - 1;
+ break;
+ }
+ else if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("IF")) {
+ int index = -1;
+ for (int j = ii; j < parseTokens.size(); j++) {
+ if (parseTokens.get(j).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j).getValue().equalsIgnoreCase("END")
+ && j + 1 < parseTokens.size() && parseTokens.get(j + 1).hasType(Token.TokenType.KEYWORD) && parseTokens.get(j + 1).getValue().equalsIgnoreCase("IF")
+ && j + 2 < parseTokens.size() && parseTokens.get(j + 2).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j + 2).getValue().equals(";") ) {
+ index = j + 2;
+ break;
+ }
+ }
+ if (index == -1) {
+ try {
+ throw new ParseFailedException("There exists syntax error and no END if block is found!");
+ } catch (ParseFailedException e) {
+ e.printStackTrace();
+ }
+ }
+ else {
+ ASTNode childNode = parseIFELSE(parseTokens.subList(ii, index + 1));
+ currentNode.addChild(childNode);
+ currentNode = childNode.getDeepestChild();
+ ii = index;
+ }
+ }
+ else if (parseTokens.get(ii).hasType(Token.TokenType.KEYWORD) && parseTokens.get(ii).getValue().equalsIgnoreCase("RETURN")) {
+ ASTNode childNode = new FunctionReturnNode();
+ for (int j = ii; j < parseTokens.size(); j++) {
+ childNode.addToken(parseTokens.get(j));
+ if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
+ ii = j;
+ break;
+ }
+ }
+ currentNode.addChild(childNode);
+ currentNode = childNode;
+ }
+ else {
+ ASTNode childNode = new FunctionBodyNode();
+ for (int j = ii; j < parseTokens.size(); j++) {
+ childNode.addToken(parseTokens.get(j));
+ if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
+ ii = j;
+ break;
+ }
+ }
+ currentNode.addChild(childNode);
+ currentNode = childNode;
+ }
+ }
+ }
+ // match function end
+ else if (parseTokens.get(i).hasType(Token.TokenType.KEYWORD) && parseTokens.get(i).getValue().equalsIgnoreCase("END")) {
+ ASTNode childNode = new FunctionEndNode();
+ for (int j = i; j < parseTokens.size(); j++) {
+ childNode.addToken(parseTokens.get(j));
+ if (parseTokens.get(j).hasType(Token.TokenType.SYMBOL) && parseTokens.get(j).getValue().equals(";")) {
+ i = j;
+ break;
+ }
+ }
+ currentNode.addChild(childNode);
+ currentNode = childNode;
+ break;
+ }
+ else if (parseTokens.get(i).hasType(Token.TokenType.EOF)) {
+ break;
+ }
+ else {
+ try {
+ throw new ParseFailedException("Failed to parse:" + parseTokens.get(i));
+ }
+ catch (ParseFailedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+
+ return root;
+ }
+
+
}