add function

This commit is contained in:
XudongXie 2024-09-17 23:36:18 +08:00
parent d61e9d8460
commit 6afc2b1085
13 changed files with 405 additions and 68 deletions

View File

@ -4,18 +4,20 @@
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add document of function">
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionBeginNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionBodyNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionColumnNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionEndNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionNameNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionRetDefNode.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionReturnNode.java" afterDir="false" />
<list default="true" id="d8d12963-4777-48e3-9669-309cf5e41d60" name="更改" comment="add ast classes of function">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Document/Function in Oracle" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Document/Function in Oracle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Generator/OpenGaussGenerator.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Generator/OpenGaussGenerator.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Interface/ColumnType.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Interface/DataType.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Lexer/OracleLexer.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Lexer/OracleLexer.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Main.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Main.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/AlterTable/AlterAddColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/AlterTable/AlterAddColumnNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/AlterTable/AlterModifyColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/AlterTable/AlterModifyColumnNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/CreateTable/ColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/CreateTable/ColumnNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionColumnNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionNameNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionNameNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionRetDefNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Function/FunctionRetDefNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/AST/Procedure/ProcedureColumnNode.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/Parser/OracleParser.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/Parser/OracleParser.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -113,13 +115,6 @@
<option name="presentableId" value="Default" />
<updated>1723106789329</updated>
</task>
<task id="LOCAL-00035" summary="revise">
<created>1726065430463</created>
<option name="number" value="00035" />
<option name="presentableId" value="LOCAL-00035" />
<option name="project" value="LOCAL" />
<updated>1726065430463</updated>
</task>
<task id="LOCAL-00036" summary="revise">
<created>1726066806993</created>
<option name="number" value="00036" />
@ -456,7 +451,14 @@
<option name="project" value="LOCAL" />
<updated>1726561299659</updated>
</task>
<option name="localTasksCounter" value="84" />
<task id="LOCAL-00084" summary="add ast classes of function">
<created>1726583392370</created>
<option name="number" value="00084" />
<option name="presentableId" value="LOCAL-00084" />
<option name="project" value="LOCAL" />
<updated>1726583392370</updated>
</task>
<option name="localTasksCounter" value="85" />
<servers />
</component>
<component name="Vcs.Log.Tabs.Properties">
@ -471,7 +473,6 @@
</option>
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="add alter table keywords" />
<MESSAGE value="add alter table parser" />
<MESSAGE value="add alter" />
<MESSAGE value="fix some bugs" />
@ -496,7 +497,8 @@
<MESSAGE value="add procedure" />
<MESSAGE value="add document of rollback, commot, execute" />
<MESSAGE value="add document of function" />
<option name="LAST_COMMIT_MESSAGE" value="add document of function" />
<MESSAGE value="add ast classes of function" />
<option name="LAST_COMMIT_MESSAGE" value="add ast classes of function" />
</component>
<component name="XDebuggerManager">
<watches-manager>

View File

@ -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<Token> 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<Token> 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"));

View File

@ -2,7 +2,7 @@ package Interface;
import Lexer.Token;
public interface ColumnType {
public interface DataType {
Token getType();
void setType(Token type);
void ResetTokensbyNameTypeConstraint();

View File

@ -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)) {

View File

@ -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);

View File

@ -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<Token> constraint;

View File

@ -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;

View File

@ -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<Token> constraint;

View File

@ -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<Token> 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) {

View File

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

View File

@ -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 <Token> tokens = new ArrayList<>();
tokens.add(new Token(Token.TokenType.KEYWORD, "RETURN"));
tokens.add(type);
tokens.add(new Token(Token.TokenType.KEYWORD, "IS"));
setTokens(tokens);
}
}

View File

@ -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<Token> constraint;

View File

@ -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<Token> 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<Token> tokens = new ArrayList<>();
FunctionColumnNode child = new FunctionColumnNode();
child.setName(parseTokens.get(ii));
tokens.add(parseTokens.get(ii));
List<Token> 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<String> 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;
}
}