/******************************************************************************* | |
* Copyright (c) 2011 Oracle. All rights reserved. | |
* This program and the accompanying materials are made available under the | |
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* Contributors: | |
* Mike Norman - June 10 2011, created DDL parser package | |
******************************************************************************/ | |
options { | |
STATIC = false; | |
SUPPORT_CLASS_VISIBILITY_PUBLIC = true; | |
ERROR_REPORTING = false; | |
JAVA_UNICODE_ESCAPE = true; | |
UNICODE_INPUT = true; | |
NODE_USES_PARSER = true; | |
TRACK_TOKENS = true; | |
VISITOR = true; | |
} | |
PARSER_BEGIN(DDLParser) | |
/******************************************************************************* | |
* Copyright (c) 2011 Oracle. All rights reserved. | |
* This program and the accompanying materials are made available under the | |
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* Contributors: | |
* Mike Norman - June 10 2011, created DDL parser package | |
******************************************************************************/ | |
package org.eclipse.persistence.tools.oracleddl.parser; | |
//javase imports | |
import java.io.InputStream; | |
import java.util.List; | |
//metadata imports | |
import org.eclipse.persistence.tools.oracleddl.metadata.BlobType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.CharType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.ClobType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.CompositeDatabaseType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.DatabaseType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.DecimalType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.DoubleType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.FieldType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.FloatType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.FunctionType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.IntervalDayToSecond; | |
import org.eclipse.persistence.tools.oracleddl.metadata.IntervalYearToMonth; | |
import org.eclipse.persistence.tools.oracleddl.metadata.LongType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.LongRawType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.NCharType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.NClobType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.NestedTableType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.NumericType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.NVarChar2Type; | |
import org.eclipse.persistence.tools.oracleddl.metadata.ObjectType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.PLSQLPackageType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.PLSQLType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.ProcedureType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.RawType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.RealType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.TableType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.URowIdType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.UnresolvedSizedType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.UnresolvedType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.VarCharType; | |
import org.eclipse.persistence.tools.oracleddl.metadata.VarChar2Type; | |
import org.eclipse.persistence.tools.oracleddl.metadata.VArrayType; | |
import org.eclipse.persistence.tools.oracleddl.util.DatabaseTypesRepository; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.BFILE_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.BINARY_INTEGER_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.BINARY_FLOAT_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.BINARY_DOUBLE_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.BOOLEAN_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.DATE_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.INTEGER_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.MLSLABEL_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.NATURAL_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.PLS_INTEGER_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.POSITIVE_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.ROWID_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.SIMPLE_INTEGER_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.SMALLINT_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.TIME_TYPE; | |
import static org.eclipse.persistence.tools.oracleddl.metadata.ScalarDatabaseTypeEnum.TIMESTAMP_TYPE; | |
public class DDLParser { | |
protected DatabaseTypesRepository typesRepository = new DatabaseTypesRepository(); | |
public DDLParser() { | |
super(); | |
} | |
public void setTypesRepository(DatabaseTypesRepository typesRepository) { | |
this.typesRepository = typesRepository; | |
} | |
} | |
PARSER_END(DDLParser) | |
// white-space | |
SKIP: { | |
" " | |
| "\t" | |
| "\n" | |
| "\r" | |
| "\f" | |
} | |
// comments | |
SKIP: { | |
<COMMENT_LINE: "--" (~["\n","\r"])* ("\n"|"\r"|"\r\n") > | |
} | |
SKIP:{ | |
<COMMENT_BLOCK: "/*" (~["*"])* "*" ("*" | (~["*","/"] (~["*"])* "*"))* "/"> | |
} | |
// PLSQL reserved keywords (prefix with K_ to avoid naming conflicts) - NB: incomplete list | |
TOKEN: { | |
<K_A: "A"> | |
| <K_ADD: "ADD"> | |
| <K_ALTER: "ALTER"> | |
| <K_ARRAY: "ARRAY"> | |
| <K_AS: "AS"> | |
| <K_AUTHID: "AUTHID"> | |
| <K_AUTOMATIC: "AUTOMATIC"> | |
| <K_AUTONOMOUS_TRANSACTION: "AUTONOMOUS_TRANSACTION"> | |
| <K_BEGIN: "BEGIN"> | |
| <K_BFILE: "BFILE"> | |
| <K_BINARY_DOUBLE: "BINARY_DOUBLE"> | |
| <K_BINARY_FLOAT: "BINARY_FLOAT"> | |
| <K_BINARY_INTEGER: "BINARY_INTEGER"> | |
| <K_BLOB: "BLOB"> | |
| <K_BODY: "BODY"> | |
| <K_BOOLEAN: "BOOLEAN"> | |
| <K_BUILTIN: "BUILTIN"> | |
| <K_BULK: "BULK"> | |
| <K_BY: "BY"> | |
| <K_BYTE: "BYTE"> | |
| <K_CHAR: "CHAR"> | |
| <K_CHARACTER: "CHARACTER"> | |
| <K_CHARSET: "%CHARSET"> | |
| <K_CLOB: "CLOB"> | |
| <K_CLOSE: "CLOSE"> | |
| <K_COLLECT: "COLLECT"> | |
| <K_COMMIT: "COMMIT"> | |
| <K_CONSTANT: "CONSTANT"> | |
| <K_CONSTRAINT: "CONSTRAINT"> | |
| <K_COUNT: "COUNT"> | |
| <K_CREATE: "CREATE"> | |
| <K_CROSS: "CROSS"> | |
| <K_CUBE: "CUBE"> | |
| <K_CURRENT_OF: "CURRENT_OF"> | |
| <K_CURRENT_USER: "CURRENT_USER"> | |
| <K_CURSOR: "CURSOR"> | |
| <K_DATE: "DATE"> | |
| <K_DAY: "DAY"> | |
| <K_DBTIMEZONE: "DBTIMEZONE"> | |
| <K_DEC: "DEC"> | |
| <K_DECIMAL: "DECIMAL"> | |
| <K_DECREMENT: "DECREMENT"> | |
| <K_DEFAULT: "DEFAULT"> | |
| <K_DEFINER: "DEFINER"> | |
| <K_DELETE: "DELETE"> | |
| <K_DETERMINISTIC: "DETERMINISTIC"> | |
| <K_DIMENSION: "DIMENSION"> | |
| <K_DOUBLE: "DOUBLE"> | |
| <K_ELSIF: "ELSIF"> | |
| <K_EMPTY: "EMPTY"> | |
| <K_ENABLE: "ENABLE"> | |
| <K_END: "END"> | |
| <K_EQUALS_PATH: "EQUALS_PATH"> | |
| <K_ESCAPE: "ESCAPE"> | |
| <K_EXCEPTION: "EXCEPTION"> | |
| <K_EXCEPTION_INIT: "EXCEPTION_INIT"> | |
| <K_EXIT: "EXIT"> | |
| <K_FALSE: "FALSE"> | |
| <K_FIPSFLAG: "FIPSFLAG"> | |
| <K_FIRST: "FIRST"> | |
| <K_FLOAT: "FLOAT"> | |
| <K_FULL: "FULL"> | |
| <K_FUNCTION: "FUNCTION"> | |
| <K_GLOBAL: "GLOBAL"> | |
| <K_GROUPING: "GROUPING"> | |
| <K_IGNORE: "IGNORE"> | |
| <K_IN: "IN"> | |
| <K_INCREMENT: "INCREMENT"> | |
| <K_INDEX: "INDEX"> | |
| <K_INFINITE: "INFINITE"> | |
| <K_INLINE: "INLINE"> | |
| <K_INNER: "INNER"> | |
| <K_INT: "INT"> | |
| <K_INTEGER: "INTEGER"> | |
| <K_INTERFACE: "INTERFACE"> | |
| <K_INTERVAL: "INTERVAL"> | |
| <K_IS: "IS"> | |
| <K_ITERATE: "ITERATE"> | |
| <K_JOIN: "JOIN"> | |
| <K_KEY: "KEY"> | |
| <K_KEEP: "KEEP"> | |
| <K_LAST: "LAST"> | |
| <K_LEFT: "LEFT"> | |
| <K_LIKE2: "LIKE2"> | |
| <K_LIKE4: "LIKE4"> | |
| <K_LIKEC: "LIKEC"> | |
| <K_LOCAL: "LOCAL"> | |
| <K_LONG: "LONG"> | |
| <K_LOOP: "LOOP"> | |
| <K_MAIN: "MAIN"> | |
| <K_MEASURES: "MEASURES"> | |
| <K_MEMBER: "MEMBER"> | |
| <K_MLSLABEL: "MLSLABEL"> | |
| <K_MODEL: "MODEL"> | |
| <K_MONTH: "MONTH"> | |
| <K_NAN: "NAN"> | |
| <K_NATIONAL: "NATIONAL"> | |
| <K_NATURAL: "NATURAL"> | |
| <K_NAV: "NAV"> | |
| <K_NCHAR: "NCHAR"> | |
| <K_NCLOB: "NCLOB"> | |
| <K_NEW_NAMES: "NEW_NAMES"> | |
| <K_NO: "'NO'"> | |
| <K_NOCOMPRESS: "NOCOMPRESS"> | |
| <K_NOCOPY: "NOCOPY"> | |
| <K_NOCYCLE: "NOCYCLE"> | |
| <K_NOT: "NOT"> | |
| <K_NULL: "NULL"> | |
| <K_NULLS: "NULLS"> | |
| <K_NUMBER: "NUMBER"> | |
| <K_NUMERIC: "NUMERIC"> | |
| <K_NVARCHAR2: "NVARCHAR2"> | |
| <K_NVARCHAR: "NVARCHAR"> | |
| <K_OBJECT: "OBJECT"> | |
| <K_OF: "OF"> | |
| <K_ON: "ON"> | |
| <K_ONLY: "ONLY"> | |
| <K_OPEN: "OPEN"> | |
| <K_OR: "OR"> | |
| <K_ORGANIZATION: "ORGANIZATION"> | |
| <K_OUT: "OUT"> | |
| <K_OUTER: "OUTER"> | |
| <K_OVERFLOW: "OVERFLOW"> | |
| <K_PACKAGE: "PACKAGE"> | |
| <K_PARALLEL_ENABLE: "PARALLEL_ENABLE"> | |
| <K_PARTITION: "PARTITION"> | |
| <K_PIPELINED: "PIPELINED"> | |
| <K_PLS_INTEGER: "PLS_INTEGER"> | |
| <K_POSITIVE: "POSITIVE"> | |
| <K_PRAGMA: "PRAGMA"> | |
| <K_PRECISION: "PRECISION"> | |
| <K_PRESENT: "PRESENT"> | |
| <K_PRESERVE: "PRESERVE"> | |
| <K_PRIMARY: "PRIMARY"> | |
| <K_PROCEDURE: "PROCEDURE"> | |
| <K_RAISE: "RAISE"> | |
| <K_RANGE: "RANGE"> | |
| <K_RAW: "RAW"> | |
| <K_READ: "READ"> | |
| <K_REAL: "REAL"> | |
| <K_RECORD: "RECORD"> | |
| <K_REF: "REF"> | |
| <K_REFERENCE: "REFERENCE"> | |
| <K_REGEXP_LIKE: "REGEXP_LIKE"> | |
| <K_REPLACE: "REPLACE"> | |
| <K_RESTRICT_REFERENCES: "RESTRICT_REFERENCES"> | |
| <K_RESULT_CACHE: "RESULT_CACHE"> | |
| <K_RETURN: "RETURN"> | |
| <K_RETURNING: "RETURNING"> | |
| <K_REVERSE: "REVERSE"> | |
| <K_RIGHT: "RIGHT"> | |
| <K_RNDS: "RNDS"> | |
| <K_RNPS: "RNPS"> | |
| <K_ROLLBACK: "ROLLBACK"> | |
| <K_ROLLUP: "ROLLUP"> | |
| <K_ROWID: "ROWID"> | |
| <K_ROWS: "ROWS"> | |
| <K_ROWTYPE: "%ROWTYPE"> | |
| <K_RULES: "RULES"> | |
| <K_SECOND: "SECOND"> | |
| <K_SEQUENTIAL: "SEQUENTIAL"> | |
| <K_SERIALLY_REUSABLE: "SERIALLY_REUSABLE"> | |
| <K_SESSIONTIMEZONE: "SESSIONTIMEZONE"> | |
| <K_SET: "SET"> | |
| <K_SETS: "SETS"> | |
| <K_SIBLINGS: "SIBLINGS"> | |
| <K_SINGLE: "SINGLE"> | |
| <K_SIMPLE_INTEGER: "SIMPLE_INTEGER"> | |
| <K_SMALLINT: "SMALLINT"> | |
| <K_SOME: "SOME"> | |
| <K_STRING: "STRING"> | |
| <K_SUBMUlookISET: "SUBMUlookISET"> | |
| <K_SUBTYPE: "SUBTYPE"> | |
| <K_TABLE: "TABLE"> | |
| <K_TEMPORARY: "TEMPORARY"> | |
| <K_THE: "THE"> | |
| <K_TIME: "TIME"> | |
| <K_TIMESTAMP: "TIMESTAMP"> | |
| <K_TO: "TO"> | |
| <K_TRANSACTION: "TRANSACTION"> | |
| <K_TRUE: "TRUE"> | |
| <K_TRUST: "TRUST"> | |
| <K_TYPE: "TYPE"> | |
| <K_TYPE2: "%TYPE"> | |
| <K_UNDER_PATH: "UNDER_PATH"> | |
| <K_UNTIL: "UNTIL"> | |
| <K_UPDATED: "UPDATED"> | |
| <K_UPSERT: "UPSERT"> | |
| <K_UROWID: "UROWID"> | |
| <K_USING: "USING"> | |
| <K_VARCHAR2: "VARCHAR2"> | |
| <K_VARCHAR: "VARCHAR"> | |
| <K_VARRAY: "VARRAY"> | |
| <K_VARYING: "VARYING"> | |
| <K_WITH: "WITH"> | |
| <K_WHILE: "WHILE"> | |
| <K_WNDS: "WNDS"> | |
| <K_WNPS: "WNPS"> | |
| <K_WORK: "WORK"> | |
| <K_YEAR: "YEAR"> | |
| <K_YES: "'YES'"> | |
| <K_ZONE: "ZONE"> | |
} | |
// separators and operators (prefix with O_ to avoid naming conflicts) | |
TOKEN: { | |
<O_ASSIGN: ":="> | |
| <O_ASTERISK: "*"> | |
| <O_ATSIGN: "@"> | |
| <O_CLOSEPAREN: ")"> | |
| <O_CONCAT: "||"> | |
| <O_COLON: ":"> | |
| <O_COMMA: ","> | |
| <O_DOT: "."> | |
| <O_DOUBLEDOT: ".."> | |
| <O_DOLLAR: "$"> | |
| <O_PERCENT: "%"> | |
| <O_EQUAL: "="> | |
| <O_GREATER: ">"> | |
| <O_GREATEREQUAL: ">="> | |
| <O_JOINPLUS: "(+)"> | |
| <O_LESS: "<"> | |
| <O_LESSEQUAL: "<="> | |
| <O_MINUS: "-"> | |
| <O_NOTEQUAL2: "<>"> | |
| <O_NOTEQUAL: "!="> | |
| <O_OPENPAREN: "("> | |
| <O_PLUS: "+"> | |
| <O_POUND: "#"> | |
| <O_QUESTIONMARK: "?"> | |
| <O_SEMICOLON: ";"> | |
| <O_SLASH: "/"> | |
| <O_TILDE: "~"> | |
} | |
// numeric literals | |
TOKEN : { | |
<S_NUMBER: <FLOAT> | |
| <FLOAT> ( ["e","E"] ([ "-","+"])? <FLOAT> )? | |
> | |
| <#FLOAT: <INTEGER> | |
| <INTEGER> ( "." <INTEGER> )? | |
| "." <INTEGER> | |
> | |
| <#INTEGER: ( <DIGIT> )+ > | |
| <#DIGIT: ["0" - "9"] > | |
} | |
// identifiers | |
TOKEN: | |
{ | |
<S_IDENTIFIER: (<LETTER>)+ (<DIGIT> | <LETTER> | <SPECIAL_CHARS>)* > | |
| <#LETTER: ["a"-"z", "A"-"Z"] > | |
| <#SPECIAL_CHARS: "$" | "_" | "#" | "@" > | |
| <S_BIND: ":" ( <S_NUMBER> | <S_IDENTIFIER> ("." <S_IDENTIFIER>)?) > | |
| <S_CHAR_LITERAL: "'" (~["'"])* "'" ("'" (~["'"])* "'")*> | |
| <S_QUOTED_IDENTIFIER: "\"" (~["\n","\r","\""])* "\"" > | |
} | |
// stripped-down version of PLSQL grammar: only parses package/top-level DDL specifications | |
// PLSQLPackage at 'top-level' | |
PLSQLPackageType parsePLSQLPackage(): | |
{String schema = null; | |
String packageName = null; | |
PLSQLPackageType packageType = new PLSQLPackageType();} | |
{ | |
<K_CREATE> [ <K_OR> <K_REPLACE> ] <K_PACKAGE> | |
[LOOKAHEAD(2) schema=OracleObjectName() <O_DOT> ] packageName=OracleObjectName() | |
{ | |
if (schema != null) { | |
packageType.setPackageName(schema + "." + packageName); | |
} | |
else { | |
packageType.setPackageName(packageName); | |
} | |
} | |
[ <K_AUTHID> [ <K_CURRENT_USER> | <K_DEFINER> ] ] | |
[ <K_AS> | <K_IS> ] | |
( packageDeclaration(packageType) )* | |
<K_END> [ OracleObjectName() ] <O_SEMICOLON> | |
<EOF> | |
{ | |
typesRepository.setDatabaseType(packageName, packageType); | |
return packageType; | |
} | |
} | |
// procedure at 'top-level' | |
ProcedureType parseTopLevelProcedure(): | |
{ProcedureType procedureType = null; | |
String schema = null; | |
String procedureName = null;} | |
{ | |
<K_CREATE> [ <K_OR> <K_REPLACE> ] <K_PROCEDURE> | |
[LOOKAHEAD(2) schema=OracleObjectName() <O_DOT> ] procedureName=OracleObjectName() | |
[ <O_OPENPAREN> argumentList() <O_CLOSEPAREN> ] [ <K_AS> | <K_IS> ] | |
skipToEnd() | |
{ | |
procedureType = new ProcedureType(procedureName); | |
if (schema != null) { | |
procedureType.setSchema(schema); | |
} | |
typesRepository.setDatabaseType(procedureName, procedureType); | |
return procedureType; | |
} | |
} | |
// function at 'top-level' | |
FunctionType parseTopLevelFunction(): | |
{FunctionType functionType = null; | |
String schema = null; | |
String functionName = null;} | |
{ | |
<K_CREATE> [ <K_OR> <K_REPLACE> ] <K_FUNCTION> | |
[LOOKAHEAD(2) schema=OracleObjectName() <O_DOT> ] functionName=OracleObjectName() | |
[ <O_OPENPAREN> argumentList() <O_CLOSEPAREN> ] functionReturnSpec() [ <K_AS> | <K_IS> ] | |
skipToEnd() | |
{ | |
functionType = new FunctionType(functionName); | |
if (schema != null) { | |
functionType.setSchema(schema); | |
} | |
//TODO - figure out returnType | |
typesRepository.setDatabaseType(functionName, functionType); | |
return functionType; | |
} | |
} | |
// table at 'top-level' | |
TableType parseTable(): | |
{ | |
TableType tableType = null; | |
String schema = null; | |
String tableName = null; | |
Token iot = null; | |
} | |
{ | |
<K_CREATE> [ <K_GLOBAL> <K_TEMPORARY> ] <K_TABLE> | |
[LOOKAHEAD(2) schema=OracleObjectName() <O_DOT> ] tableName=OracleObjectName() | |
{ | |
tableType = new TableType(tableName); | |
if (schema != null) { | |
tableType.setSchema(schema); | |
} } | |
<O_OPENPAREN> columnDeclarations(tableType) <O_CLOSEPAREN> | |
[ <K_ORGANIZATION> ] [ iot=<K_INDEX> ] [ <K_NOCOMPRESS> ] [ <K_OVERFLOW> ] | |
[ <K_ON> <K_COMMIT > [<K_DELETE> | <K_PRESERVE> ] <K_ROWS> ] <O_SEMICOLON> | |
<EOF> | |
{ | |
if (iot != null) { | |
tableType.setIOT(true); | |
} | |
typesRepository.setDatabaseType(tableName, tableType); | |
return tableType; | |
} | |
} | |
// type at 'top-level' | |
CompositeDatabaseType parseType(): | |
{CompositeDatabaseType databaseType = null; | |
String schema = null; | |
String typeName = null; | |
boolean varray = false; | |
boolean nestedTable = false; | |
} | |
{ | |
<K_CREATE> [ <K_OR> <K_REPLACE> ] <K_TYPE> | |
[LOOKAHEAD(2) schema=OracleObjectName() <O_DOT> ] typeName=OracleObjectName() <K_AS> | |
[ <K_OBJECT> <O_OPENPAREN> | |
{ | |
databaseType = new ObjectType(typeName); | |
if (schema != null) { | |
((ObjectType)databaseType).setSchema(schema); } | |
} columnDeclarations(databaseType) <O_CLOSEPAREN> | |
| <K_VARRAY> <O_OPENPAREN> <S_NUMBER> <O_CLOSEPAREN> <K_OF> | |
{ databaseType = new VArrayType(typeName); | |
if (schema != null) { | |
((VArrayType)databaseType).setSchema(schema); | |
} | |
} columnTypeSpec(databaseType) | |
| <K_TABLE> <K_OF> { | |
databaseType = new NestedTableType(typeName); | |
if (schema != null) { | |
((NestedTableType)databaseType).setSchema(schema); | |
} } columnTypeSpec(databaseType) | |
] | |
[ <O_SEMICOLON> ] | |
<EOF> | |
{ typesRepository.setDatabaseType(typeName, databaseType); | |
return databaseType; | |
} | |
} | |
void columnDeclarations(CompositeDatabaseType enclosingType) #void: | |
{} | |
{ | |
columnDeclaration(enclosingType) [ <O_COMMA> columnDeclarations(enclosingType) ] | |
} | |
void columnDeclaration(CompositeDatabaseType enclosingType) #void: | |
{String s = null; | |
String pk = null; | |
boolean notNull = false; | |
DatabaseType columnType = null; | |
FieldType column = null; | |
} | |
{ | |
( LOOKAHEAD(2) s=OracleObjectName() | |
{ | |
column = new FieldType(s); | |
if (enclosingType != null) { | |
enclosingType.addCompositeType(column); | |
} } | |
columnType=columnTypeSpec(enclosingType) [ <K_NOT> <K_NULL> <K_ENABLE> {notNull = true;} ] | |
| LOOKAHEAD(2) | |
[ <K_CONSTRAINT> ] [ OracleObjectName() ] <K_PRIMARY> <K_KEY> | |
<O_OPENPAREN> pkList((TableType)enclosingType) <O_CLOSEPAREN> <K_ENABLE> | |
) | |
{ | |
if (column != null) { | |
column.setDataType(columnType); | |
if (notNull) { | |
column.setNotNull(); | |
} | |
} | |
} | |
} | |
DatabaseType columnTypeSpec(CompositeDatabaseType enclosingType): | |
{String s = null; | |
Token t = null; | |
DatabaseType dt = null;} | |
{ | |
( | |
dt=datatype() | |
| s=columnSpec() [ <O_OPENPAREN> t=<S_NUMBER> <O_CLOSEPAREN> ] | |
) | |
{ | |
if (s != null) { | |
if (t != null) { | |
Long size = Long.decode(t.image); | |
dt = new UnresolvedSizedType(s, size); | |
} | |
else { | |
dt = new UnresolvedType(s); | |
} | |
} | |
return dt; | |
} | |
} | |
void pkList(TableType tableType) #void: | |
{} | |
{ | |
pk(tableType) ( <O_COMMA> pk(tableType) )* | |
} | |
void pk(TableType tableType) #void: | |
{ | |
String s = null; | |
} | |
{ | |
s=OracleObjectName() | |
{ | |
List<FieldType> columns = tableType.getColumns(); | |
for (FieldType column : columns) { | |
if (column.getFieldName().equals(s)) { | |
column.setPk(); | |
break; | |
} | |
} } | |
} | |
void packageDeclaration(PLSQLPackageType packageType) #void: | |
{} | |
{ | |
LOOKAHEAD(2) variableDeclaration(packageType) | |
| typeDeclaration(packageType) | |
| cursorDeclaration(packageType) | |
| procedureSpec(packageType) | |
| functionSpec(packageType) | |
| exceptionDeclaration(packageType) | |
| pragmaDeclaration(packageType) | |
} | |
void variableDeclaration(PLSQLPackageType packageType): | |
{} | |
{ | |
<S_IDENTIFIER> [ <K_CONSTANT> ] typeSpec() [ <K_NOT> <K_NULL> ] | |
[ variableDefaultAssignment() ] | |
<O_SEMICOLON> } | |
void variableDefaultAssignment() #void: | |
{} | |
{ | |
( <O_ASSIGN> | <K_DEFAULT> ) skipToSemiColon() | |
} | |
DatabaseType datatype(): | |
{Token t = null; | |
DatabaseType dt = null; | |
Token precision = null; | |
Long sl; | |
Long pl; | |
Token scale = null;} | |
{ | |
<K_BINARY_INTEGER> { return BINARY_INTEGER_TYPE;} | |
| <K_BINARY_FLOAT> { return BINARY_FLOAT_TYPE;} | |
| <K_BINARY_DOUBLE> { return BINARY_DOUBLE_TYPE;} | |
| <K_NATURAL> { return NATURAL_TYPE;} | |
| <K_POSITIVE> { return POSITIVE_TYPE;} | |
| ( t=<K_NUMBER> | |
| t=<K_NUMERIC> | |
| t=<K_DECIMAL> | |
| t=<K_DEC> | |
) [ <O_OPENPAREN> [ precision=<O_ASTERISK > | precision=<S_NUMBER> ] ( <O_COMMA> scale=<S_NUMBER> )* <O_CLOSEPAREN> ] | |
{ | |
if (t.kind == K_NUMBER || t.kind == K_NUMERIC) { | |
if (precision != null && precision.image.equals("*")) { | |
precision = null; } | |
if (precision == null) { | |
if (scale != null && scale.image.equals("0")) { | |
dt = INTEGER_TYPE; } else { | |
dt = new NumericType(); } | |
} | |
else { | |
pl = Long.decode(precision.image); | |
if (scale == null) { | |
dt = new NumericType(pl); | |
} | |
else { | |
sl = Long.decode(scale.image); | |
dt = new NumericType(pl, sl); | |
} | |
} | |
} | |
else if (t.kind == K_DECIMAL || t.kind == K_DEC) { | |
if (precision != null && precision.image.equals("*")) { | |
precision = null; | |
} | |
if (precision == null) { | |
dt = new DecimalType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
if (scale == null) { | |
dt = new DecimalType(pl); | |
} | |
else { | |
sl = Long.decode(scale.image); | |
dt = new DecimalType(pl, sl); | |
} | |
} | |
} return dt; } | |
| <K_LONG> [ t=<K_RAW> ] [ <O_OPENPAREN> precision=<S_NUMBER> <O_CLOSEPAREN> ] { | |
if (t == null) { | |
if (precision == null) { | |
dt = new LongType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
dt = new LongType(pl); | |
} | |
} | |
else { | |
if (precision == null) { | |
dt = new LongRawType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
dt = new LongRawType(pl); | |
} | |
} | |
return dt; } | |
| <K_RAW> [ <O_OPENPAREN> precision=<S_NUMBER> <O_CLOSEPAREN> ] { | |
if (precision == null) { | |
dt = new RawType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
dt = new RawType(pl); | |
} | |
return dt; | |
} | |
| <K_BOOLEAN> { return BOOLEAN_TYPE;} | |
| <K_DATE> { return DATE_TYPE;} | |
| LOOKAHEAD(2) <K_INTERVAL> <K_DAY> [ <O_OPENPAREN> precision=<S_NUMBER> <O_CLOSEPAREN> ] <K_TO> <K_SECOND> [ <O_OPENPAREN> scale=<S_NUMBER> <O_CLOSEPAREN> ] | |
{ | |
if (precision == null) { | |
dt = new IntervalDayToSecond(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
if (scale == null) { | |
dt = new IntervalDayToSecond(pl); | |
} | |
else { | |
sl = Long.decode(scale.image); | |
dt = new IntervalDayToSecond(pl, sl); | |
} | |
} | |
return dt; } | |
| <K_INTERVAL> <K_YEAR> [ <O_OPENPAREN> <S_NUMBER> <O_CLOSEPAREN> ] <K_TO> <K_MONTH> { | |
if (precision == null) { | |
dt = new IntervalYearToMonth(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
dt = new IntervalYearToMonth(pl); | |
} | |
return dt; } | |
| ( <K_TIME> { return TIME_TYPE;} | |
| <K_TIMESTAMP> { return TIMESTAMP_TYPE;} | |
) [ <O_OPENPAREN> <S_NUMBER> <O_CLOSEPAREN> ] [ <K_WITH> [ <K_LOCAL> ] <K_TIME> <K_ZONE> ] | |
| <K_INTEGER> { return INTEGER_TYPE;} | |
| <K_INT> { return INTEGER_TYPE;} | |
| <K_SMALLINT> { return SMALLINT_TYPE;} | |
| <K_FLOAT> [ <O_OPENPAREN> precision=<S_NUMBER> <O_CLOSEPAREN> ] | |
{ | |
if (precision == null) { | |
return new FloatType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
FloatType ft = new FloatType(pl); | |
return ft; } | |
} | |
| <K_REAL> { return new RealType();} | |
| <K_MLSLABEL> { return MLSLABEL_TYPE;} | |
| <K_PLS_INTEGER> { return PLS_INTEGER_TYPE;} | |
| <K_SIMPLE_INTEGER> { return SIMPLE_INTEGER_TYPE;} | |
| <K_BLOB > { return new BlobType();} | |
| <K_NCLOB> { return new NClobType();} | |
| <K_BFILE> { return BFILE_TYPE;} | |
| <K_ROWID> { return ROWID_TYPE;} | |
| <K_UROWID> [ <O_OPENPAREN> precision=<S_NUMBER> <O_CLOSEPAREN> ] | |
{ | |
if (precision == null) { | |
return new URowIdType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new URowIdType(pl); | |
} } | |
| <K_DOUBLE> <K_PRECISION> { return new DoubleType();} | |
| <K_CHAR> [ t=<K_VARYING> ] [ <O_OPENPAREN> precision=<S_NUMBER> [ <K_BYTE> | <K_CHAR> ] <O_CLOSEPAREN> ] | |
[ LOOKAHEAD(2) <K_CHARACTER> <K_SET> [ LOOKAHEAD(2) <S_IDENTIFIER> | columnSpec() <K_CHARSET> ] ] { | |
if (t == null) { | |
if (precision == null) { | |
return new CharType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new CharType(pl); } | |
} | |
else { | |
// ANSI syntax for VARCHAR2 | |
if (precision == null) { | |
return new VarChar2Type(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new VarChar2Type(pl); | |
} } } | |
| <K_VARCHAR> [ <K_VARYING> ] [ <O_OPENPAREN> precision=<S_NUMBER> [ <K_BYTE> | <K_CHAR> ] <O_CLOSEPAREN> ] | |
[ LOOKAHEAD(2) <K_CHARACTER> <K_SET> [ LOOKAHEAD(2) <S_IDENTIFIER> | columnSpec() <K_CHARSET> ] ] | |
{ | |
if (precision == null) { | |
return new VarCharType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new VarCharType(pl); | |
} | |
} | |
| <K_VARCHAR2> [ <K_VARYING> ] [ <O_OPENPAREN> precision=<S_NUMBER> [ <K_BYTE> | <K_CHAR> ] <O_CLOSEPAREN> ] | |
[ LOOKAHEAD(2) <K_CHARACTER> <K_SET> [ LOOKAHEAD(2) <S_IDENTIFIER> | columnSpec() <K_CHARSET> ] ] | |
{ | |
if (precision == null) { | |
return new VarChar2Type(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new VarChar2Type(pl); } } | |
| <K_CHARACTER> [ t=<K_VARYING> ] [ <O_OPENPAREN> precision=<S_NUMBER> <O_CLOSEPAREN> ] | |
{ | |
if (t == null) { | |
if (precision == null) { | |
return new CharType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new CharType(pl); | |
} | |
} | |
else { | |
// ANSI syntax for VARCHAR | |
if (precision == null) { | |
return new VarCharType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new VarCharType(pl); | |
} | |
} | |
} | |
| <K_NCHAR> [ t=<K_VARYING> ] [ <O_OPENPAREN> precision=<S_NUMBER> <O_CLOSEPAREN> ] | |
{ | |
if (t == null) { | |
if (precision == null) { | |
return new NCharType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new NCharType(pl); | |
} | |
} | |
else { | |
// ANSI syntax for NVARCHAR2 | |
if (precision == null) { | |
return new NVarChar2Type(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new NVarChar2Type(pl); | |
} | |
} | |
} | |
| <K_NVARCHAR> [ <O_OPENPAREN> precision=<S_NUMBER> <O_CLOSEPAREN> ] { | |
if (precision == null) { | |
return new NVarChar2Type(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new NVarChar2Type(pl); | |
} } | |
| <K_NVARCHAR2> [ <O_OPENPAREN> precision=<S_NUMBER> <O_CLOSEPAREN> ] | |
{ | |
if (precision == null) { | |
return new NVarChar2Type(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new NVarChar2Type(pl); | |
} | |
} | |
| <K_NATIONAL> ( <K_CHARACTER> | <K_CHAR> ) [ t=<K_VARYING> ] [ <O_OPENPAREN> precision=<S_NUMBER> <O_CLOSEPAREN> ] | |
{ | |
if (t == null) { | |
if (precision == null) { | |
return new NCharType(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new NCharType(pl); | |
} | |
} | |
else { | |
// ANSI syntax for NVARCHAR2 | |
if (precision == null) { | |
return new NVarChar2Type(); | |
} | |
else { | |
pl = Long.decode(precision.image); | |
return new NVarChar2Type(pl); | |
} | |
} | |
} | |
| <K_CLOB> [ LOOKAHEAD(2) <K_CHARACTER> <K_SET> [ LOOKAHEAD(2) <S_IDENTIFIER> | columnSpec() <K_CHARSET> ] ] { return new ClobType();} | |
} | |
String typeSpec(): | |
{String s = null;} | |
{ | |
( datatype() | |
| LOOKAHEAD(3) columnSpec() <K_TYPE2> | |
| LOOKAHEAD(3) tableSpec() <K_ROWTYPE> | |
| typeName() [ <O_OPENPAREN> <S_NUMBER> <O_CLOSEPAREN> ] | |
) | |
{ | |
Token first = jjtThis.jjtGetFirstToken(); | |
Token last = jjtThis.jjtGetLastToken(); | |
Token cur = first; | |
StringBuilder sb = new StringBuilder(); | |
sb.append(first.image); | |
while (cur != last) { | |
cur = cur.next; | |
sb.append(cur.image); } | |
jjtThis.jjtSetValue(sb.toString()); | |
return sb.toString(); } | |
} | |
String columnSpec() #void: | |
{String s1 = null; | |
String s2 = null; | |
String s3 = null;} | |
{ | |
s1=OracleObjectName() [ <O_DOT> s2=OracleObjectName() [ <O_DOT> s3=OracleObjectName() ] ] | |
{ | |
StringBuilder sb = new StringBuilder(s1); | |
if (s2 != null) { | |
sb.append('.'); | |
sb.append(s2); | |
if (s3 != null) { | |
sb.append('.'); | |
sb.append(s3); | |
} | |
} | |
return sb.toString(); | |
} | |
} | |
String tableSpec() #void: | |
{} | |
{ | |
OracleObjectName() [ <O_DOT> OracleObjectName() [ <O_ATSIGN> <S_IDENTIFIER> ] ] | |
{return token.image;} | |
} | |
String typeName() #void: | |
{} | |
{ | |
OracleObjectName() [ <O_DOT> OracleObjectName() ] | |
{return token.image;} | |
} | |
void typeDeclaration(PLSQLPackageType packageType) #void: | |
{String s = null;} | |
{ | |
<K_TYPE> s=typeName() <K_IS> | |
aTypeDeclaration(packageType) | |
<O_SEMICOLON> | |
} | |
void aTypeDeclaration(PLSQLPackageType packageType) #void: | |
{} | |
{ | |
recordDeclaration(packageType) | |
| subtypeDeclaration(packageType) | |
| plsqlTableDeclaration(packageType) | |
| varrayDeclaration(packageType) | |
| refCursorDeclaration(packageType) | |
} | |
void recordDeclaration(PLSQLPackageType packageType) #void: | |
{} | |
{ | |
<K_RECORD> <O_OPENPAREN> | |
fieldDeclarations() | |
<O_CLOSEPAREN> | |
} | |
void fieldDeclarations() #void: | |
{} | |
{ | |
fieldDeclaration() [ <O_COMMA> fieldDeclarations() ] | |
} | |
SimpleNode fieldDeclaration(): | |
{String s = null; | |
} | |
{ | |
s=typeName() typeSpec() [ <K_NOT> <K_NULL> ] [ variableDefaultAssignment() ] | |
{ | |
jjtThis.jjtSetValue(s); | |
return jjtThis; | |
} | |
} | |
void subtypeDeclaration(PLSQLPackageType packageType) #void: | |
{} | |
{ | |
<K_SUBTYPE> OracleObjectName() <K_IS> datatype() | |
( <K_RANGE> <S_NUMBER> <O_DOUBLEDOT> <S_NUMBER> | |
| <S_NUMBER> [ <O_COMMA> <S_NUMBER> ] | |
| <K_CHARACTER> <K_SET> <S_IDENTIFIER> | |
) [ <K_NOT> <K_NULL> ] | |
} | |
void plsqlTableDeclaration(PLSQLPackageType packageType) #void: | |
{} | |
{ | |
<K_TABLE> <K_OF> typeSpec() [ <K_NOT> <K_NULL> ] <K_INDEX> <K_BY> | |
plsqlTableIndexByDeclaration(packageType) | |
} | |
void plsqlTableIndexByDeclaration(PLSQLPackageType packageType) #void: | |
{} | |
{ | |
( <K_PLS_INTEGER > | |
| <K_BINARY_INTEGER> | |
| <K_VARCHAR2> <O_OPENPAREN> <S_NUMBER> <O_CLOSEPAREN> | |
| <K_STRING> <O_OPENPAREN> <S_NUMBER> <O_CLOSEPAREN> | |
) | |
} | |
void varrayDeclaration(PLSQLPackageType packageType) #void: | |
{} | |
{ | |
( <K_VARRAY> | <K_VARYING> <K_ARRAY> ) <O_OPENPAREN> <S_NUMBER> <O_CLOSEPAREN> | |
<K_OF> datatype() [ <K_NOT> <K_NULL> ] | |
} | |
void refCursorDeclaration(PLSQLPackageType packageType) #void: | |
{String s = null;} | |
{ | |
<K_REF> <K_CURSOR> [ refCursorTypeSpec(packageType) ] | |
} | |
void refCursorTypeSpec(PLSQLPackageType packageType) #void: | |
{String s = null;} | |
{ | |
<K_RETURN> [LOOKAHEAD(3) s=columnSpec() [ <K_TYPE2> ] | |
| LOOKAHEAD(3) s=tableSpec() [ <K_ROWTYPE> ] ] | |
} | |
void cursorDeclaration(PLSQLPackageType packageType) #void: | |
{Token t = null;} | |
{ | |
<K_CURSOR> t=<S_IDENTIFIER> | |
<O_SEMICOLON> | |
} | |
// Procedure Specification | |
void procedureSpec(PLSQLPackageType packageType) #void: | |
{Token t = null;} | |
{ | |
<K_PROCEDURE> t=<S_IDENTIFIER> | |
[ <O_OPENPAREN> argumentList() <O_CLOSEPAREN> ] | |
<O_SEMICOLON> | |
} | |
void argumentList() #void: | |
{} | |
{ | |
argument() ( <O_COMMA> argument() )* | |
} | |
// Function Specification | |
void functionSpec(PLSQLPackageType packageType) #void: | |
{Token t = null;} | |
{ | |
<K_FUNCTION> t=<S_IDENTIFIER> | |
[ <O_OPENPAREN> argumentList() <O_CLOSEPAREN> ] | |
functionReturnSpec() | |
[ <K_DETERMINISTIC> | <K_PIPELINED> | <K_PARALLEL_ENABLE> | <K_RESULT_CACHE> ] | |
<O_SEMICOLON> | |
} | |
SimpleNode functionReturnSpec(): | |
{} { (<K_RETURN> typeSpec()) | |
{ | |
jjtThis.jjtSetValue("RETURN"); | |
return jjtThis; | |
} | |
} | |
SimpleNode argument(): | |
{Token t = null; | |
String direction = null; | |
} | |
{ | |
t=<S_IDENTIFIER> [(direction=direction())] | |
[ <K_NOCOPY> ] typeSpec() [ argumentDefaultAssignment() ] | |
{ | |
if (direction != null) { | |
jjtThis.jjtSetValue(direction + " " + t.image); | |
} | |
else { | |
// by default, arguments are IN | |
jjtThis.jjtSetValue("IN " + t.image); | |
} | |
return jjtThis; | |
} | |
} | |
String direction() #void: | |
{} | |
{ | |
LOOKAHEAD(2) <K_IN> <K_OUT> { return "IN OUT"; } | |
| <K_IN> { return "IN"; } | |
| <K_OUT> { return "OUT"; } | |
} | |
SimpleNode argumentDefaultAssignment(): | |
{} | |
{ | |
( <O_ASSIGN> | <K_DEFAULT> ) skipToNextArg() | |
{ | |
jjtThis.jjtSetValue(" (optional)"); | |
return jjtThis; | |
} | |
} | |
void exceptionDeclaration(PLSQLPackageType packageType) #void: | |
{} | |
{ | |
<S_IDENTIFIER> <K_EXCEPTION> <O_SEMICOLON> | |
} | |
void pragmaDeclaration(PLSQLPackageType packageType) #void: | |
{} | |
{ <K_PRAGMA> | |
[ <K_AUTONOMOUS_TRANSACTION> | |
| <K_EXCEPTION_INIT> <O_OPENPAREN> <S_IDENTIFIER> <O_COMMA> <S_NUMBER> <O_CLOSEPAREN> | |
| <K_SERIALLY_REUSABLE> | |
| <K_INLINE> <O_OPENPAREN> <S_IDENTIFIER> <O_COMMA> [ <K_YES> | <K_NO> ] <O_CLOSEPAREN> | |
| <K_RESTRICT_REFERENCES> <O_OPENPAREN> [ <S_IDENTIFIER> | <K_DEFAULT> ] | |
( <O_COMMA> [ <K_RNDS> | <K_WNDS> | <K_RNPS> | <K_WNPS> | <K_TRUST>] )+ <O_CLOSEPAREN> | |
] | |
<O_SEMICOLON> | |
} | |
String OracleObjectName() #void: | |
{} | |
{ | |
<S_IDENTIFIER> | |
{return token.image;} | |
| <S_QUOTED_IDENTIFIER> | |
{ | |
String s = token.image; | |
return s.substring(1, s.length() - 1); // strip-off quotes | |
} | |
} | |
void skipToSemiColon() #void: | |
{} | |
{ | |
{ | |
Token t = getNextToken(); | |
while (t.kind != O_SEMICOLON) { | |
t = getNextToken(); | |
} | |
token_source.input_stream.backup(1); | |
} | |
} | |
void skipToNextArg() #void: | |
{} | |
{ | |
{ | |
Token t = getNextToken(); | |
while (t.kind != O_COMMA && t.kind != O_CLOSEPAREN) { | |
t = getNextToken(); | |
} | |
token_source.input_stream.backup(1); | |
} | |
} | |
void skipToEnd() #void: | |
{} | |
{ | |
{ | |
/** skip through all the tokens. */ | |
Token t = getNextToken(); | |
while (t.kind != EOF) { | |
t = getNextToken(); | |
} | |
} | |
} |