0001: // Copyright (c) 2001, 2002, 2003, 2004, 2006 Per M.A. Bothner and Brainfood Inc.
0002: // This is free software; for terms and warranty disclaimer see ./COPYING.
0003:
0004: package gnu.xquery.lang;
0005:
0006: import gnu.kawa.lispexpr.*;
0007: import gnu.mapping.*;
0008: import gnu.lists.*;
0009: import gnu.text.*;
0010: import gnu.expr.*;
0011: import gnu.math.IntNum;
0012: import java.util.Vector;
0013: import java.util.Stack;
0014: import java.io.File;
0015: import gnu.kawa.xml.*;
0016: import gnu.xml.*;
0017: import gnu.bytecode.*;
0018: import gnu.kawa.reflect.OccurrenceType;
0019: import gnu.kawa.reflect.SingletonType;
0020: import gnu.kawa.functions.Convert;
0021: import gnu.xquery.util.NamedCollator;
0022: import gnu.xquery.util.CastableAs;
0023: import gnu.xquery.util.QNameUtils;
0024: import gnu.xquery.util.RelativeStep;
0025: import gnu.xquery.util.ValuesFilter;
0026: import kawa.standard.require;
0027:
0028: /** A class to read xquery forms. */
0029:
0030: public class XQParser extends Lexer {
0031: int curToken;
0032: Object curValue;
0033:
0034: /** Normally null.
0035: * 'C' means parsing the type of a 'cast as' or 'castable as'. */
0036: int parseContext;
0037: /** True if we've seen a VarDecl, FunctionDecl, or OptionDecl. */
0038: boolean seenDeclaration;
0039:
0040: String libraryModuleNamespace;
0041:
0042: /** Value of getLineNumber() at start of current token.
0043: * Sometimes set otherwise, to report errors. */
0044: int curLine;
0045:
0046: /** Value of getColumnNumber() at start of current token.
0047: * Sometimes set otherwise, to report errors. */
0048: int curColumn;
0049:
0050: XQuery interpreter;
0051:
0052: int seenPosition;
0053: int seenLast;
0054:
0055: public static boolean warnOldVersion = true;
0056: public static boolean warnHidePreviousDeclaration = false;
0057:
0058: /** The internal name of the variable containing '.', the context node. */
0059: static final Symbol DOT_VARNAME = Symbol.makeUninterned("$dot$");
0060:
0061: /** The pseduo-function position() is mapped to a reference. */
0062: static final Symbol POSITION_VARNAME = Symbol
0063: .makeUninterned("$position$");
0064:
0065: /** The pseduo-function last() is mapped to a reference to this variable. */
0066: static final Symbol LAST_VARNAME = Symbol.makeUninterned("$last$");
0067:
0068: public static final gnu.kawa.reflect.InstanceOf instanceOf = new gnu.kawa.reflect.InstanceOf(
0069: XQuery.getInstance(), "instance");
0070: public static final CastableAs castableAs = CastableAs.castableAs;
0071: public static final Convert treatAs = Convert.as;
0072:
0073: NameLookup lexical;
0074:
0075: NamedCollator defaultCollator = null;
0076:
0077: /** The default order for empty sequences.
0078: * Either <code>'L'</code> (for "least") or <code>'G'</code> (for "greatest").
0079: */
0080: char defaultEmptyOrder = 'L';
0081: boolean emptyOrderDeclarationSeen;
0082:
0083: Path baseURI = null;
0084: boolean baseURIDeclarationSeen;
0085:
0086: public void setStaticBaseUri(String uri) {
0087: try {
0088: baseURI = fixupStaticBaseUri(URIPath.valueOf(uri));
0089: } catch (Throwable ex) {
0090: if (ex instanceof WrappedException)
0091: ex = ((WrappedException) ex).getCause();
0092: error('e', "invalid URI: " + ex.getMessage());
0093: }
0094: }
0095:
0096: static Path fixupStaticBaseUri(Path path) {
0097: path = path.getAbsolute();
0098: if (path instanceof FilePath)
0099: path = URIPath.valueOf(path.toURI());
0100: return path;
0101: }
0102:
0103: public String getStaticBaseUri() {
0104: Path path = baseURI;
0105: if (path == null) {
0106: Environment env = Environment.getCurrent();
0107: Object value = env.get(Symbol.make("", "base-uri"), null,
0108: null);
0109: if (value != null) {
0110: if (value instanceof Path)
0111: path = (Path) path;
0112: else
0113: path = URIPath.valueOf(value.toString());
0114: }
0115:
0116: if (path == null) {
0117: LineBufferedReader port = getPort();
0118: path = port.getPath();
0119: if (path instanceof FilePath
0120: && (!path.exists() || port instanceof TtyInPort || port instanceof CharArrayInPort))
0121: path = null;
0122: }
0123:
0124: if (path == null)
0125: path = Path.currentPath();
0126:
0127: path = fixupStaticBaseUri(path);
0128: baseURI = path;
0129: }
0130:
0131: return path.toString();
0132: }
0133:
0134: public String resolveAgainstBaseUri(String uri) {
0135: if (Path.uriSchemeSpecified(uri))
0136: return uri;
0137: String base = getStaticBaseUri();
0138: Path basePath = Path.valueOf(base);
0139: return basePath.resolve(uri).toString();
0140: }
0141:
0142: boolean boundarySpacePreserve;
0143: boolean boundarySpaceDeclarationSeen;
0144:
0145: boolean orderingModeUnordered;
0146: boolean orderingModeSeen;
0147:
0148: /** True if we've seen a 'copy-namespaces' declaration'. */
0149: boolean copyNamespacesDeclarationSeen;
0150: int copyNamespacesMode = XMLFilter.COPY_NAMESPACES_PRESERVE
0151: | XMLFilter.COPY_NAMESPACES_INHERIT;
0152:
0153: /** The static construction mode. True if "strip"; false if "preserve". */
0154: boolean constructionModeStrip;
0155: /** True if a construction mode declaration has been seen. */
0156: boolean constructionModeDeclarationSeen;
0157:
0158: public Namespace[] functionNamespacePath = XQuery.defaultFunctionNamespacePath;
0159:
0160: /** Stack of currently active for/let Declarations. */
0161: Declaration[] flworDecls;
0162: /* Index in flworDecls of first Declaration in current FLWOR. */
0163: int flworDeclsFirst;
0164: /* Total number of currently active for/let Declarations. */
0165: int flworDeclsCount;
0166:
0167: int parseCount;
0168: int commentCount;
0169: /** An error message if comments are disallowed. Normally null. */
0170: String errorIfComment;
0171:
0172: /** Skip whitespace.
0173: * Sets 'index' to the that of the next non-whitespace character,
0174: * and returns that. If there are no more non-space characters,
0175: * returns ' '. */
0176: final int skipSpace() throws java.io.IOException, SyntaxException {
0177: return skipSpace(true);
0178: }
0179:
0180: final int skipSpace(boolean verticalToo)
0181: throws java.io.IOException, SyntaxException {
0182: for (;;) {
0183: int ch = read();
0184: if (ch == '(') {
0185: if (!checkNext(':'))
0186: return '(';
0187: skipComment();
0188: } else if (ch == '{') {
0189: ch = read();
0190: if (ch != '-') {
0191: unread(ch);
0192: return '{';
0193: }
0194: ch = read();
0195: if (ch != '-') {
0196: unread(ch);
0197: unread('-');
0198: return '{';
0199: }
0200: skipOldComment();
0201: } else if (verticalToo ? (ch < 0 || !Character
0202: .isWhitespace((char) ch))
0203: : (ch != ' ' && ch != '\t'))
0204: return ch;
0205: }
0206: }
0207:
0208: final void skipToSemicolon() throws java.io.IOException {
0209: for (;;) {
0210: int next = read();
0211: if (next < 0 || next == ';')
0212: break;
0213: }
0214: }
0215:
0216: final void skipOldComment() throws java.io.IOException,
0217: SyntaxException {
0218: int seenDashes = 0;
0219: int startLine = getLineNumber() + 1;
0220: int startColumn = getColumnNumber() - 2;
0221: warnOldVersion("use (: :) instead of old-style comment {-- --}");
0222: for (;;) {
0223: int ch = read();
0224: if (ch == '-')
0225: seenDashes++;
0226: else if (ch == '}' && seenDashes >= 2)
0227: return;
0228: else if (ch < 0) {
0229: curLine = startLine;
0230: curColumn = startColumn;
0231: eofError("non-terminated comment starting here");
0232: } else
0233: seenDashes = 0;
0234: }
0235: }
0236:
0237: final void skipComment() throws java.io.IOException,
0238: SyntaxException {
0239: commentCount++;
0240: int startLine = getLineNumber() + 1;
0241: int startColumn = getColumnNumber() - 1;
0242: if (errorIfComment != null) {
0243: curLine = startLine;
0244: curColumn = startColumn;
0245: error('e', errorIfComment);
0246: }
0247: int prev = 0;
0248: int commentNesting = 0;
0249: char saveReadState = pushNesting(':');
0250: for (;;) {
0251: int ch = read();
0252: if (ch == ':') {
0253: if (prev == '(') {
0254: commentNesting++;
0255: ch = 0;
0256: }
0257: } else if (ch == ')' && prev == ':') {
0258: if (commentNesting == 0) {
0259: popNesting(saveReadState);
0260: return;
0261: }
0262: --commentNesting;
0263: } else if (ch < 0) {
0264: curLine = startLine;
0265: curColumn = startColumn;
0266: eofError("non-terminated comment starting here");
0267: }
0268: prev = ch;
0269: }
0270: }
0271:
0272: /** Do skipSpace followed by unread to find next non-space character. */
0273: final int peekNonSpace(String message) throws java.io.IOException,
0274: SyntaxException {
0275: int ch = skipSpace();
0276: if (ch < 0)
0277: eofError(message);
0278: unread(ch);
0279: return ch;
0280: }
0281:
0282: static final int EOF_TOKEN = -1;
0283: static final int EOL_TOKEN = '\n';
0284: static final char INTEGER_TOKEN = '0';
0285: static final char DECIMAL_TOKEN = '1';
0286: static final char DOUBLE_TOKEN = '2';
0287: static final int STRING_TOKEN = '"';
0288: static final int SLASHSLASH_TOKEN = 'D';
0289: static final int DOTDOT_TOKEN = '3';
0290: static final int COLON_EQUAL_TOKEN = 'L'; // ":="
0291: static final int COLON_COLON_TOKEN = 'X';
0292:
0293: /** A non-qualified (simple) name (NCName).
0294: * The tokenBuffer contains the name (which does not contain a ':'). */
0295: static final int NCNAME_TOKEN = 'A';
0296:
0297: /** A non-qualified (simple) name (NCName) followed by a colon.
0298: * The colon is not followed by another NCNAME (in which it would
0299: * be a QNAME_TOKEN instead).
0300: * The tokenBuffer contains the name (which does not contain the ':'). */
0301: static final int NCNAME_COLON_TOKEN = 'C';
0302:
0303: /** A Qualified name (QName).
0304: * The tokenBuffer contains the full name, which contains one ':'. */
0305: static final int QNAME_TOKEN = 'Q';
0306:
0307: static final int ARROW_TOKEN = 'R';
0308:
0309: /* FuncName including following '('). */
0310: static final int FNAME_TOKEN = 'F';
0311:
0312: static final int IMPORT_MODULE_TOKEN = 'I'; // <"import" "module">
0313: static final int IMPORT_SCHEMA_TOKEN = 'T'; // <"import" "schema">
0314: static final int MODULE_NAMESPACE_TOKEN = 'M'; // <"module" "namespace">
0315: static final int DECLARE_NAMESPACE_TOKEN = 'N'; // <"declare" "namespace">
0316: static final int DECLARE_BOUNDARY_SPACE_TOKEN = 'S'; // <"declare" "boundary-space">
0317: static final int DEFAULT_ELEMENT_TOKEN = 'E'; // <"declare" "default" "element">
0318: static final int DEFAULT_FUNCTION_TOKEN = 'O'; // <"declare" "default" "function">
0319: static final int DEFAULT_COLLATION_TOKEN = 'G';
0320: static final int DEFAULT_ORDER_TOKEN = 'H'; // <"declare" "default" "order">
0321:
0322: static final int DECLARE_FUNCTION_TOKEN = 'P'; // <"declare" "function">
0323: static final int DECLARE_VARIABLE_TOKEN = 'V'; // <"declare" "variable">
0324: static final int DECLARE_BASE_URI_TOKEN = 'B'; // <"declare" "base-uri">
0325: static final int DECLARE_ORDERING_TOKEN = 'U'; // <"declare" "ordering">
0326: static final int DECLARE_CONSTRUCTION_TOKEN = 'K'; // <"declare" "construction">
0327: static final int DECLARE_OPTION_TOKEN = 'o'; // <"declare" "option">
0328: static final int DECLARE_COPY_NAMESPACES_TOKEN = 'L'; // <"declare" "copy-namespaces">
0329: static final int DEFINE_QNAME_TOKEN = 'W'; // <"define" QName> - an error
0330: static final int XQUERY_VERSION_TOKEN = 'Y'; // <"xquery" "version">
0331:
0332: /* 'Q': QName (intern'ed name is curValue)
0333: * 'R': NCName ':' '*'
0334: * OP_AXIS_FIRST: 'ancestor' followed by '::'
0335: * ...
0336: * OP_AXIS_FIRST+AXIS_SELF: 'self' followed by '::'
0337: */
0338:
0339: static final int OP_AXIS_FIRST = 100;
0340: static final int COUNT_OP_AXIS = 13;
0341: static final int AXIS_ANCESTOR = 0;
0342: static final int AXIS_ANCESTOR_OR_SELF = 1;
0343: static final int AXIS_ATTRIBUTE = 2;
0344: static final int AXIS_CHILD = 3;
0345: static final int AXIS_DESCENDANT = 4;
0346: static final int AXIS_DESCENDANT_OR_SELF = 5;
0347: static final int AXIS_FOLLOWING = 6;
0348: static final int AXIS_FOLLOWING_SIBLING = 7;
0349: static final int AXIS_NAMESPACE = 8;
0350: static final int AXIS_PARENT = 9;
0351: static final int AXIS_PRECEDING = 10;
0352: static final int AXIS_PRECEDING_SIBLING = 11;
0353: static final int AXIS_SELF = 12;
0354: static final int OP_WHERE = 196;
0355: static final int PRAGMA_START_TOKEN = 197; // '{#'
0356: // Token types for binary operators.
0357: static final int OP_BASE = 400;
0358: static final int OP_OR = OP_BASE; // 'or'
0359: static final int OP_AND = OP_BASE + 1; // 'and'
0360: static final int OP_EQU = OP_BASE + 2; // ' ='
0361: static final int OP_NEQ = OP_BASE + 3; // '! ='
0362: static final int OP_LSS = OP_BASE + 4; // '<'
0363: static final int OP_GRT = OP_BASE + 5; // '>'
0364: static final int OP_LEQ = OP_BASE + 6; // '< ='
0365: static final int OP_GEQ = OP_BASE + 7; // '> ='
0366: static final int OP_IS = OP_BASE + 8; // 'is'
0367: static final int OP_ISNOT = OP_BASE + 9; // 'isnot'
0368: static final int OP_GRTGRT = OP_BASE + 10; // '>>'
0369: static final int OP_LSSLSS = OP_BASE + 11; // '<<'
0370:
0371: static final int OP_RANGE_TO = OP_BASE + 12; // 'to'
0372:
0373: static final int OP_ADD = OP_BASE + 13; // '+'
0374: static final int OP_SUB = OP_BASE + 14; // '-'
0375:
0376: static final int OP_MUL = OP_BASE + 15; // '*'
0377: static final int OP_DIV = OP_BASE + 16; // 'div'
0378: static final int OP_IDIV = OP_BASE + 17; // 'idiv'
0379: static final int OP_MOD = OP_BASE + 18; // 'mod'
0380:
0381: static final int OP_UNION = OP_BASE + 19; // 'union'
0382:
0383: static final int OP_INTERSECT = OP_BASE + 20; // 'intersect'
0384: static final int OP_EXCEPT = OP_BASE + 21; // 'except'
0385:
0386: static final int OP_INSTANCEOF = OP_BASE + 22; // 'instance' 'of'
0387: static final int OP_TREAT_AS = OP_BASE + 23; // 'treat' 'as'
0388: static final int OP_CASTABLE_AS = OP_BASE + 24; // 'castable' 'as'
0389: static final int OP_CAST_AS = OP_BASE + 25; // 'cast' 'as'
0390:
0391: static final int OP_EQ = OP_BASE + 26; // 'eq'
0392: static final int OP_NE = OP_BASE + 27; // 'ne'
0393: static final int OP_LT = OP_BASE + 28; // 'lt'
0394: static final int OP_LE = OP_BASE + 29; // 'le
0395: static final int OP_GT = OP_BASE + 30; // 'gt'
0396: static final int OP_GE = OP_BASE + 31; // 'ge'
0397:
0398: static final int OP_NODE = 230; // 'node' followed by '('
0399: static final int OP_TEXT = 231; // 'text' followed by '('
0400: static final int OP_COMMENT = 232; // 'comment' followed by '('
0401: static final int OP_PI = 233; // 'processing-instruction' '('
0402: static final int OP_DOCUMENT = 234; // 'document-node' '('
0403: static final int OP_ELEMENT = 235; // 'element' '('
0404: static final int OP_ATTRIBUTE = 236; // 'attribute' '('
0405: static final int OP_ITEM = 237; // 'item' '('
0406: static final int OP_EMPTY_SEQUENCE = 238; // 'empty-sequence' '('
0407: static final int OP_SCHEMA_ATTRIBUTE = 239; // 'schema-attribute' '('
0408: static final int OP_SCHEMA_ELEMENT = 240; // 'schema-element' '('
0409: static final int IF_LPAREN_TOKEN = 241; // 'if' '('
0410: static final int TYPESWITCH_LPAREN_TOKEN = 242; // 'typeswitch' '('
0411:
0412: static final int FOR_DOLLAR_TOKEN = 243; // 'for' '$'
0413: static final int LET_DOLLAR_TOKEN = 244; // 'let' '$'
0414: static final int SOME_DOLLAR_TOKEN = 245; // 'some' '$'
0415: static final int EVERY_DOLLAR_TOKEN = 246; // 'every' '$'
0416: static final int CASE_DOLLAR_TOKEN = 247; // 'case' '$'
0417: static final int VALIDATE_LBRACE_TOKEN = 248; // 'validate' '{'
0418: static final int ORDERED_LBRACE_TOKEN = 249; // 'ordered' '{'
0419: static final int UNORDERED_LBRACE_TOKEN = 250; // 'unordered' '{'
0420: static final int ELEMENT_TOKEN = 251; // 'element' followed by '{' or alpha
0421: static final int ATTRIBUTE_TOKEN = 252;// 'attribute' followed by '{' or alpha
0422: static final int TEXT_TOKEN = 253; // 'text' followed by '{'
0423: static final int COMMENT_TOKEN = 254; // 'text' followed by '{'
0424: static final int PI_TOKEN = 255; // 'processing-instruction' followed by '{' or alpha
0425: static final int DOCUMENT_TOKEN = 256; // ;document' followed by '{'
0426:
0427: private int saveToken;
0428: private Object saveValue;
0429:
0430: public void mark() throws java.io.IOException {
0431: super .mark();
0432: saveToken = curToken;
0433: saveValue = curValue;
0434: }
0435:
0436: public void reset() throws java.io.IOException {
0437: curToken = saveToken;
0438: curValue = saveValue;
0439: super .reset();
0440: }
0441:
0442: private int setToken(int token, int width) {
0443: curToken = token;
0444: curLine = port.getLineNumber() + 1;
0445: curColumn = port.getColumnNumber() + 1 - width;
0446: return token;
0447: }
0448:
0449: void checkSeparator(char ch) {
0450: if (XName.isNameStart(ch))
0451: error('e', "missing separator", "XPST0003");
0452: }
0453:
0454: int getRawToken() throws java.io.IOException, SyntaxException {
0455: int next;
0456: for (;;) {
0457: next = read();
0458: if (next < 0)
0459: return setToken(EOF_TOKEN, 0);
0460: if (next == '\n' || next == '\r') {
0461: if (nesting <= 0)
0462: return setToken(EOL_TOKEN, 0);
0463: } else if (next == '(') {
0464: if (checkNext(':'))
0465: skipComment();
0466: else if (checkNext('#'))
0467: return setToken(PRAGMA_START_TOKEN, 2);
0468: else
0469: return setToken('(', 1);
0470: } else if (next == '{') {
0471: if (!checkNext('-'))
0472: return setToken('{', 1);
0473: next = read();
0474: if (next != '-') {
0475: // FIXME backup 2 chars. Can fix using special token for '{-'.
0476: unread();
0477: unread();
0478: return setToken('{', 1);
0479: }
0480: skipOldComment();
0481: } else if (next != ' ' && next != '\t')
0482: break;
0483: }
0484: tokenBufferLength = 0;
0485: curLine = port.getLineNumber() + 1;
0486: curColumn = port.getColumnNumber();
0487: char ch = (char) next;
0488: switch (ch) {
0489: case ')':
0490: case '[':
0491: case ']':
0492: case '}':
0493: case '$':
0494: case '@':
0495: case ',':
0496: case '?':
0497: case ';':
0498: break;
0499: case ':':
0500: if (checkNext('='))
0501: ch = COLON_EQUAL_TOKEN;
0502: else if (checkNext(':'))
0503: ch = COLON_COLON_TOKEN;
0504: break;
0505: case '|':
0506: ch = OP_UNION;
0507: break;
0508: case '*':
0509: ch = OP_MUL;
0510: break;
0511: case '+':
0512: ch = OP_ADD;
0513: break;
0514: case '-':
0515: ch = OP_SUB;
0516: break;
0517: case '!':
0518: if (checkNext('='))
0519: ch = OP_NEQ;
0520: break;
0521: case '/':
0522: if (checkNext('/'))
0523: ch = SLASHSLASH_TOKEN;
0524: break;
0525: case '=':
0526: if (checkNext('>'))
0527: ch = ARROW_TOKEN;
0528: ch = OP_EQU;
0529: break;
0530: case '>':
0531: ch = checkNext('=') ? (char) OP_GEQ
0532: : checkNext('>') ? (char) OP_GRTGRT : (char) OP_GRT;
0533: break;
0534: case '<':
0535: ch = checkNext('=') ? (char) OP_LEQ
0536: : checkNext('<') ? (char) OP_LSSLSS : (char) OP_LSS;
0537: break;
0538: case '\'':
0539: case '\"':
0540: char saveReadState = pushNesting((char) next);
0541: for (;;) {
0542: next = read();
0543: if (next < 0)
0544: eofError("unexpected end-of-file in string starting here");
0545: if (next == '&') {
0546: parseEntityOrCharRef();
0547: continue;
0548: } else if (ch == next) {
0549: next = read();
0550: if (ch != next) {
0551: unread(next);
0552: break;
0553: }
0554: }
0555: tokenBufferAppend((char) next);
0556: }
0557: popNesting(saveReadState);
0558: ch = STRING_TOKEN;
0559: break;
0560: default:
0561: if (Character.isDigit(ch)
0562: || (ch == '.' && Character.isDigit((char) peek()))) {
0563: boolean seenDot = ch == '.';
0564: for (;;) {
0565: tokenBufferAppend(ch);
0566: next = read();
0567: if (next < 0)
0568: break;
0569: ch = (char) next;
0570: if (ch == '.') {
0571: if (seenDot)
0572: break;
0573: seenDot = true;
0574: } else if (!Character.isDigit(ch))
0575: break;
0576: }
0577: if (next == 'e' || next == 'E') {
0578: tokenBufferAppend((char) next);
0579: next = read();
0580: if (next == '+' || next == '-') {
0581: tokenBufferAppend((char) next);
0582: next = read();
0583: }
0584: int expDigits = 0;
0585: for (;;) {
0586: if (next < 0)
0587: break;
0588: ch = (char) next;
0589: if (!Character.isDigit(ch)) {
0590: checkSeparator(ch);
0591: unread();
0592: break;
0593: }
0594: tokenBufferAppend(ch);
0595: next = read();
0596: expDigits++;
0597: }
0598: if (expDigits == 0)
0599: error('e', "no digits following exponent",
0600: "XPST0003");
0601: ch = DOUBLE_TOKEN;
0602: } else {
0603: ch = seenDot ? DECIMAL_TOKEN : INTEGER_TOKEN;
0604: if (next >= 0) {
0605: checkSeparator((char) next);
0606: unread(next);
0607: }
0608: }
0609: } else if (ch == '.') {
0610: if (checkNext('.'))
0611: ch = DOTDOT_TOKEN;
0612: break;
0613: } else if (XName.isNameStart(ch)) {
0614: for (;;) {
0615: tokenBufferAppend(ch);
0616: next = read();
0617: ch = (char) next;
0618: if (!XName.isNamePart(ch))
0619: break;
0620: }
0621: if (next < 0)
0622: ch = NCNAME_TOKEN;
0623: else {
0624: if (next != ':')
0625: ch = NCNAME_TOKEN;
0626: else {
0627: next = read();
0628: if (next < 0)
0629: eofError("unexpected end-of-file after NAME ':'");
0630: ch = (char) next;
0631: if (XName.isNameStart(ch)) {
0632: tokenBufferAppend(':');
0633: for (;;) {
0634: tokenBufferAppend(ch);
0635: next = read();
0636: ch = (char) next;
0637: if (!XName.isNamePart(ch))
0638: break;
0639: }
0640: ch = QNAME_TOKEN;
0641: } else if (ch == '=') {
0642: unread(ch);
0643: ch = NCNAME_TOKEN;
0644: } else
0645: ch = NCNAME_COLON_TOKEN;
0646: }
0647: unread(next);
0648: }
0649: } else if (ch >= ' ' && ch < 127)
0650: syntaxError("invalid character '" + ch + '\'');
0651: else
0652: syntaxError("invalid character '\\u"
0653: + Integer.toHexString(ch) + '\'');
0654: }
0655: curToken = ch;
0656: return ch;
0657: }
0658:
0659: /** Scan until a given delimiter.
0660: * On success, text upto the delimiter is in then tokenBuffer (with
0661: * tokenBufferLength marking its length); the delimiter is not included.
0662: */
0663: public void getDelimited(String delimiter)
0664: throws java.io.IOException, SyntaxException {
0665: tokenBufferLength = 0;
0666: int dlen = delimiter.length();
0667: char last = delimiter.charAt(dlen - 1);
0668: for (;;) {
0669: int ch = read();
0670: if (ch < 0)
0671: eofError("unexpected end-of-file looking for '"
0672: + delimiter + '\'');
0673: int dstart, j;
0674: // Look for a match for the last delimiter character.
0675: if (ch == last
0676: && (dstart = tokenBufferLength - (j = dlen - 1)) >= 0) {
0677: // Check that the initial part of the delimiter has also been seen.
0678: do {
0679: if (j == 0) {
0680: tokenBufferLength = dstart;
0681: return;
0682: }
0683: j--;
0684: } while (tokenBuffer[dstart + j] == delimiter.charAt(j));
0685: }
0686: tokenBufferAppend((char) ch);
0687: }
0688: }
0689:
0690: public void appendNamedEntity(String name) {
0691: name = name.intern();
0692: char ch = '?';
0693: if (name == "lt")
0694: ch = '<';
0695: else if (name == "gt")
0696: ch = '>';
0697: else if (name == "amp")
0698: ch = '&';
0699: else if (name == "quot")
0700: ch = '"';
0701: else if (name == "apos")
0702: ch = '\'';
0703: else
0704: error("unknown enity reference: '" + name + "'");
0705: tokenBufferAppend(ch);
0706: }
0707:
0708: boolean match(String word1, String word2, boolean force)
0709: throws java.io.IOException, SyntaxException {
0710: if (match(word1)) {
0711: mark();
0712: getRawToken();
0713: if (match(word2)) {
0714: reset();
0715: getRawToken();
0716: return true;
0717: }
0718: reset();
0719: if (force) {
0720: error('e', "'" + word1 + "' must be followed by '"
0721: + word2 + "'", "XPST0003");
0722: return true;
0723: }
0724: }
0725: return false;
0726: }
0727:
0728: /** Return the current token, assuming it is in operator context.
0729: * Resolve NCNAME_TOKEN (identifier) to 'and', 'or', 'div', etc.
0730: */
0731: int peekOperator() throws java.io.IOException, SyntaxException {
0732: while (curToken == EOL_TOKEN) {
0733: if (nesting == 0)
0734: return EOL_TOKEN;
0735: getRawToken();
0736: }
0737: if (curToken == NCNAME_TOKEN) {
0738: int len = tokenBufferLength;
0739: char c1, c2, c3;
0740: switch (len) {
0741: case 2:
0742: c1 = tokenBuffer[0];
0743: c2 = tokenBuffer[1];
0744: if (c1 == 'o' && c2 == 'r')
0745: curToken = OP_OR;
0746: else if (c1 == 't' && c2 == 'o')
0747: curToken = OP_RANGE_TO;
0748: else if (c1 == 'i' && c2 == 's')
0749: curToken = OP_IS;
0750: else if (c1 == 'e' && c2 == 'q')
0751: curToken = OP_EQ;
0752: else if (c1 == 'n' && c2 == 'e')
0753: curToken = OP_NE;
0754: else if (c1 == 'g') {
0755: if (c2 == 'e')
0756: curToken = OP_GE;
0757: else if (c2 == 't')
0758: curToken = OP_GT;
0759: } else if (c1 == 'l') {
0760: if (c2 == 'e')
0761: curToken = OP_LE;
0762: else if (c2 == 't')
0763: curToken = OP_LT;
0764: }
0765: break;
0766:
0767: case 3:
0768: c1 = tokenBuffer[0];
0769: c2 = tokenBuffer[1];
0770: c3 = tokenBuffer[2];
0771: if (c1 == 'a') {
0772: if (c2 == 'n' && c3 == 'd')
0773: curToken = OP_AND;
0774: } else if (c1 == 'm') {
0775: if (c2 == 'u' && c3 == 'l')
0776: curToken = OP_MUL;
0777: if (c2 == 'o' && c3 == 'd')
0778: curToken = OP_MOD;
0779: } else if (c1 == 'd') {
0780: if (c2 == 'i' && c3 == 'v')
0781: curToken = OP_DIV;
0782: }
0783: break;
0784: case 4:
0785: if (match("idiv"))
0786: curToken = OP_IDIV;
0787: else if (match("cast", "as", true))
0788: curToken = OP_CAST_AS;
0789: break;
0790: case 5:
0791: if (match("where"))
0792: curToken = OP_WHERE;
0793: else if (match("isnot"))
0794: curToken = OP_ISNOT;
0795: else if (match("union"))
0796: curToken = OP_UNION;
0797: else if (match("treat", "as", true))
0798: curToken = OP_TREAT_AS;
0799: break;
0800: case 6:
0801: if (match("except"))
0802: curToken = OP_EXCEPT;
0803: break;
0804: case 8:
0805: if (match("instance", "of", true))
0806: curToken = OP_INSTANCEOF;
0807: else if (match("castable", "as", true))
0808: curToken = OP_CASTABLE_AS;
0809: break;
0810: case 9:
0811: if (match("intersect"))
0812: curToken = OP_INTERSECT;
0813: break;
0814: case 10:
0815: if (match("instanceof")) // obsolete
0816: {
0817: warnOldVersion("use 'instanceof of' (two words) instead of 'instanceof'");
0818: curToken = OP_INSTANCEOF;
0819: }
0820: break;
0821: default:
0822: break;
0823: }
0824: }
0825: return curToken;
0826: }
0827:
0828: /**
0829: * Internal method to match against double-lexeme tokens.
0830: * @param word0 expected previous word
0831: * @param word1 expected next word
0832: */
0833: private boolean lookingAt(String word0, String word1)
0834: throws java.io.IOException, SyntaxException {
0835: if (!word0.equals(curValue))
0836: return false;
0837: int i = 0;
0838: int len = word1.length();
0839: for (;;) {
0840: int ch = read();
0841: if (i == len) {
0842: if (ch < 0)
0843: return true;
0844: if (!XName.isNamePart((char) ch)) {
0845: unread();
0846: return true;
0847: }
0848: i++;
0849: break;
0850: }
0851: if (ch < 0 || ch != word1.charAt(i++))
0852: break;
0853: }
0854: port.skip(-i);
0855: return false;
0856: }
0857:
0858: int getAxis() {
0859: // match axis name
0860: String name = new String(tokenBuffer, 0, tokenBufferLength)
0861: .intern();
0862: int i;
0863: for (i = COUNT_OP_AXIS; --i >= 0;)
0864: if (axisNames[i] == name)
0865: break;
0866: if (i < 0 || i == AXIS_NAMESPACE) // The namespace-axis is XSLT/XPath-only.
0867: {
0868: error('e', "unknown axis name '" + name + '\'', "XPST0003");
0869: i = AXIS_CHILD;
0870: }
0871: return (char) (OP_AXIS_FIRST + i);
0872: }
0873:
0874: /** Process token, assuming we are in operand context.
0875: */
0876:
0877: int peekOperand() throws java.io.IOException, SyntaxException {
0878: while (curToken == EOL_TOKEN)
0879: getRawToken();
0880: if (curToken == NCNAME_TOKEN || curToken == QNAME_TOKEN) {
0881: int next = skipSpace(nesting != 0);
0882: switch (tokenBuffer[0]) {
0883: case 'a':
0884: if (match("attribute")) {
0885: if (next == '(')
0886: return curToken = OP_ATTRIBUTE;
0887: if (next == '{' || XName.isNameStart((char) next)) {
0888: unread();
0889: return curToken = ATTRIBUTE_TOKEN;
0890: }
0891: break;
0892: }
0893: break;
0894: case 'c':
0895: if (match("comment")) {
0896: if (next == '(')
0897: return curToken = OP_COMMENT;
0898: if (next == '{') {
0899: unread();
0900: return curToken = COMMENT_TOKEN;
0901: }
0902: }
0903: break;
0904: case 'd':
0905: if (next == '{' && match("document")) {
0906: unread();
0907: return curToken = DOCUMENT_TOKEN;
0908: }
0909: if (next == '(' && match("document-node"))
0910: return curToken = OP_DOCUMENT;
0911: break;
0912: case 'e':
0913: if (match("element")) {
0914: if (next == '(')
0915: return curToken = OP_ELEMENT;
0916: if (next == '{' || XName.isNameStart((char) next)) {
0917: unread();
0918: return curToken = ELEMENT_TOKEN;
0919: }
0920: break;
0921: }
0922: if (match("empty-sequence"))
0923: return curToken = OP_EMPTY_SEQUENCE;
0924: if (next == '$' && match("every"))
0925: return curToken = EVERY_DOLLAR_TOKEN;
0926: break;
0927: case 'f':
0928: if (next == '$' && match("for"))
0929: return curToken = FOR_DOLLAR_TOKEN;
0930: break;
0931: case 'i':
0932: if (next == '(' && match("if"))
0933: return curToken = IF_LPAREN_TOKEN;
0934: if (next == '(' && match("item"))
0935: return curToken = OP_ITEM;
0936: break;
0937: case 'l':
0938: if (next == '$' && match("let"))
0939: return curToken = LET_DOLLAR_TOKEN;
0940: break;
0941: case 'n':
0942: if (next == '(' && match("node"))
0943: return curToken = OP_NODE;
0944: break;
0945: case 'o':
0946: if (next == '{' && match("ordered"))
0947: return curToken = ORDERED_LBRACE_TOKEN;
0948: break;
0949: case 'p':
0950: if (match("processing-instruction")) {
0951: if (next == '(')
0952: return curToken = OP_PI;
0953: if (next == '{' || XName.isNameStart((char) next)) {
0954: unread();
0955: return curToken = PI_TOKEN;
0956: }
0957: break;
0958: }
0959: break;
0960: case 's':
0961: if (next == '$' && match("some"))
0962: return curToken = SOME_DOLLAR_TOKEN;
0963: if (next == '(' && match("schema-attribute"))
0964: return curToken = OP_SCHEMA_ATTRIBUTE;
0965: if (next == '(' && match("schema-element"))
0966: return curToken = OP_SCHEMA_ELEMENT;
0967: break;
0968: case 't':
0969: if (match("text")) {
0970: if (next == '(')
0971: return curToken = OP_TEXT;
0972: if (next == '{') {
0973: unread();
0974: return curToken = TEXT_TOKEN;
0975: }
0976: }
0977: if (next == '(' && match("typeswitch"))
0978: return curToken = TYPESWITCH_LPAREN_TOKEN;
0979: break;
0980: case 'u':
0981: if (next == '{' && match("unordered"))
0982: return curToken = UNORDERED_LBRACE_TOKEN;
0983: break;
0984: case 'v':
0985: if (next == '{' && match("validate"))
0986: return curToken = VALIDATE_LBRACE_TOKEN;
0987: break;
0988: }
0989: if (next == '(' && peek() != ':') {
0990: return curToken = FNAME_TOKEN;
0991: }
0992: if (next == ':' && peek() == ':')
0993: return curToken = getAxis();
0994: String name = new String(tokenBuffer, 0, tokenBufferLength);
0995: curValue = name;
0996: switch (next) {
0997: case 'b':
0998: if (lookingAt("declare", /*"b"+*/"ase-uri"))
0999: return curToken = DECLARE_BASE_URI_TOKEN;
1000: if (lookingAt("declare", /*"b"+*/"oundary-space"))
1001: return curToken = DECLARE_BOUNDARY_SPACE_TOKEN;
1002: break;
1003: case 'c':
1004: if (lookingAt("declare", /*"c"+*/"onstruction"))
1005: return curToken = DECLARE_CONSTRUCTION_TOKEN;
1006: if (lookingAt("declare", /*"c"+*/"opy-namespaces"))
1007: return curToken = DECLARE_COPY_NAMESPACES_TOKEN;
1008: break;
1009: case 'd':
1010: if (lookingAt("declare", /*"d"+*/"efault")) {
1011: getRawToken();
1012: if (match("function"))
1013: return curToken = DEFAULT_FUNCTION_TOKEN;
1014: if (match("element"))
1015: return curToken = DEFAULT_ELEMENT_TOKEN;
1016: if (match("collation"))
1017: return curToken = DEFAULT_COLLATION_TOKEN;
1018: if (match("order"))
1019: return curToken = DEFAULT_ORDER_TOKEN;
1020: error("unrecognized/unimplemented 'declare default'");
1021: skipToSemicolon();
1022: return peekOperand();
1023: }
1024: case 'e':
1025: if (lookingAt("default", /*"e"+*/"lement")) {
1026: warnOldVersion("replace 'default element' by 'declare default element namespace'");
1027: return curToken = DEFAULT_ELEMENT_TOKEN;
1028: }
1029: break;
1030: case 'f':
1031: if (lookingAt("declare", /*"f"+*/"unction"))
1032: return curToken = DECLARE_FUNCTION_TOKEN;
1033: if (lookingAt("define", /*"f"+*/"unction")) {
1034: warnOldVersion("replace 'define function' by 'declare function'");
1035: return curToken = DECLARE_FUNCTION_TOKEN;
1036: }
1037: if (lookingAt("default", /*"f"+*/"unction")) {
1038: warnOldVersion("replace 'default function' by 'declare default function namespace'");
1039: return curToken = DEFAULT_FUNCTION_TOKEN;
1040: }
1041: break;
1042: case 'm':
1043: if (lookingAt("import", /*"m"+*/"odule"))
1044: return curToken = IMPORT_MODULE_TOKEN;
1045: break;
1046: case 'n':
1047: if (lookingAt("declare", /*"n"+*/"amespace"))
1048: return curToken = DECLARE_NAMESPACE_TOKEN;
1049: if (lookingAt("default", /*"n"+*/"amespace")) {
1050: warnOldVersion("replace 'default namespace' by 'declare default element namespace'");
1051: return curToken = DEFAULT_ELEMENT_TOKEN;
1052: }
1053: if (lookingAt("module", /*"n"+*/"amespace"))
1054: return curToken = MODULE_NAMESPACE_TOKEN;
1055: break;
1056: case 'o':
1057: if (lookingAt("declare", /*"o"+*/"rdering"))
1058: return curToken = DECLARE_ORDERING_TOKEN;
1059: if (lookingAt("declare", /*"o"+*/"ption"))
1060: return curToken = DECLARE_OPTION_TOKEN;
1061: break;
1062: case 's':
1063: if (lookingAt("import", /*"s"+*/"chema"))
1064: return curToken = IMPORT_SCHEMA_TOKEN;
1065: break;
1066: case 'v':
1067: if (lookingAt("declare", /*"v"+*/"ariable"))
1068: return curToken = DECLARE_VARIABLE_TOKEN;
1069: if (lookingAt("define", /*"v"+*/"ariable")) {
1070: warnOldVersion("replace 'define variable' by 'declare variable'");
1071: return curToken = DECLARE_VARIABLE_TOKEN;
1072: }
1073: if (lookingAt("xquery", /*"v"+*/"ersion"))
1074: return curToken = XQUERY_VERSION_TOKEN;
1075: break;
1076: case 'x':
1077: if (lookingAt("declare", /*"x"+*/"mlspace")) {
1078: warnOldVersion("replace 'define xmlspace' by 'declare boundary-space'");
1079: return curToken = DECLARE_BOUNDARY_SPACE_TOKEN;
1080: }
1081: break;
1082: }
1083: if (next >= 0) {
1084: unread();
1085: if (XName.isNameStart((char) next)
1086: && curValue.equals("define")) {
1087: getRawToken();
1088: curToken = DEFINE_QNAME_TOKEN;
1089: }
1090: }
1091: return curToken;
1092: }
1093: if (curToken == NCNAME_COLON_TOKEN) {
1094: int next = read();
1095: if (next == ':') // We've seen an Axis specifier.
1096: curToken = getAxis();
1097: else
1098: unread(next);
1099: }
1100: return curToken;
1101: }
1102:
1103: void checkAllowedNamespaceDeclaration(String prefix, String uri,
1104: boolean inConstructor) {
1105: boolean xmlPrefix = "xml".equals(prefix);
1106: if (NamespaceBinding.XML_NAMESPACE.equals(uri)) {
1107: if (!xmlPrefix || !inConstructor)
1108: error(
1109: 'e',
1110: "namespace uri cannot be the same as the prefined xml namespace",
1111: "XQST0070");
1112: } else if (xmlPrefix || "xmlns".equals(prefix))
1113: error('e', "namespace prefix cannot be 'xml' or 'xmlns'",
1114: "XQST0070");
1115: }
1116:
1117: void pushNamespace(String prefix, String uri) {
1118: if (uri.length() == 0)
1119: uri = null;
1120: prologNamespaces = new NamespaceBinding(prefix, uri,
1121: prologNamespaces);
1122: }
1123:
1124: public XQParser(InPort port, SourceMessages messages, XQuery interp) {
1125: super (port, messages);
1126: interpreter = interp;
1127: lexical = new NameLookup(interp);
1128: nesting = 1;
1129:
1130: // Push standard namespaces into lexical scope.
1131: NamespaceBinding ns = builtinNamespaces;
1132: prologNamespaces = ns;
1133: }
1134:
1135: public void setInteractive(boolean v) {
1136: if (interactive != v)
1137: if (v)
1138: nesting--;
1139: else
1140: nesting++;
1141: interactive = v;
1142: }
1143:
1144: private static final int priority(int opcode) {
1145: switch (opcode) {
1146: case OP_OR:
1147: return 1;
1148: case OP_AND:
1149: return 2;
1150: case OP_EQU:
1151: case OP_NEQ:
1152: case OP_LSS:
1153: case OP_GRT:
1154: case OP_LEQ:
1155: case OP_GEQ:
1156: case OP_EQ:
1157: case OP_NE:
1158: case OP_LT:
1159: case OP_GT:
1160: case OP_LE:
1161: case OP_GE:
1162: case OP_IS:
1163: case OP_ISNOT:
1164: case OP_GRTGRT:
1165: case OP_LSSLSS:
1166: return 3;
1167: case OP_RANGE_TO:
1168: return 4;
1169: case OP_ADD:
1170: case OP_SUB:
1171: return 5;
1172: case OP_MUL:
1173: case OP_DIV:
1174: case OP_IDIV:
1175: case OP_MOD:
1176: return 6;
1177: case OP_UNION:
1178: return 7;
1179: case OP_INTERSECT:
1180: case OP_EXCEPT:
1181: return 8;
1182: case OP_INSTANCEOF:
1183: return 9;
1184: case OP_TREAT_AS:
1185: return 10;
1186: case OP_CASTABLE_AS:
1187: return 11;
1188: case OP_CAST_AS:
1189: return 12;
1190: default:
1191: return 0;
1192: }
1193: }
1194:
1195: static Expression makeBinary(Expression func, Expression exp1,
1196: Expression exp2) {
1197: Expression[] args = new Expression[2];
1198: args[0] = exp1;
1199: args[1] = exp2;
1200: return new ApplyExp(func, args);
1201: }
1202:
1203: static Expression makeExprSequence(Expression exp1, Expression exp2) {
1204: return makeBinary(makeFunctionExp(
1205: "gnu.kawa.functions.AppendValues", "appendValues"),
1206: exp1, exp2);
1207: }
1208:
1209: Expression makeBinary(int op, Expression exp1, Expression exp2)
1210: throws java.io.IOException, SyntaxException {
1211: Expression func;
1212: switch (op) {
1213: case OP_ADD:
1214: func = makeFunctionExp("gnu.xquery.util.ArithOp", "add",
1215: "+");
1216: break;
1217: case OP_SUB:
1218: func = makeFunctionExp("gnu.xquery.util.ArithOp", "sub",
1219: "-");
1220: break;
1221: case OP_MUL:
1222: func = makeFunctionExp("gnu.xquery.util.ArithOp", "mul",
1223: "*");
1224: break;
1225: case OP_DIV:
1226: func = makeFunctionExp("gnu.xquery.util.ArithOp", "div",
1227: "div");
1228: break;
1229: case OP_IDIV:
1230: func = makeFunctionExp("gnu.xquery.util.ArithOp", "idiv",
1231: "idiv");
1232: break;
1233: case OP_MOD:
1234: func = makeFunctionExp("gnu.xquery.util.ArithOp", "mod",
1235: "mod");
1236: break;
1237: case OP_EQ:
1238: func = makeFunctionExp("gnu.xquery.util.Compare", "valEq",
1239: "eq");
1240: break;
1241: case OP_NE:
1242: func = makeFunctionExp("gnu.xquery.util.Compare", "valNe",
1243: "ne");
1244: break;
1245: case OP_LT:
1246: func = makeFunctionExp("gnu.xquery.util.Compare", "valLt",
1247: "lt");
1248: break;
1249: case OP_LE:
1250: func = makeFunctionExp("gnu.xquery.util.Compare", "valLe",
1251: "le");
1252: break;
1253: case OP_GT:
1254: func = makeFunctionExp("gnu.xquery.util.Compare", "valGt",
1255: "gt");
1256: break;
1257: case OP_GE:
1258: func = makeFunctionExp("gnu.xquery.util.Compare", "valGe",
1259: "ge");
1260: break;
1261: case OP_EQU:
1262: func = makeFunctionExp("gnu.xquery.util.Compare", "=");
1263: break;
1264: case OP_NEQ:
1265: func = makeFunctionExp("gnu.xquery.util.Compare", "!=");
1266: break;
1267: case OP_LSS:
1268: func = makeFunctionExp("gnu.xquery.util.Compare", "<");
1269: break;
1270: case OP_LEQ:
1271: func = makeFunctionExp("gnu.xquery.util.Compare", "<=");
1272: break;
1273: case OP_GRT:
1274: func = makeFunctionExp("gnu.xquery.util.Compare", ">");
1275: break;
1276: case OP_GEQ:
1277: func = makeFunctionExp("gnu.xquery.util.Compare", ">=");
1278: break;
1279: case OP_IS:
1280: func = makeFunctionExp("gnu.kawa.xml.NodeCompare", "$Eq",
1281: "is");
1282: break;
1283: case OP_ISNOT:
1284: func = makeFunctionExp("gnu.kawa.xml.NodeCompare", "$Ne",
1285: "isnot");
1286: break;
1287: case OP_GRTGRT:
1288: func = makeFunctionExp("gnu.kawa.xml.NodeCompare", "$Gr",
1289: ">>");
1290: break;
1291: case OP_LSSLSS:
1292: func = makeFunctionExp("gnu.kawa.xml.NodeCompare", "$Ls",
1293: "<<");
1294: break;
1295: case OP_RANGE_TO:
1296: func = makeFunctionExp("gnu.xquery.util.IntegerRange",
1297: "integerRange");
1298: break;
1299: case OP_UNION:
1300: func = makeFunctionExp("gnu.kawa.xml.UnionNodes",
1301: "unionNodes");
1302: break;
1303: case OP_INTERSECT:
1304: func = makeFunctionExp("gnu.kawa.xml.IntersectNodes",
1305: "intersectNodes");
1306: break;
1307: case OP_EXCEPT:
1308: func = makeFunctionExp("gnu.kawa.xml.IntersectNodes",
1309: "exceptNodes");
1310: break;
1311: default:
1312: return syntaxError("unimplemented binary op: " + op);
1313: }
1314: return makeBinary(func, exp1, exp2);
1315: }
1316:
1317: private void parseSimpleKindType() throws java.io.IOException,
1318: SyntaxException {
1319: getRawToken();
1320: if (curToken == ')')
1321: getRawToken();
1322: else
1323: error("expected ')'");
1324: }
1325:
1326: public Expression parseNamedNodeType(boolean attribute)
1327: throws java.io.IOException, SyntaxException {
1328: Expression qname;
1329: getRawToken();
1330: if (curToken == ')') {
1331: qname = QuoteExp.getInstance(ElementType.MATCH_ANY_QNAME);
1332: getRawToken();
1333: } else {
1334: if (curToken == QNAME_TOKEN || curToken == NCNAME_TOKEN)
1335: qname = parseNameTest(attribute);
1336: else {
1337: if (curToken != OP_MUL)
1338: syntaxError("expected QName or *");
1339: qname = QuoteExp
1340: .getInstance(ElementType.MATCH_ANY_QNAME);
1341: }
1342:
1343: getRawToken();
1344: if (curToken == ',') {
1345: getRawToken();
1346: if (curToken == QNAME_TOKEN || curToken == NCNAME_TOKEN) {
1347: Expression tname = parseNameTest(true);
1348: } else
1349: syntaxError("expected QName");
1350: getRawToken();
1351: }
1352: if (curToken == ')')
1353: getRawToken();
1354: else
1355: error("expected ')' after element");
1356: }
1357: return makeNamedNodeType(attribute, qname);
1358: }
1359:
1360: static Expression makeNamedNodeType(boolean attribute,
1361: Expression qname) {
1362: Expression[] name = new Expression[2];
1363: ClassType nodeType = ClassType
1364: .make(attribute ? "gnu.kawa.xml.AttributeType"
1365: : "gnu.kawa.xml.ElementType");
1366: ApplyExp elt = new ApplyExp(nodeType.getDeclaredMethod("make",
1367: 1), new Expression[] { qname });
1368: elt.setFlag(ApplyExp.INLINE_IF_CONSTANT);
1369: return elt;
1370: }
1371:
1372: private boolean warnedOldStyleKindTest;
1373:
1374: private void warnOldStyleKindTest() {
1375: if (warnedOldStyleKindTest)
1376: return;
1377: error('w', "old-style KindTest - first one here");
1378: warnedOldStyleKindTest = true;
1379: }
1380:
1381: /** Parse: ["as" SequenceType] */
1382: public Expression parseOptionalTypeDeclaration()
1383: throws java.io.IOException, SyntaxException {
1384: if (!match("as"))
1385: return null;
1386: getRawToken();
1387: return parseDataType();
1388: }
1389:
1390: public Expression parseDataType() throws java.io.IOException,
1391: SyntaxException {
1392: Expression etype = parseItemType();
1393: int min, max;
1394: if (etype == null) {
1395: if (curToken != OP_EMPTY_SEQUENCE)
1396: return syntaxError("bad syntax - expected DataType");
1397: parseSimpleKindType();
1398: if (curToken == '?' || curToken == OP_ADD
1399: || curToken == OP_MUL) {
1400: getRawToken();
1401: return syntaxError("occurrence-indicator meaningless after empty-sequence()");
1402: }
1403: etype = QuoteExp
1404: .getInstance(OccurrenceType.emptySequenceType);
1405: min = 0;
1406: max = 0;
1407: } else if (curToken == '?') {
1408: min = 0;
1409: max = 1;
1410: } else if (curToken == OP_ADD) {
1411: min = 1;
1412: max = -1;
1413: } else if (curToken == OP_MUL) {
1414: min = 0;
1415: max = -1;
1416: } else {
1417: min = 1;
1418: max = 1;
1419: }
1420: if (parseContext == 'C') {
1421: if (max != 1)
1422: return syntaxError("type to 'cast as' or 'castable as' must be a 'SingleType'");
1423: }
1424: if (min != max) {
1425: getRawToken();
1426: Expression[] args = { etype,
1427: QuoteExp.getInstance(gnu.math.IntNum.make(min)),
1428: QuoteExp.getInstance(gnu.math.IntNum.make(max)) };
1429: ApplyExp otype = new ApplyExp(ClassType.make(
1430: "gnu.kawa.reflect.OccurrenceType")
1431: .getDeclaredMethod("getInstance", 3), args);
1432: otype.setFlag(ApplyExp.INLINE_IF_CONSTANT);
1433: return otype;
1434: }
1435: return etype;
1436: }
1437:
1438: public Expression parseMaybeKindTest() throws java.io.IOException,
1439: SyntaxException {
1440: Type type;
1441: switch (curToken) {
1442: case OP_ATTRIBUTE:
1443: case OP_ELEMENT:
1444: return parseNamedNodeType(curToken == OP_ATTRIBUTE);
1445:
1446: case OP_TEXT:
1447: parseSimpleKindType();
1448: type = NodeType.textNodeTest;
1449: break;
1450:
1451: case OP_COMMENT:
1452: parseSimpleKindType();
1453: type = NodeType.commentNodeTest;
1454: break;
1455:
1456: case OP_DOCUMENT:
1457: parseSimpleKindType();
1458: type = NodeType.documentNodeTest;
1459: break;
1460:
1461: case OP_NODE:
1462: parseSimpleKindType();
1463: type = NodeType.anyNodeTest;
1464: break;
1465:
1466: case OP_PI:
1467: getRawToken();
1468: String piTarget = null;
1469: if (curToken == NCNAME_TOKEN || curToken == STRING_TOKEN) {
1470: piTarget = new String(tokenBuffer, 0, tokenBufferLength);
1471: getRawToken();
1472: }
1473: if (curToken == ')')
1474: getRawToken();
1475: else
1476: error("expected ')'");
1477: type = ProcessingInstructionType.getInstance(piTarget);
1478: break;
1479:
1480: default:
1481: return null;
1482: }
1483: return QuoteExp.getInstance(type);
1484: }
1485:
1486: public Expression parseItemType() throws java.io.IOException,
1487: SyntaxException {
1488: peekOperand();
1489: Expression etype = parseMaybeKindTest();
1490: Type type;
1491: if (etype != null) {
1492: if (parseContext == 'C')
1493: // Kludge to force error below.
1494: type = XDataType.anyAtomicType;
1495: else
1496: return etype;
1497: } else if (curToken == OP_ITEM) {
1498: parseSimpleKindType();
1499: type = SingletonType.getInstance();
1500: } else if (curToken == NCNAME_TOKEN || curToken == QNAME_TOKEN) {
1501: String tname = new String(tokenBuffer, 0, tokenBufferLength);
1502: getRawToken();
1503: type = interpreter.getTypeFor(tname);
1504: if (type == null) {
1505: error('e', "unknown type " + tname, "XPST0051");
1506: type = Type.pointer_type;
1507: }
1508: } else
1509: return null;
1510: if (parseContext == 'C') {
1511: if (type == SingletonType.getInstance())
1512: return syntaxError(
1513: "type to 'cast as' or 'castable as' must be atomic",
1514: "XPST0080");
1515: if (type == XDataType.anyAtomicType)
1516: return syntaxError(
1517: "type to 'cast as' or 'castable as' cannot be anyAtomicType",
1518: "XPST0080");
1519: if (type == XDataType.NotationType)
1520: return syntaxError(
1521: "type to 'cast as' or 'castable as' cannot be NOTATION",
1522: "XPST0080");
1523: }
1524: return QuoteExp.getInstance(type);
1525: }
1526:
1527: /** Parse a <code>URILiteral</code>..
1528: * @return either a String (on success),
1529: * or an ErrorExp (after emitting an error).
1530: */
1531: Object parseURILiteral() throws java.io.IOException,
1532: SyntaxException {
1533: getRawToken();
1534: if (curToken != STRING_TOKEN)
1535: return declError("expected a URILiteral");
1536: String str = new String(tokenBuffer, 0, tokenBufferLength);
1537: str = TextUtils.replaceWhitespace(str, true);
1538: // FUTURE: An implementation MAY raise a static error if the value
1539: // of a URILiteral is of nonzero length and is not in the lexical
1540: // space of xs:anyURI, or if it is a string that represents a
1541: // relative URI as defined in [RFC2396]. err:XQST0046
1542: return str;
1543: }
1544:
1545: Expression parseExpr() throws java.io.IOException, SyntaxException {
1546: return parseExprSingle();
1547: }
1548:
1549: final Expression parseExprSingle() throws java.io.IOException,
1550: SyntaxException {
1551: int startLine = curLine;
1552: int startColumn = curColumn;
1553: peekOperand();
1554: switch (curToken) {
1555: // FIXME old code tweaked line/column
1556: // as in:
1557: // maybeSetLine(exp, startLine, startColumn - 3);
1558:
1559: case IF_LPAREN_TOKEN:
1560: return parseIfExpr();
1561: case TYPESWITCH_LPAREN_TOKEN:
1562: return parseTypeSwitch();
1563: case FOR_DOLLAR_TOKEN:
1564: return parseFLWRExpression(true);
1565: case LET_DOLLAR_TOKEN:
1566: return parseFLWRExpression(false);
1567: case SOME_DOLLAR_TOKEN:
1568: return parseQuantifiedExpr(false);
1569: case EVERY_DOLLAR_TOKEN:
1570: return parseQuantifiedExpr(true);
1571: default:
1572: return parseBinaryExpr(priority(OP_OR));
1573: }
1574: }
1575:
1576: Expression parseBinaryExpr(int prio) throws java.io.IOException,
1577: SyntaxException {
1578: Expression exp = parseUnaryExpr();
1579: for (;;) {
1580: int token = peekOperator();
1581: if (token == EOL_TOKEN
1582: // Following makes for better error handling.
1583: || (token == OP_LSS && peek() == '/'))
1584: return exp;
1585: int tokPriority = priority(token);
1586: if (tokPriority < prio)
1587: return exp;
1588: char saveReadState = pushNesting('%');
1589: getRawToken();
1590: popNesting(saveReadState);
1591: if (token >= OP_INSTANCEOF && token <= OP_CAST_AS) {
1592: if (token == OP_CAST_AS || token == OP_CASTABLE_AS)
1593: parseContext = 'C';
1594: Expression type = parseDataType();
1595: parseContext = '\0';
1596: Expression[] args = new Expression[2];
1597: Expression func;
1598: switch (token) {
1599: case OP_INSTANCEOF:
1600: args[0] = exp;
1601: args[1] = type;
1602: func = makeFunctionExp("gnu.xquery.lang.XQParser",
1603: "instanceOf");
1604: break;
1605: case OP_CASTABLE_AS:
1606: args[0] = exp;
1607: args[1] = type;
1608: func = new ReferenceExp(
1609: XQResolveNames.castableAsDecl);
1610: break;
1611: case OP_TREAT_AS:
1612: args[0] = type;
1613: args[1] = exp;
1614: func = makeFunctionExp("gnu.xquery.lang.XQParser",
1615: "treatAs");
1616: break;
1617: default: // i.e. case OP_CAST_AS:
1618: args[0] = type;
1619: args[1] = exp;
1620: func = new ReferenceExp(XQResolveNames.castAsDecl);
1621: break;
1622: }
1623: exp = new ApplyExp(func, args);
1624: } else if (token == OP_INSTANCEOF) {
1625: Expression[] args = { exp, parseDataType() };
1626: exp = new ApplyExp(makeFunctionExp(
1627: "gnu.xquery.lang.XQParser", "instanceOf"), args);
1628: } else {
1629: Expression exp2 = parseBinaryExpr(tokPriority + 1);
1630: if (token == OP_AND)
1631: exp = new IfExp(booleanValue(exp),
1632: booleanValue(exp2), XQuery.falseExp);
1633: else if (token == OP_OR)
1634: exp = new IfExp(booleanValue(exp), XQuery.trueExp,
1635: booleanValue(exp2));
1636: else
1637: exp = makeBinary(token, exp, exp2);
1638: }
1639: }
1640: }
1641:
1642: Expression parseUnaryExpr() throws java.io.IOException,
1643: SyntaxException {
1644: Expression exp;
1645: if (curToken == OP_SUB || curToken == OP_ADD) {
1646: int op = curToken;
1647: getRawToken();
1648: exp = parseUnaryExpr();
1649: Expression func = makeFunctionExp(
1650: "gnu.xquery.util.ArithOp", op == OP_ADD ? "plus"
1651: : "minus", op == OP_ADD ? "+" : "-");
1652: exp = new ApplyExp(func, new Expression[] { exp });
1653: } else
1654: exp = parseUnionExpr();
1655: return exp;
1656: }
1657:
1658: Expression parseUnionExpr() throws java.io.IOException,
1659: SyntaxException {
1660: Expression exp = parseIntersectExceptExpr();
1661: for (;;) {
1662: int op = peekOperator();
1663: if (op != OP_UNION)
1664: break;
1665: getRawToken();
1666: Expression exp2 = parseIntersectExceptExpr();
1667: exp = makeBinary(op, exp, exp2);
1668: }
1669: return exp;
1670: }
1671:
1672: Expression parseIntersectExceptExpr() throws java.io.IOException,
1673: SyntaxException {
1674: Expression exp = parsePathExpr();
1675: for (;;) {
1676: int op = peekOperator();
1677: if (op != OP_INTERSECT && op != OP_EXCEPT)
1678: break;
1679: getRawToken();
1680: Expression exp2 = parsePathExpr();
1681: exp = makeBinary(op, exp, exp2);
1682: }
1683: return exp;
1684: }
1685:
1686: Expression parsePathExpr() throws java.io.IOException,
1687: SyntaxException {
1688: Expression step1;
1689: if (curToken == '/' || curToken == SLASHSLASH_TOKEN) {
1690: Declaration dotDecl = lexical.lookup(DOT_VARNAME, false);
1691: Expression dot;
1692: if (dotDecl == null)
1693: dot = syntaxError("context item is undefined",
1694: "XPDY0002");
1695: else
1696: dot = new ReferenceExp(DOT_VARNAME, dotDecl);
1697: step1 = new ApplyExp(ClassType.make(
1698: "gnu.xquery.util.NodeUtils").getDeclaredMethod(
1699: "rootDocument", 1), new Expression[] { dot });
1700: int next = skipSpace(nesting != 0);
1701: unread(next);
1702: if (next < 0 || next == ')' || next == '}') {
1703: getRawToken();
1704: return step1;
1705: }
1706: } else
1707: step1 = parseStepExpr();
1708: return parseRelativePathExpr(step1);
1709: }
1710:
1711: /** Returns an expression that evaluates to a Symbol.
1712: * The expression will normally be constant
1713: * folded to a Symbol, but we cannot do that yet. */
1714: Expression parseNameTest(boolean attribute)
1715: throws java.io.IOException, SyntaxException {
1716: String local = null, prefix = null;
1717: if (curToken == QNAME_TOKEN) {
1718: int colon = tokenBufferLength;
1719: while (tokenBuffer[--colon] != ':')
1720: ;
1721: prefix = new String(tokenBuffer, 0, colon);
1722: colon++;
1723: local = new String(tokenBuffer, colon, tokenBufferLength
1724: - colon);
1725: } else if (curToken == OP_MUL) {
1726: int next = read();
1727: local = ElementType.MATCH_ANY_LOCALNAME;
1728: if (next != ':')
1729: unread(next);
1730: else {
1731: next = read();
1732: if (next < 0)
1733: eofError("unexpected end-of-file after '*:'");
1734: if (XName.isNameStart((char) next)) {
1735: unread();
1736: getRawToken();
1737: if (curToken != NCNAME_TOKEN)
1738: syntaxError("invalid name test");
1739: else
1740: local = new String(tokenBuffer, 0,
1741: tokenBufferLength).intern();
1742: } else if (next != '*')
1743: syntaxError("missing local-name after '*:'");
1744: }
1745: return QuoteExp.getInstance(new Symbol(null, local));
1746: } else if (curToken == NCNAME_TOKEN) {
1747: local = new String(tokenBuffer, 0, tokenBufferLength);
1748: if (attribute)
1749: return new QuoteExp(Namespace.EmptyNamespace
1750: .getSymbol(local.intern()));
1751: prefix = null;
1752: } else if (curToken == NCNAME_COLON_TOKEN) {
1753: prefix = new String(tokenBuffer, 0, tokenBufferLength);
1754: int next = read();
1755: if (next != '*')
1756: syntaxError("invalid characters after 'NCName:'");
1757: local = ElementType.MATCH_ANY_LOCALNAME;
1758: }
1759: if (prefix != null)
1760: prefix = prefix.intern();
1761: Expression[] args = new Expression[3];
1762: args[0] = new ApplyExp(new ReferenceExp(
1763: XQResolveNames.resolvePrefixDecl),
1764: new Expression[] { QuoteExp.getInstance(prefix) });
1765: args[1] = new QuoteExp(local == null ? "" : local);
1766: args[2] = new QuoteExp(prefix);
1767: ApplyExp make = new ApplyExp(Compilation.typeSymbol
1768: .getDeclaredMethod("make", 3), args);
1769: make.setFlag(ApplyExp.INLINE_IF_CONSTANT);
1770: return make;
1771: }
1772:
1773: Expression parseNodeTest(int axis) throws java.io.IOException,
1774: SyntaxException {
1775: int token = peekOperand();
1776: Expression[] args = new Expression[1];
1777:
1778: Expression etype = parseMaybeKindTest();
1779:
1780: if (etype != null) {
1781: args[0] = etype;
1782: } else if (curToken == NCNAME_TOKEN || curToken == QNAME_TOKEN
1783: || curToken == NCNAME_COLON_TOKEN || curToken == OP_MUL) {
1784: args[0] = makeNamedNodeType(axis == AXIS_ATTRIBUTE,
1785: parseNameTest(axis == AXIS_ATTRIBUTE));
1786: } else if (axis >= 0)
1787: return syntaxError("unsupported axis '" + axisNames[axis]
1788: + "::'");
1789: else
1790: return null;
1791:
1792: Declaration dotDecl = lexical.lookup(DOT_VARNAME, false);
1793: Expression dot;
1794: if (dotDecl == null)
1795: dot = syntaxError(
1796: "node test when context item is undefined",
1797: "XPDY0002");
1798: else
1799: dot = new ReferenceExp(DOT_VARNAME, dotDecl);
1800: if (etype == null)
1801: getRawToken();
1802:
1803: Expression makeAxisStep;
1804: if (axis == AXIS_CHILD || axis == -1)
1805: makeAxisStep = makeChildAxisStep;
1806: else if (axis == AXIS_DESCENDANT)
1807: makeAxisStep = makeDescendantAxisStep;
1808: else {
1809: String axisName;
1810: switch (axis) {
1811: case AXIS_DESCENDANT_OR_SELF:
1812: axisName = "DescendantOrSelf";
1813: break;
1814: case AXIS_SELF:
1815: axisName = "Self";
1816: break;
1817: case AXIS_PARENT:
1818: axisName = "Parent";
1819: break;
1820: case AXIS_ANCESTOR:
1821: axisName = "Ancestor";
1822: break;
1823: case AXIS_ANCESTOR_OR_SELF:
1824: axisName = "AncestorOrSelf";
1825: break;
1826: case AXIS_FOLLOWING:
1827: axisName = "Following";
1828: break;
1829: case AXIS_FOLLOWING_SIBLING:
1830: axisName = "FollowingSibling";
1831: break;
1832: case AXIS_PRECEDING:
1833: axisName = "Preceding";
1834: break;
1835: case AXIS_PRECEDING_SIBLING:
1836: axisName = "PrecedingSibling";
1837: break;
1838: case AXIS_ATTRIBUTE:
1839: axisName = "Attribute";
1840: break;
1841: default:
1842: throw new Error();
1843: }
1844: makeAxisStep = QuoteExp.getInstance(new PrimProcedure(
1845: "gnu.kawa.xml." + axisName + "Axis", "make", 1));
1846: }
1847: ApplyExp mkAxis = new ApplyExp(makeAxisStep, args);
1848: mkAxis.setFlag(ApplyExp.INLINE_IF_CONSTANT);
1849: return new ApplyExp(mkAxis, new Expression[] { dot });
1850: }
1851:
1852: public static QuoteExp makeChildAxisStep = QuoteExp
1853: .getInstance(new PrimProcedure("gnu.kawa.xml.ChildAxis",
1854: "make", 1));
1855: public static QuoteExp makeDescendantAxisStep = QuoteExp
1856: .getInstance(new PrimProcedure(
1857: "gnu.kawa.xml.DescendantAxis", "make", 1));
1858:
1859: Expression parseRelativePathExpr(Expression exp)
1860: throws java.io.IOException, SyntaxException {
1861: // If the previous operator was '//', then the corresponding E1.
1862: Expression beforeSlashSlash = null;
1863:
1864: while (curToken == '/' || curToken == SLASHSLASH_TOKEN) {
1865: boolean descendants = curToken == SLASHSLASH_TOKEN;
1866:
1867: LambdaExp lexp = new LambdaExp(3);
1868: Declaration dotDecl = lexp.addDeclaration(DOT_VARNAME);
1869: dotDecl.setFlag(Declaration.IS_SINGLE_VALUE);
1870: dotDecl.setType(NodeType.anyNodeTest);
1871: dotDecl.noteValue(null); // Does not have a known value.
1872: lexp.addDeclaration(POSITION_VARNAME, LangPrimType.intType);
1873: lexp.addDeclaration(LAST_VARNAME, LangPrimType.intType);
1874: comp.push(lexp);
1875: if (descendants) {
1876: curToken = '/';
1877: Expression dot = new ReferenceExp(DOT_VARNAME, dotDecl);
1878: Expression[] args = { dot };
1879: TreeScanner op = DescendantOrSelfAxis.anyNode;
1880: lexp.body = new ApplyExp(op, args);
1881: beforeSlashSlash = exp;
1882: } else {
1883: getRawToken();
1884: Expression exp2 = parseStepExpr();
1885:
1886: // Optimize: 'E1//child::TEST' to 'E1/descendant::TEST'
1887: Expression func;
1888: ApplyExp aexp;
1889: if (beforeSlashSlash != null
1890: && exp2 instanceof ApplyExp
1891: && (func = ((ApplyExp) exp2).getFunction()) instanceof ApplyExp
1892: && (aexp = (ApplyExp) func).getFunction() == makeChildAxisStep) {
1893: aexp.setFunction(makeDescendantAxisStep);
1894: exp = beforeSlashSlash;
1895: }
1896:
1897: lexp.body = exp2;
1898: beforeSlashSlash = null;
1899: }
1900: comp.pop(lexp);
1901:
1902: /*
1903: if (lexp.body instanceof ApplyExp)
1904: {
1905: // Optimize the case of a simple name step.
1906: ApplyExp aexp = (ApplyExp) lexp.body;
1907: Expression func = aexp.getFunction();
1908: Expression[] args = aexp.getArgs();
1909: if (false
1910: && func == funcNamedChildren && args.length==2
1911: && args[0] instanceof ReferenceExp
1912: && ((ReferenceExp) args[0]).getBinding() == decl)
1913: {
1914: args[0] = exp;
1915: if (descendants)
1916: func = funcNamedDescendants;
1917: exp = new ApplyExp (func, args);
1918: handled = true;
1919: }
1920: else if (func == funcForwardFilter && args.length==2
1921: && args[0] instanceof ApplyExp
1922: && descendants)
1923: {
1924: ApplyExp xapp = (ApplyExp) args[0];
1925: Expression[] xargs = xapp.getArgs();
1926: if (xapp.getFunction() == funcNamedChildren
1927: && xargs.length == 2
1928: && ((ReferenceExp) xargs[0]).getBinding() == decl)
1929: {
1930: xapp.setFunction(funcNamedDescendants);
1931: }
1932: }
1933: }
1934: */
1935:
1936: Expression[] args = new Expression[] { exp, lexp };
1937: exp = new ApplyExp(RelativeStep.relativeStep, args);
1938: }
1939: return exp;
1940: }
1941:
1942: Expression parseStepExpr() throws java.io.IOException,
1943: SyntaxException {
1944: int axis;
1945: if (curToken == '.' || curToken == DOTDOT_TOKEN) {
1946: axis = curToken == '.' ? AXIS_SELF : AXIS_PARENT;
1947: getRawToken();
1948: Declaration dotDecl = lexical.lookup(DOT_VARNAME, false);
1949: Expression exp;
1950: if (dotDecl == null)
1951: exp = syntaxError("context item is undefined",
1952: "XPDY0002");
1953: else
1954: exp = new ReferenceExp(DOT_VARNAME, dotDecl);
1955: if (axis == AXIS_PARENT) {
1956: Expression[] args = { exp };
1957: exp = new ApplyExp(ParentAxis
1958: .make(NodeType.anyNodeTest), args);
1959: }
1960: // Note that '..' is an AbbrevReverseStep,
1961: // but '.' is a FilterExpr - and hence not a valid ForwardStep.
1962: return parseStepQualifiers(exp, axis == AXIS_SELF ? -1
1963: : axis);
1964: }
1965: axis = peekOperand() - OP_AXIS_FIRST;
1966: Expression unqualifiedStep;
1967: if (axis >= 0 && axis < COUNT_OP_AXIS) {
1968: getRawToken();
1969: unqualifiedStep = parseNodeTest(axis);
1970: } else if (curToken == '@') {
1971: getRawToken();
1972: axis = AXIS_ATTRIBUTE;
1973: unqualifiedStep = parseNodeTest(axis);
1974: } else if (curToken == OP_ATTRIBUTE) {
1975: axis = AXIS_ATTRIBUTE;
1976: unqualifiedStep = parseNodeTest(axis);
1977: } else {
1978: unqualifiedStep = parseNodeTest(-1);
1979: if (unqualifiedStep != null) {
1980: axis = AXIS_CHILD;
1981: } else {
1982: axis = -1;
1983: unqualifiedStep = parsePrimaryExpr();
1984: }
1985: }
1986: return parseStepQualifiers(unqualifiedStep, axis);
1987: }
1988:
1989: Expression parseStepQualifiers(Expression exp, int axis)
1990: throws java.io.IOException, SyntaxException {
1991: for (;;) {
1992: if (curToken == '[') {
1993: int startLine = getLineNumber() + 1;
1994: int startColumn = getColumnNumber() + 1;
1995: int saveSeenPosition = seenPosition;
1996: int saveSawLast = seenLast;
1997: getRawToken();
1998: LambdaExp lexp = new LambdaExp(3);
1999: maybeSetLine(lexp, startLine, startColumn);
2000: Declaration dot = lexp.addDeclaration(DOT_VARNAME);
2001: if (axis >= 0)
2002: dot.setType(NodeType.anyNodeTest);
2003: else
2004: dot.setType(SingletonType.getInstance());
2005: lexp.addDeclaration(POSITION_VARNAME, Type.int_type);
2006: lexp.addDeclaration(LAST_VARNAME, Type.int_type);
2007: comp.push(lexp);
2008: dot.noteValue(null);
2009: Expression cond = parseExprSequence(']', false);
2010: if (curToken == EOF_TOKEN)
2011: eofError("missing ']' - unexpected end-of-file");
2012: char kind;
2013: Procedure valuesFilter;
2014: if (axis < 0) {
2015: kind = 'P';
2016: valuesFilter = ValuesFilter.exprFilter;
2017: } else if (axis == AXIS_ANCESTOR
2018: || axis == AXIS_ANCESTOR_OR_SELF
2019: || axis == AXIS_PARENT
2020: || axis == AXIS_PRECEDING
2021: || axis == AXIS_PRECEDING_SIBLING) {
2022: kind = 'R';
2023: valuesFilter = ValuesFilter.reverseFilter;
2024: } else {
2025: kind = 'F';
2026: valuesFilter = ValuesFilter.forwardFilter;
2027: }
2028: /*)
2029: boolean sawPosition = seenPosition > saveSeenPosition;
2030: boolean sawLast = seenLast > saveSeenLast;
2031: */
2032: maybeSetLine(cond, startLine, startColumn);
2033: comp.pop(lexp);
2034: lexp.body = cond;
2035: getRawToken();
2036: Expression[] args = { exp, lexp };
2037: exp = new ApplyExp(valuesFilter, args);
2038: }
2039: /*
2040: else if (curToken == ARROW_TOKEN)
2041: ...;
2042: */
2043: else {
2044: return exp;
2045: }
2046: }
2047: }
2048:
2049: /**
2050: * Parse a PrimaryExpr.
2051: * @return an Expression.
2052: */
2053: Expression parsePrimaryExpr() throws java.io.IOException,
2054: SyntaxException {
2055: Expression exp = parseMaybePrimaryExpr();
2056: if (exp == null) {
2057: exp = syntaxError("missing expression");
2058: if (curToken != EOF_TOKEN)
2059: getRawToken();
2060: return exp;
2061: }
2062: return exp;
2063: }
2064:
2065: void parseEntityOrCharRef() throws java.io.IOException,
2066: SyntaxException {
2067: int next = read();
2068: if (next == '#') {
2069: int base;
2070: next = read();
2071: if (next == 'x') {
2072: base = 16;
2073: next = read();
2074: } else
2075: base = 10;
2076: int value = 0;
2077: while (next >= 0) {
2078: char ch = (char) next;
2079: int digit = Character.digit((char) ch, base);
2080: if (digit < 0)
2081: break;
2082: if (value >= 0x8000000)
2083: break; // Overflow likely.
2084: value = value * base;
2085: value += digit;
2086: next = read();
2087: }
2088: if (next != ';') {
2089: unread();
2090: error("invalid character reference");
2091: }
2092: // See definition of 'Char' in XML 1.1 2nd ed Specification.
2093: else if ((value > 0 && value <= 0xD7FF)
2094: || (value >= 0xE000 && value <= 0xFFFD)
2095: || (value >= 0x10000 && value <= 0x10FFFF))
2096: tokenBufferAppend(value);
2097: else
2098: error('e', "invalid character value " + value,
2099: "XQST0090");
2100: } else {
2101: int saveLength = tokenBufferLength;
2102: while (next >= 0) {
2103: char ch = (char) next;
2104: if (!XName.isNamePart(ch))
2105: break;
2106: tokenBufferAppend(ch);
2107: next = read();
2108: }
2109: if (next != ';') {
2110: unread();
2111: error("invalid entity reference");
2112: return;
2113: }
2114: String ref = new String(tokenBuffer, saveLength,
2115: tokenBufferLength - saveLength);
2116: tokenBufferLength = saveLength;
2117: appendNamedEntity(ref);
2118: }
2119: }
2120:
2121: /** Count of enclosed expressions seen in element or attribute content. */
2122: int enclosedExpressionsSeen;
2123:
2124: static Expression makeText = makeFunctionExp(
2125: "gnu.kawa.xml.MakeText", "makeText");
2126:
2127: /** Parse ElementContent (delimiter == '<') or AttributeContent (otherwise).
2128: * @param delimiter is '<' if parsing ElementContent, is either '\'' or
2129: * '\"' if parsing AttributeContent depending on the starting quote
2130: * @param result a buffer to place the resulting Expressions.
2131: */
2132: void parseContent(char delimiter, Vector result)
2133: throws java.io.IOException, SyntaxException {
2134: tokenBufferLength = 0;
2135: int startSize = result.size();
2136: int prevEnclosed = startSize - 1;
2137: boolean skipBoundarySpace = !boundarySpacePreserve
2138: && delimiter == '<';
2139: boolean skippable = skipBoundarySpace;
2140: for (;;) {
2141: int next = read();
2142: if (next == delimiter) {
2143: if (delimiter == '<') {
2144: next = read();
2145: Expression text = null;
2146: if (tokenBufferLength > 0) {
2147: String str = new String(tokenBuffer, 0,
2148: tokenBufferLength);
2149: Expression[] args = { new QuoteExp(str) };
2150: text = new ApplyExp(makeText, args);
2151: }
2152: tokenBufferLength = 0;
2153: if (next == '/') {
2154: if (text != null && !skippable)
2155: result.addElement(text);
2156: break;
2157: }
2158: Expression content = parseXMLConstructor(next, true);
2159: boolean isCDATA = false;
2160: boolean emptyCDATA = false;
2161: if (content instanceof ApplyExp) {
2162: ApplyExp aexp = (ApplyExp) content;
2163: if (aexp.getFunction() == makeCDATA) {
2164: isCDATA = true;
2165: String str = (String) aexp.getArg(0)
2166: .valueIfConstant();
2167: emptyCDATA = str != null
2168: && str.length() == 0;
2169: }
2170: }
2171: if (text != null && (!skippable || isCDATA))
2172: result.addElement(text);
2173: if (isCDATA)
2174: skippable = false;
2175: else
2176: skippable = skipBoundarySpace;
2177: if (!emptyCDATA)
2178: result.addElement(content);
2179: tokenBufferLength = 0;
2180: continue;
2181: } else if (checkNext(delimiter)) {
2182: tokenBufferAppend(delimiter);
2183: continue;
2184: }
2185: }
2186: if (next == delimiter || next < 0 || next == '{') {
2187: addText: {
2188: String text;
2189: if (tokenBufferLength > 0 && !skippable)
2190: text = new String(tokenBuffer, 0,
2191: tokenBufferLength);
2192: else if (next == '{'
2193: && prevEnclosed == result.size())
2194: // Handle the <a>{E1}{E2}</a> case - we must insert a
2195: // joiner between E1 ad E2 to avoid a space being inserted.
2196: text = "";
2197: else
2198: break addText; // Don't need to add anything.
2199: Expression[] args = { new QuoteExp(text) };
2200: result.addElement(new ApplyExp(makeText, args));
2201: }
2202: tokenBufferLength = 0;
2203: if (next == delimiter)
2204: break;
2205: else if (next < 0)
2206: eofError("unexpected end-of-file");
2207: else // if (next == '{')
2208: {
2209: next = read();
2210: if (next == '{') {
2211: tokenBufferAppend('{');
2212: skippable = false;
2213: } else {
2214: unread(next);
2215: enclosedExpressionsSeen++;
2216: Expression exp = parseEnclosedExpr();
2217: result.addElement(exp);
2218: tokenBufferLength = 0;
2219: prevEnclosed = result.size();
2220: skippable = skipBoundarySpace;
2221: }
2222: }
2223: } else if (next == '}') {
2224: next = read();
2225: if (next == '}') {
2226: tokenBufferAppend('}');
2227: skippable = false;
2228: } else {
2229: error("unexpected '}' in element content");
2230: unread(next);
2231: }
2232: } else if (next == '&') {
2233: parseEntityOrCharRef();
2234: skippable = false;
2235: } else {
2236: if (delimiter != '<'
2237: && (next == '\t' || next == '\n' || next == '\r'))
2238: next = ' ';
2239: if (next == '<')
2240: error('e',
2241: "'<' must be quoted in a direct attribute value");
2242: if (skippable)
2243: skippable = Character.isWhitespace((char) next);
2244: tokenBufferAppend((char) next);
2245: }
2246: }
2247: }
2248:
2249: /** Parse an EnclosedExpr.
2250: * Assume the '{' has been read.
2251: */
2252: Expression parseEnclosedExpr() throws java.io.IOException,
2253: SyntaxException {
2254: String saveErrorIfComment = errorIfComment;
2255: errorIfComment = null;
2256: char saveReadState = pushNesting('{');
2257: peekNonSpace("unexpected end-of-file after '{'");
2258: int startLine = getLineNumber() + 1;
2259: int startColumn = getColumnNumber() + 1;
2260: getRawToken();
2261: Expression exp = parseExpr();
2262: for (;;) {
2263: if (curToken == '}')
2264: break;
2265: if (curToken == EOF_TOKEN || curToken == ')'
2266: || curToken == ']') {
2267: exp = syntaxError("missing '}'");
2268: break;
2269: }
2270: if (curToken != ',')
2271: exp = syntaxError("missing '}' or ','");
2272: else
2273: getRawToken();
2274:
2275: exp = makeExprSequence(exp, parseExpr());
2276:
2277: }
2278: maybeSetLine(exp, startLine, startColumn);
2279: popNesting(saveReadState);
2280: errorIfComment = saveErrorIfComment;
2281: return exp;
2282: }
2283:
2284: /** Coerce the value of an expresison to a boolean value. */
2285: public static Expression booleanValue(Expression exp) {
2286: Expression[] args = { exp };
2287: Expression string = makeFunctionExp(
2288: "gnu.xquery.util.BooleanValue", "booleanValue");
2289: return new ApplyExp(string, args);
2290: }
2291:
2292: static final Expression makeCDATA = makeFunctionExp(
2293: "gnu.kawa.xml.MakeCDATA", "makeCDATA");
2294:
2295: /** Parse an ElementConstructor or other constructs starting with '<'.
2296: * Assume initial '<' has been processed.
2297: * @param next next character (after '<').
2298: */
2299: Expression parseXMLConstructor(int next, boolean inElementContent)
2300: throws java.io.IOException, SyntaxException {
2301: Expression exp;
2302: if (next == '!') {
2303: next = read();
2304: if (next == '-' && peek() == '-') {
2305: skip();
2306: getDelimited("-->");
2307: boolean bad = false;
2308: int i = tokenBufferLength;
2309: boolean sawHyphen = true;
2310: while (--i >= 0) {
2311: boolean curHyphen = tokenBuffer[i] == '-';
2312: if (sawHyphen && curHyphen) {
2313: bad = true;
2314: break;
2315: }
2316: sawHyphen = curHyphen;
2317: }
2318: if (bad)
2319: exp = syntaxError("consecutive or final hyphen in XML comment");
2320: else {
2321: Expression[] args = { new QuoteExp(new String(
2322: tokenBuffer, 0, tokenBufferLength)) };
2323: exp = new ApplyExp(makeFunctionExp(
2324: "gnu.kawa.xml.CommentConstructor",
2325: "commentConstructor"), args);
2326: }
2327: } else if (next == '[' && read() == 'C' && read() == 'D'
2328: && read() == 'A' && read() == 'T' && read() == 'A'
2329: && read() == '[') {
2330: if (!inElementContent)
2331: error('e',
2332: "CDATA section must be in element content");
2333: getDelimited("]]>");
2334: Expression[] args = { new QuoteExp(new String(
2335: tokenBuffer, 0, tokenBufferLength)) };
2336: exp = new ApplyExp(makeCDATA, args);
2337: } else
2338: exp = syntaxError("'<!' must be followed by '--' or '[CDATA['");
2339: } else if (next == '?') {
2340: next = peek();
2341: if (next < 0 || !XName.isNameStart((char) next)
2342: || getRawToken() != NCNAME_TOKEN)
2343: syntaxError("missing target after '<?'");
2344: String target = new String(tokenBuffer, 0,
2345: tokenBufferLength);
2346: int nspaces = 0;
2347: for (;;) {
2348: int ch = read();
2349: if (ch < 0)
2350: break;
2351: if (!Character.isWhitespace((char) ch)) {
2352: unread();
2353: break;
2354: }
2355: nspaces++;
2356: }
2357: getDelimited("?>");
2358: if (nspaces == 0 && tokenBufferLength > 0)
2359: syntaxError("target must be followed by space or '?>'");
2360: String content = new String(tokenBuffer, 0,
2361: tokenBufferLength);
2362: Expression[] args = { new QuoteExp(target),
2363: new QuoteExp(content) };
2364: exp = new ApplyExp(makeFunctionExp(
2365: "gnu.kawa.xml.MakeProcInst", "makeProcInst"), args);
2366: } else if (next < 0 || !XName.isNameStart((char) next))
2367: exp = syntaxError("expected QName after '<'");
2368: else {
2369: unread(next);
2370: getRawToken();
2371: char saveReadState = pushNesting('<');
2372: exp = parseElementConstructor();
2373: if (!inElementContent)
2374: exp = wrapWithBaseUri(exp);
2375: popNesting(saveReadState);
2376: }
2377: return exp;
2378: }
2379:
2380: /** Generate code to cast argument to a QName
2381: * (which is implemented using <code>Symbol</code>). */
2382: static ApplyExp castQName(Expression value) {
2383: return new ApplyExp(
2384: new ReferenceExp(XQResolveNames.xsQNameDecl),
2385: new Expression[] { value });
2386: }
2387:
2388: /** Parse ElementConstructor.
2389: * Assume initial {@code '<'} has been processed,
2390: * and we're looking at the next token..
2391: * Reads through end of the end tag. FIXME
2392: */
2393: Expression parseElementConstructor() throws java.io.IOException,
2394: SyntaxException {
2395: // Note that we cannot do namespace resolution at parse time,
2396: // because of constructs like this: <a x="{$x:v}" xmlns:x="xx"/>
2397: // Instead we defer namespaced lookup until XQResolveNames. (Mostly -
2398: // some places still incorrectly do premature namespace resolution.)
2399: String startTag = new String(tokenBuffer, 0, tokenBufferLength);
2400: Vector vec = new Vector();
2401: Expression[] args;
2402: vec.addElement(castQName(new QuoteExp(startTag)));
2403: errorIfComment = "comment not allowed in element start tag";
2404: NamespaceBinding nsBindings = null;
2405: int ch;
2406: for (;;) {
2407: ch = skipSpace();
2408: if (ch < 0 || ch == '>' || ch == '/')
2409: break;
2410: unread(ch);
2411: getRawToken();
2412: int vecSize = vec.size();
2413: if (curToken != NCNAME_TOKEN && curToken != QNAME_TOKEN)
2414: break;
2415: String attrName = new String(tokenBuffer, 0,
2416: tokenBufferLength);
2417: int startLine = getLineNumber() + 1;
2418: int startColumn = getColumnNumber() + 1 - tokenBufferLength;
2419: String definingNamespace = null;
2420: if (curToken == NCNAME_TOKEN) {
2421: if (attrName.equals("xmlns"))
2422: definingNamespace = "";
2423: } else {
2424: if (attrName.startsWith("xmlns:"))
2425: definingNamespace = attrName.substring(6).intern();
2426: }
2427: Expression makeAttr = definingNamespace != null ? null
2428: : MakeAttribute.makeAttributeExp;
2429: vec.addElement(castQName(new QuoteExp(attrName)));
2430: ch = skipSpace();
2431: if (ch != '=') {
2432: errorIfComment = null;
2433: return syntaxError("missing '=' after attribute");
2434: }
2435: ch = skipSpace();
2436: int enclosedExpressionsStart = enclosedExpressionsSeen;
2437: if (ch == '{') {
2438: warnOldVersion("enclosed attribute value expression should be quoted");
2439: vec.addElement(parseEnclosedExpr());
2440: } else
2441: parseContent((char) ch, vec);
2442: int n = vec.size() - vecSize;
2443: if (definingNamespace != null) {
2444: String ns = "";
2445: if (n == 1)
2446: ns = "";
2447: else if (enclosedExpressionsSeen > enclosedExpressionsStart)
2448: syntaxError("enclosed expression not allowed in namespace declaration");
2449: else {
2450: Object x = vec.elementAt(vecSize + 1);
2451: ApplyExp ax;
2452: if (x instanceof ApplyExp
2453: && (ax = (ApplyExp) x).getFunction() == makeText)
2454: x = ax.getArg(0);
2455: ns = ((QuoteExp) x).getValue().toString().intern();
2456: }
2457: vec.setSize(vecSize);
2458: checkAllowedNamespaceDeclaration(definingNamespace, ns,
2459: true);
2460: if (definingNamespace == "")
2461: definingNamespace = null;
2462: for (NamespaceBinding nsb = nsBindings; nsb != null; nsb = nsb
2463: .getNext()) {
2464: if (nsb.getPrefix() == definingNamespace) {
2465: error(
2466: 'e',
2467: definingNamespace == null ? "duplicate default namespace declaration"
2468: : "duplicate namespace prefix '"
2469: + definingNamespace
2470: + '\'', "XQST0071");
2471: break;
2472: }
2473: }
2474: nsBindings = new NamespaceBinding(definingNamespace,
2475: ns == "" ? null : ns, nsBindings);
2476: } else {
2477: args = new Expression[n];
2478: for (int i = n; --i >= 0;)
2479: args[i] = (Expression) vec.elementAt(vecSize + i);
2480: vec.setSize(vecSize);
2481: ApplyExp aexp = new ApplyExp(makeAttr, args);
2482: maybeSetLine(aexp, startLine, startColumn);
2483: vec.addElement(aexp);
2484: }
2485: }
2486: errorIfComment = null;
2487: boolean empty = false;
2488: if (ch == '/') {
2489: ch = read();
2490: if (ch == '>')
2491: empty = true;
2492: else
2493: unread(ch);
2494: }
2495: if (!empty) {
2496: if (ch != '>')
2497: return syntaxError("missing '>' after start element");
2498: parseContent('<', vec);
2499: ch = peek();
2500: if (ch >= 0) {
2501: if (!XName.isNameStart((char) ch))
2502: return syntaxError("invalid tag syntax after '</'");
2503: getRawToken();
2504: String tag = new String(tokenBuffer, 0,
2505: tokenBufferLength);
2506: if (!(tag.equals(startTag)))
2507: return syntaxError("'<" + startTag
2508: + ">' closed by '</" + tag + ">'");
2509: errorIfComment = "comment not allowed in element end tag";
2510: ch = skipSpace();
2511: errorIfComment = null;
2512: }
2513: if (ch != '>')
2514: return syntaxError("missing '>' after end element");
2515: }
2516: args = new Expression[vec.size()];
2517: vec.copyInto(args);
2518: MakeElement mkElement = new MakeElement();
2519: mkElement.copyNamespacesMode = copyNamespacesMode;
2520: // Ths is just the chain of NamespaceBindings for namespace declaration
2521: // attributes from this immediate constructor. At resolve time we chain
2522: // this list onto the list from outer element constructors.
2523: mkElement.setNamespaceNodes(nsBindings);
2524: Expression result = new ApplyExp(new QuoteExp(mkElement), args);
2525: return result;
2526: }
2527:
2528: Expression wrapWithBaseUri(Expression exp) {
2529: if (getStaticBaseUri() == null)
2530: return exp;
2531: return new ApplyExp(MakeWithBaseUri.makeWithBaseUri,
2532: new Expression[] {
2533: new ApplyExp(new ReferenceExp(
2534: XQResolveNames.staticBaseUriDecl),
2535: Expression.noExpressions), exp })
2536: .setLine(exp);
2537: }
2538:
2539: /** Parse ParenthesizedExpr.
2540: *.When called, curToken should be pointing at a '(',
2541: * or a token which ends if a '(', such as IF_LPAREN_TOKEN.
2542: */
2543: Expression parseParenExpr() throws java.io.IOException,
2544: SyntaxException {
2545: getRawToken();
2546: char saveReadState = pushNesting('(');
2547: Expression exp = parseExprSequence(')', true);
2548: popNesting(saveReadState);
2549: if (curToken == EOF_TOKEN)
2550: eofError("missing ')' - unexpected end-of-file");
2551: return exp;
2552: }
2553:
2554: Expression parseExprSequence(int rightToken, boolean optional)
2555: throws java.io.IOException, SyntaxException {
2556: if (curToken == rightToken || curToken == EOF_TOKEN) {
2557: if (!optional)
2558: syntaxError("missing expression");
2559: return QuoteExp.voidExp;
2560: }
2561: Expression exp = null;
2562: for (;;) {
2563: Expression exp1 = parseExprSingle();
2564:
2565: exp = exp == null ? exp1 : makeExprSequence(exp, exp1);
2566: if (curToken == rightToken || curToken == EOF_TOKEN)
2567: break;
2568: if (nesting == 0 && curToken == EOL_TOKEN)
2569: return exp;
2570: if (curToken != ',')
2571: return syntaxError(rightToken == ')' ? "expected ')'"
2572: : "confused by syntax error");
2573: getRawToken();
2574: }
2575: return exp;
2576: }
2577:
2578: Expression parseTypeSwitch() throws java.io.IOException,
2579: SyntaxException {
2580: char save = pushNesting('t');
2581: Expression selector = parseParenExpr();
2582: getRawToken();
2583: Object varName = null;
2584: Declaration decl;
2585: Vector vec = new Vector();
2586: vec.addElement(selector);
2587: while (match("case")) {
2588: pushNesting('c');
2589: getRawToken();
2590: if (curToken == '$') {
2591: decl = parseVariableDeclaration();
2592: if (decl == null)
2593: return syntaxError("missing Variable after '$'");
2594: getRawToken();
2595: if (match("as"))
2596: getRawToken();
2597: else
2598: error('e', "missing 'as'");
2599: } else
2600: decl = new Declaration("(arg)");
2601: decl.setTypeExp(parseDataType());
2602: popNesting('t');
2603: LambdaExp lexp = new LambdaExp(1);
2604: lexp.addDeclaration(decl);
2605: if (match("return"))
2606: getRawToken();
2607: else
2608: error("missing 'return' after 'case'");
2609: comp.push(lexp);
2610: pushNesting('r');
2611: Expression caseExpr = parseExpr();
2612: lexp.body = caseExpr;
2613: popNesting('t');
2614: comp.pop(lexp);
2615: vec.addElement(lexp);
2616: }
2617:
2618: if (match("default")) {
2619: LambdaExp lexp = new LambdaExp(1);
2620: getRawToken();
2621:
2622: if (curToken == '$') {
2623: decl = parseVariableDeclaration();
2624: if (decl == null)
2625: return syntaxError("missing Variable after '$'");
2626: getRawToken();
2627: } else
2628: decl = new Declaration("(arg)");
2629: lexp.addDeclaration(decl);
2630:
2631: if (match("return"))
2632: getRawToken();
2633: else
2634: error("missing 'return' after 'default'");
2635: comp.push(lexp);
2636: Expression defaultExpr = parseExpr();
2637: lexp.body = defaultExpr;
2638: comp.pop(lexp);
2639: vec.addElement(lexp);
2640: } else {
2641: error(comp.isPedantic() ? 'e' : 'w',
2642: "no 'default' clause in 'typeswitch'", "XPST0003");
2643: }
2644: popNesting(save);
2645: Expression[] args = new Expression[vec.size()];
2646: vec.copyInto(args);
2647: return new ApplyExp(makeFunctionExp(
2648: "gnu.kawa.reflect.TypeSwitch", "typeSwitch"), args);
2649: }
2650:
2651: /**
2652: * Try to parse a PrimaryExpr.
2653: * @return an Expression, or null if no PrimaryExpr was seen.
2654: */
2655: Expression parseMaybePrimaryExpr() throws java.io.IOException,
2656: SyntaxException {
2657: int startLine = curLine;
2658: int startColumn = curColumn;
2659: int token = peekOperand();
2660: Expression exp;
2661: int c1, c2, c3;
2662: Vector vec;
2663: Expression[] args;
2664: switch (token) {
2665: case '(':
2666: exp = parseParenExpr();
2667: break;
2668:
2669: case PRAGMA_START_TOKEN:
2670: Stack extArgs = new Stack();
2671: for (;;) {
2672: getRawToken();
2673: Expression qname;
2674: if (curToken != QNAME_TOKEN && curToken != NCNAME_TOKEN)
2675: qname = syntaxError("missing pragma name");
2676: else
2677: qname = QuoteExp.getInstance(new String(
2678: tokenBuffer, 0, tokenBufferLength));
2679: extArgs.push(qname);
2680: StringBuffer sbuf = new StringBuffer();
2681: int ch;
2682: int spaces = -1;
2683: do {
2684: ch = read();
2685: spaces++;
2686: } while (ch >= 0 && Character.isWhitespace((char) ch));
2687: while (ch != '#' || peek() != ')') {
2688: if (ch < 0)
2689: eofError("pragma ended by end-of-file");
2690: if (spaces == 0)
2691: error("missing space between pragma and extension content");
2692: spaces = 1;
2693: sbuf.append((char) ch);
2694: ch = read();
2695: }
2696: read(); // skip ')'
2697: extArgs.push(QuoteExp.getInstance(sbuf.toString()));
2698: getRawToken();
2699: if (curToken != PRAGMA_START_TOKEN)
2700: break;
2701: }
2702: if (curToken == '{') {
2703: getRawToken();
2704: if (curToken != '}') {
2705: char saveReadState = pushNesting('{');
2706: extArgs.push(parseExprSequence('}', false));
2707: popNesting(saveReadState);
2708: if (curToken == EOF_TOKEN)
2709: eofError("missing '}' - unexpected end-of-file");
2710: }
2711: args = new Expression[extArgs.size()];
2712: extArgs.copyInto(args);
2713: exp = new ApplyExp(new ReferenceExp(
2714: XQResolveNames.handleExtensionDecl), args);
2715: } else
2716: exp = syntaxError("missing '{' after pragma");
2717: break;
2718:
2719: case '{':
2720: exp = syntaxError("saw unexpected '{' - assume you meant '('");
2721: parseEnclosedExpr();
2722: break;
2723:
2724: case OP_LSS:
2725: int next = read();
2726: if (next == '/') {
2727: getRawToken();
2728: String msg;
2729: if (curToken == NCNAME_TOKEN || curToken == QNAME_TOKEN
2730: || curToken == NCNAME_COLON_TOKEN)
2731: msg = "saw end tag '</"
2732: + new String(tokenBuffer, 0,
2733: tokenBufferLength)
2734: + ">' not in an element constructor";
2735: else
2736: msg = "saw end tag '</' not in an element constructor";
2737: curLine = startLine;
2738: curColumn = startColumn;
2739: exp = syntaxError(msg);
2740: while (curToken != OP_GRT && curToken != EOF_TOKEN
2741: && curToken != EOL_TOKEN)
2742: getRawToken();
2743: return exp;
2744: } else {
2745: exp = parseXMLConstructor(next, false);
2746: maybeSetLine(exp, startLine, startColumn);
2747: }
2748: break;
2749:
2750: case STRING_TOKEN:
2751: exp = new QuoteExp(new String(tokenBuffer, 0,
2752: tokenBufferLength).intern());
2753: break;
2754:
2755: case INTEGER_TOKEN:
2756: exp = new QuoteExp(IntNum.valueOf(tokenBuffer, 0,
2757: tokenBufferLength, 10, false));
2758: break;
2759:
2760: case DECIMAL_TOKEN:
2761: case DOUBLE_TOKEN:
2762: String str = new String(tokenBuffer, 0, tokenBufferLength);
2763: try {
2764: Object val;
2765: if (token == DECIMAL_TOKEN)
2766: val = new java.math.BigDecimal(str);
2767: else
2768: val = new java.lang.Double(str);
2769: exp = new QuoteExp(val);
2770: } catch (Throwable ex) {
2771: exp = syntaxError("invalid decimal literal: '" + str
2772: + "'");
2773: }
2774: break;
2775: case '$':
2776: Object name = parseVariable();
2777: if (name == null)
2778: return syntaxError("missing Variable");
2779: exp = new ReferenceExp(name);
2780: break;
2781: case FNAME_TOKEN:
2782: name = new String(tokenBuffer, 0, tokenBufferLength);
2783: char save = pushNesting('(');
2784: getRawToken();
2785: vec = new Vector(10);
2786: if (curToken != ')') {
2787: for (;;) {
2788: Expression arg = parseExpr();
2789: vec.addElement(arg);
2790: if (curToken == ')')
2791: break;
2792: if (curToken != ',')
2793: return syntaxError("missing ')' after function call");
2794: getRawToken();
2795: }
2796: }
2797: args = new Expression[vec.size()];
2798:
2799: vec.copyInto(args);
2800: ReferenceExp rexp = new ReferenceExp(name, null);
2801: rexp.setProcedureName(true);
2802: exp = new ApplyExp(rexp, args);
2803: maybeSetLine(exp, startLine, startColumn);
2804: popNesting(save);
2805: break;
2806:
2807: case ELEMENT_TOKEN:
2808: case ATTRIBUTE_TOKEN:
2809: case COMMENT_TOKEN:
2810: case DOCUMENT_TOKEN:
2811: case TEXT_TOKEN:
2812: case PI_TOKEN:
2813: getRawToken(); // Skip 'element'.
2814: vec = new Vector();
2815: Expression func;
2816:
2817: if (token == ELEMENT_TOKEN || token == ATTRIBUTE_TOKEN) {
2818: Expression element;
2819: if (curToken == NCNAME_TOKEN || curToken == QNAME_TOKEN)
2820: element = parseNameTest(token != ELEMENT_TOKEN);
2821: else if (curToken == '{')
2822: element = parseEnclosedExpr();
2823: else
2824: return syntaxError("missing element/attribute name");
2825: vec.addElement(castQName(element));
2826: if (token == ELEMENT_TOKEN) {
2827: MakeElement mk = new MakeElement();
2828: mk.copyNamespacesMode = copyNamespacesMode;
2829: func = new QuoteExp(mk);
2830: } else
2831: func = MakeAttribute.makeAttributeExp;
2832: getRawToken();
2833: } else if (token == DOCUMENT_TOKEN)
2834: func = makeFunctionExp(
2835: "gnu.kawa.xml.DocumentConstructor",
2836: "documentConstructor");
2837: else if (token == COMMENT_TOKEN)
2838: func = makeFunctionExp(
2839: "gnu.kawa.xml.CommentConstructor",
2840: "commentConstructor");
2841: else if (token == PI_TOKEN) {
2842: Expression target;
2843: if (curToken == NCNAME_TOKEN)
2844: target = new QuoteExp(new String(tokenBuffer, 0,
2845: tokenBufferLength).intern());
2846: else if (curToken == '{') {
2847: target = parseEnclosedExpr();
2848: } else {
2849: target = syntaxError("expected NCName or '{' after 'processing-instruction'");
2850: if (curToken != QNAME_TOKEN)
2851: return target;
2852: }
2853: vec.addElement(target);
2854: func = makeFunctionExp("gnu.kawa.xml.MakeProcInst",
2855: "makeProcInst");
2856: getRawToken();
2857: } else
2858: /* token == TEXT_TOKEN */
2859: func = makeFunctionExp("gnu.kawa.xml.MakeText",
2860: "makeText");
2861: char saveReadState = pushNesting('{');
2862: peekNonSpace("unexpected end-of-file after '{'");
2863: if (curToken != '{')
2864: return syntaxError("missing '{'");
2865: getRawToken();
2866: if (token == TEXT_TOKEN || token == COMMENT_TOKEN
2867: || token == PI_TOKEN)
2868: vec
2869: .addElement(parseExprSequence('}',
2870: token == PI_TOKEN));
2871: else if (curToken != '}') {
2872: vec.addElement(parseExpr());
2873: while (curToken == ',') {
2874: getRawToken();
2875: vec.addElement(parseExpr());
2876: }
2877: }
2878: popNesting(saveReadState);
2879: if (curToken != '}')
2880: return syntaxError("missing '}'");
2881: args = new Expression[vec.size()];
2882: vec.copyInto(args);
2883: exp = new ApplyExp(func, args);
2884: maybeSetLine(exp, startLine, startColumn);
2885: if (token == DOCUMENT_TOKEN || token == ELEMENT_TOKEN)
2886: exp = wrapWithBaseUri(exp);
2887: break;
2888:
2889: case ORDERED_LBRACE_TOKEN:
2890: case UNORDERED_LBRACE_TOKEN:
2891: getRawToken();
2892: exp = parseExprSequence('}', false);
2893: break;
2894:
2895: default:
2896: return null;
2897: }
2898: /*
2899: if (nesting == 0)
2900: {
2901: int ch = skipSpace(false);
2902: if (ch < 0 || ch == '\n' || ch == '\r')
2903: return exp;
2904: unread(ch);
2905: }
2906: */
2907: getRawToken();
2908: return exp;
2909: }
2910:
2911: public Expression parseIfExpr() throws java.io.IOException,
2912: SyntaxException {
2913: char saveReadState1 = pushNesting('i');
2914: getRawToken();
2915: char saveReadState2 = pushNesting('(');
2916: Expression cond = parseExprSequence(')', false);
2917: popNesting(saveReadState2);
2918: if (curToken == EOF_TOKEN)
2919: eofError("missing ')' - unexpected end-of-file");
2920: getRawToken();
2921: if (!match("then"))
2922: syntaxError("missing 'then'");
2923: else
2924: getRawToken();
2925: Expression thenPart = parseExpr();
2926: if (!match("else"))
2927: syntaxError("missing 'else'");
2928: else
2929: getRawToken();
2930: popNesting(saveReadState1);
2931: Expression elsePart = parseExpr();
2932: return new IfExp(booleanValue(cond), thenPart, elsePart);
2933: }
2934:
2935: public boolean match(String word) {
2936: if (curToken != NCNAME_TOKEN)
2937: return false;
2938: int len = word.length();
2939: if (tokenBufferLength != len)
2940: return false;
2941: for (int i = len; --i >= 0;) {
2942: char cs = word.charAt(i);
2943: char cb = tokenBuffer[i];
2944: if (cs != cb)
2945: return false;
2946: }
2947: return true;
2948: }
2949:
2950: /** Parse a Variable. */
2951: public Object parseVariable() throws java.io.IOException,
2952: SyntaxException {
2953: if (curToken == '$')
2954: getRawToken();
2955: else
2956: syntaxError("missing '$' before variable name");
2957: String str = new String(tokenBuffer, 0, tokenBufferLength);
2958: // Note we cannot do namespace resolution here - see comment in
2959: // parseElementConstructor.
2960: if (curToken == QNAME_TOKEN)
2961: return str;
2962: else if (curToken == NCNAME_TOKEN)
2963: return Namespace.EmptyNamespace.getSymbol(str.intern());
2964: else
2965: return null;
2966: }
2967:
2968: public Declaration parseVariableDeclaration()
2969: throws java.io.IOException, SyntaxException {
2970: Object name = parseVariable();
2971: if (name == null)
2972: return null;
2973: Declaration decl = new Declaration(name);
2974: maybeSetLine(decl, getLineNumber() + 1, getColumnNumber() + 1
2975: - tokenBufferLength);
2976: return decl;
2977: }
2978:
2979: public Expression parseFLWRExpression(boolean isFor)
2980: throws java.io.IOException, SyntaxException {
2981: int flworDeclsSave = flworDeclsFirst;
2982: flworDeclsFirst = flworDeclsCount;
2983: Expression exp = parseFLWRInner(isFor);
2984:
2985: if (match("order")) {
2986: getRawToken();
2987: if (match("by"))
2988: getRawToken();
2989: else
2990: error("missing 'by' following 'order'");
2991: Stack specs = new Stack();
2992: for (;;) {
2993: boolean descending = false;
2994: char emptyOrder = defaultEmptyOrder;
2995:
2996: LambdaExp lexp = new LambdaExp(flworDeclsCount
2997: - flworDeclsFirst);
2998: for (int i = flworDeclsFirst; i < flworDeclsCount; i++)
2999: lexp.addDeclaration(flworDecls[i].getSymbol());
3000: comp.push(lexp);
3001: lexp.body = parseExprSingle();
3002: comp.pop(lexp);
3003: specs.push(lexp);
3004:
3005: if (match("ascending"))
3006: getRawToken();
3007: else if (match("descending")) {
3008: getRawToken();
3009: descending = true;
3010: }
3011: if (match("empty")) {
3012: getRawToken();
3013: if (match("greatest")) {
3014: getRawToken();
3015: emptyOrder = 'G';
3016: } else if (match("least")) {
3017: getRawToken();
3018: emptyOrder = 'L';
3019: } else
3020: error("'empty' sequence order must be 'greatest' or 'least'");
3021: }
3022: specs.push(new QuoteExp((descending ? "D" : "A")
3023: + emptyOrder));
3024: Object collation = defaultCollator;
3025: if (match("collation")) {
3026: Object uri = parseURILiteral();
3027: if (uri instanceof String) {
3028: try {
3029: String uriString = resolveAgainstBaseUri((String) uri);
3030: collation = NamedCollator.make(uriString);
3031: } catch (Exception name) {
3032: error('e', "unknown collation '" + uri
3033: + "'", "XQST0076");
3034: }
3035: }
3036: getRawToken();
3037: }
3038: specs.push(new QuoteExp(collation));
3039: if (curToken != ',')
3040: break;
3041: getRawToken();
3042: }
3043: if (!match("return"))
3044: return syntaxError("expected 'return' clause");
3045: getRawToken();
3046:
3047: LambdaExp lexp = new LambdaExp(flworDeclsCount
3048: - flworDeclsFirst);
3049: //maybeSetLine(lexp, declLine, declColumn);
3050: for (int i = flworDeclsFirst; i < flworDeclsCount; i++)
3051: lexp.addDeclaration(flworDecls[i].getSymbol());
3052: comp.push(lexp);
3053: lexp.body = parseExprSingle();
3054: comp.pop(lexp);
3055: int nspecs = specs.size();
3056: Expression[] args = new Expression[2 + nspecs];
3057: args[0] = exp;
3058: args[1] = lexp;
3059: for (int i = 0; i < nspecs; i++)
3060: args[2 + i] = (Expression) specs.elementAt(i);
3061: return new ApplyExp(makeFunctionExp(
3062: "gnu.xquery.util.OrderedMap", "orderedMap"), args);
3063:
3064: }
3065: flworDeclsCount = flworDeclsFirst;
3066: flworDeclsFirst = flworDeclsSave;
3067: return exp;
3068: }
3069:
3070: /** Parse a let- or a for-expression.
3071: * Assume the 'let'/'for'-token has been seen, and we've read '$'.
3072: *
3073: * If we see the 'order' keyword of an 'order by' clause then we stop
3074: * parsing, and return a result as if we instead saw a
3075: * 'return make-tuple($x, ...)'. The 'order by' clause will get
3076: * parsed by the outer-most 'for' or 'let'.
3077: */
3078: public Expression parseFLWRInner(boolean isFor)
3079: throws java.io.IOException, SyntaxException {
3080: char saveNesting = pushNesting(isFor ? 'f' : 'l');
3081: curToken = '$';
3082: Declaration decl = parseVariableDeclaration();
3083: if (decl == null)
3084: return syntaxError("missing Variable - saw "
3085: + tokenString());
3086: if (flworDecls == null)
3087: flworDecls = new Declaration[8];
3088: else if (flworDeclsCount >= flworDecls.length) {
3089: Declaration[] tmp = new Declaration[2 * flworDeclsCount];
3090: System.arraycopy(flworDecls, 0, tmp, 0, flworDeclsCount);
3091: flworDecls = tmp;
3092: }
3093: flworDecls[flworDeclsCount++] = decl;
3094: getRawToken();
3095:
3096: Expression type = parseOptionalTypeDeclaration();
3097: ScopeExp sc;
3098: Expression[] inits = new Expression[1];
3099: Declaration posDecl = null;
3100: if (isFor) {
3101: boolean sawAt = match("at");
3102: LambdaExp lexp = new LambdaExp(sawAt ? 2 : 1);
3103: if (sawAt) {
3104: getRawToken();
3105: if (curToken == '$') {
3106: posDecl = parseVariableDeclaration();
3107: getRawToken();
3108: }
3109: if (posDecl == null)
3110: syntaxError("missing Variable after 'at'");
3111: }
3112: sc = lexp;
3113: if (match("in"))
3114: getRawToken();
3115: else {
3116: if (curToken == COLON_EQUAL_TOKEN)
3117: getRawToken();
3118: syntaxError("missing 'in' in 'for' clause");
3119: }
3120: } else {
3121: if (curToken == COLON_EQUAL_TOKEN)
3122: getRawToken();
3123: else {
3124: if (match("in"))
3125: getRawToken();
3126: syntaxError("missing ':=' in 'let' clause");
3127: }
3128: LetExp let = new LetExp(inits);
3129: sc = let;
3130: }
3131: inits[0] = parseExprSingle();
3132: if (type != null && !isFor) // FIXME - for now
3133: inits[0] = Convert.makeCoercion(inits[0], type);
3134: popNesting(saveNesting);
3135: comp.push(sc);
3136: sc.addDeclaration(decl);
3137: decl.setTypeExp(type);
3138: if (isFor) {
3139: decl.noteValue(null); // Does not have a known value.
3140: decl.setFlag(Declaration.IS_SINGLE_VALUE);
3141: }
3142: if (posDecl != null) {
3143: sc.addDeclaration(posDecl);
3144: posDecl.setType(LangPrimType.intType);
3145: posDecl.noteValue(null);
3146: posDecl.setFlag(Declaration.IS_SINGLE_VALUE);
3147: }
3148: Expression body;
3149: if (curToken == ',') {
3150: getRawToken();
3151: if (curToken != '$')
3152: return syntaxError("missing $NAME after ','");
3153: body = parseFLWRInner(isFor);
3154: } else if (match("for")) {
3155: getRawToken();
3156: if (curToken != '$')
3157: return syntaxError("missing $NAME after 'for'");
3158: body = parseFLWRInner(true);
3159: } else if (match("let")) {
3160: getRawToken();
3161: if (curToken != '$')
3162: return syntaxError("missing $NAME after 'let'");
3163: body = parseFLWRInner(false);
3164: } else {
3165: Expression cond;
3166: char save = pushNesting('w');
3167: if (curToken == OP_WHERE) {
3168: getRawToken();
3169: cond = parseExprSingle();
3170: } else if (match("where")) {
3171: cond = parseExprSingle();
3172: } else
3173: cond = null;
3174: popNesting(save);
3175: boolean sawStable = match("stable");
3176: if (sawStable)
3177: getRawToken();
3178: boolean sawReturn = match("return");
3179: boolean sawOrder = match("order");
3180: if (!sawReturn && !sawOrder && !match("let")
3181: && !match("for"))
3182: return syntaxError("missing 'return' clause");
3183: if (!sawOrder)
3184: peekNonSpace("unexpected eof-of-file after 'return'");
3185: int bodyLine = getLineNumber() + 1;
3186: int bodyColumn = getColumnNumber() + 1;
3187: if (sawReturn)
3188: getRawToken();
3189: if (sawOrder) {
3190: int ndecls = flworDeclsCount - flworDeclsFirst;
3191: Expression[] args = new Expression[ndecls];
3192: for (int i = 0; i < ndecls; i++)
3193: args[i] = new ReferenceExp(
3194: flworDecls[flworDeclsFirst + i]);
3195: body = new ApplyExp(
3196: new PrimProcedure("gnu.xquery.util.OrderedMap",
3197: "makeTuple$V", 1), args);
3198: } else
3199: body = parseExprSingle();
3200: if (cond != null)
3201: body = new IfExp(booleanValue(cond), body,
3202: QuoteExp.voidExp);
3203: maybeSetLine(body, bodyLine, bodyColumn);
3204: }
3205: comp.pop(sc);
3206: if (isFor) {
3207: LambdaExp lexp = (LambdaExp) sc;
3208: lexp.body = body;
3209: Expression[] args = { sc, inits[0] }; // SIC
3210: return new ApplyExp(makeFunctionExp(
3211: "gnu.kawa.functions.ValuesMap",
3212: lexp.min_args == 1 ? "valuesMap"
3213: : "valuesMapWithPos"), args);
3214: } else
3215: ((LetExp) sc).setBody(body);
3216: return sc;
3217:
3218: }
3219:
3220: /** Parse a some- or an every-expression.
3221: * Assume the 'some'/'every'-token has been seen, and we've read '$'. */
3222: public Expression parseQuantifiedExpr(boolean isEvery)
3223: throws java.io.IOException, SyntaxException {
3224: char saveNesting = pushNesting(isEvery ? 'e' : 's');
3225: curToken = '$';
3226: Declaration decl = parseVariableDeclaration();
3227: if (decl == null)
3228: return syntaxError("missing Variable token:" + curToken);
3229: getRawToken();
3230:
3231: LambdaExp lexp = new LambdaExp(1);
3232: lexp.addDeclaration(decl);
3233: decl.noteValue(null); // Does not have a known value.
3234: decl.setFlag(Declaration.IS_SINGLE_VALUE);
3235: decl.setTypeExp(parseOptionalTypeDeclaration());
3236:
3237: if (match("in"))
3238: getRawToken();
3239: else {
3240: if (curToken == COLON_EQUAL_TOKEN)
3241: getRawToken();
3242: syntaxError("missing 'in' in QuantifiedExpr");
3243: }
3244: Expression[] inits = { parseExprSingle() };
3245: popNesting(saveNesting);
3246: comp.push(lexp);
3247: Expression body;
3248: if (curToken == ',') {
3249: getRawToken();
3250: if (curToken != '$')
3251: return syntaxError("missing $NAME after ','");
3252: body = parseQuantifiedExpr(isEvery);
3253: } else {
3254: boolean sawSatisfies = match("satisfies");
3255: if (!sawSatisfies && !match("every") && !match("some"))
3256: return syntaxError("missing 'satisfies' clause");
3257: peekNonSpace("unexpected eof-of-file after 'satisfies'");
3258: int bodyLine = getLineNumber() + 1;
3259: int bodyColumn = getColumnNumber() + 1;
3260: if (sawSatisfies)
3261: getRawToken();
3262: body = parseExprSingle();
3263: maybeSetLine(body, bodyLine, bodyColumn);
3264: }
3265: comp.pop(lexp);
3266: lexp.body = body;
3267: Expression[] args = { lexp, inits[0] }; // SIC
3268: return new ApplyExp(makeFunctionExp(
3269: "gnu.xquery.util.ValuesEvery", isEvery ? "every"
3270: : "some"), args);
3271: }
3272:
3273: public Expression parseFunctionDefinition(int declLine,
3274: int declColumn) throws java.io.IOException, SyntaxException {
3275: if (curToken != QNAME_TOKEN && curToken != NCNAME_TOKEN)
3276: return syntaxError("missing function name");
3277: String name = new String(tokenBuffer, 0, tokenBufferLength);
3278: Symbol sym = namespaceResolve(name, true);
3279: String uri = sym.getNamespaceURI();
3280: if (uri == NamespaceBinding.XML_NAMESPACE
3281: || uri == XQuery.SCHEMA_NAMESPACE
3282: || uri == XQuery.SCHEMA_INSTANCE_NAMESPACE
3283: || uri == XQuery.XQUERY_FUNCTION_NAMESPACE) {
3284: error('e',
3285: "cannot declare function in standard namespace '"
3286: + uri + '\'', "XQST0045");
3287: } else if (uri == "") {
3288: error(comp.isPedantic() ? 'e' : 'w',
3289: "cannot declare function in empty namespace",
3290: "XQST0060");
3291: } else if (libraryModuleNamespace != null
3292: && uri != libraryModuleNamespace
3293: && (!XQuery.LOCAL_NAMESPACE.equals(uri) || comp
3294: .isPedantic())) {
3295: error('e', "function not in namespace of library module",
3296: "XQST0048");
3297: }
3298: getRawToken();
3299: if (curToken != '(')
3300: return syntaxError("missing parameter list:" + curToken);
3301: getRawToken();
3302: LambdaExp lexp = new LambdaExp();
3303: maybeSetLine(lexp, declLine, declColumn);
3304: lexp.setName(name);
3305: Declaration decl = comp.currentScope().addDeclaration(sym);
3306: if (comp.isStatic())
3307: decl.setFlag(Declaration.STATIC_SPECIFIED);
3308: lexp.setFlag(LambdaExp.OVERLOADABLE_FIELD);
3309: decl.setCanRead(true);
3310: decl.setProcedureDecl(true);
3311: maybeSetLine(decl, declLine, declColumn);
3312: comp.push(lexp);
3313: if (curToken != ')') {
3314: paramLoop: for (;;) {
3315: Declaration param = parseVariableDeclaration();
3316: if (param == null)
3317: error("missing parameter name");
3318: else {
3319: lexp.addDeclaration(param);
3320: getRawToken();
3321: lexp.min_args++;
3322: lexp.max_args++;
3323: param.setTypeExp(parseOptionalTypeDeclaration());
3324: }
3325: if (curToken == ')')
3326: break;
3327: if (curToken != ',') {
3328: Expression err = syntaxError("missing ',' in parameter list");
3329: for (;;) {
3330: getRawToken();
3331: if (curToken < 0 || curToken == ';'
3332: || curToken == ';')
3333: return err;
3334: if (curToken == ')')
3335: break paramLoop;
3336: if (curToken == ',')
3337: break;
3338: }
3339: } else
3340: getRawToken();
3341: }
3342: }
3343: getRawToken();
3344: Expression retType = parseOptionalTypeDeclaration();
3345: lexp.body = parseEnclosedExpr();
3346: comp.pop(lexp);
3347: if (retType != null)
3348: Convert.setCoercedReturnValue(lexp, retType, interpreter);
3349: SetExp sexp = new SetExp(decl, lexp);
3350: sexp.setDefining(true);
3351: decl.noteValue(lexp);
3352: return sexp;
3353: }
3354:
3355: public Object readObject() throws java.io.IOException,
3356: SyntaxException {
3357: return parse(null);
3358: }
3359:
3360: Compilation comp;
3361:
3362: String defaultElementNamespace = "";
3363:
3364: /** Chain of namespace bindings from namespace declaration attributes
3365: * in outer direct element constructors. This is only non-empty during
3366: * resolve time, but it is declared here so namespaceResolve can use it. */
3367: NamespaceBinding constructorNamespaces = NamespaceBinding.predefinedXML;
3368:
3369: /** Chain of namespace bindings from declarations in prolog,
3370: * followed by the builtinNamespaces. */
3371: NamespaceBinding prologNamespaces;
3372:
3373: static NamespaceBinding builtinNamespaces;
3374: static {
3375: NamespaceBinding ns = NamespaceBinding.predefinedXML;
3376: ns = new NamespaceBinding("xml",
3377: NamespaceBinding.XML_NAMESPACE, ns);
3378: ns = new NamespaceBinding("xs", XQuery.SCHEMA_NAMESPACE, ns);
3379: ns = new NamespaceBinding("xsi",
3380: XQuery.SCHEMA_INSTANCE_NAMESPACE, ns);
3381: ns = new NamespaceBinding("fn",
3382: XQuery.XQUERY_FUNCTION_NAMESPACE, ns);
3383: ns = new NamespaceBinding("html", XQuery.XHTML_NAMESPACE, ns);
3384: ns = new NamespaceBinding("kawa",
3385: XQuery.KAWA_FUNCTION_NAMESPACE, ns);
3386: ns = new NamespaceBinding("qexo",
3387: XQuery.QEXO_FUNCTION_NAMESPACE, ns);
3388: ns = new NamespaceBinding("local", XQuery.LOCAL_NAMESPACE, ns);
3389: builtinNamespaces = ns;
3390: }
3391:
3392: protected Symbol namespaceResolve(String name, boolean function) {
3393: int colon = name.indexOf(':');
3394: String prefix = colon >= 0 ? name.substring(0, colon).intern()
3395: : function ? XQuery.DEFAULT_FUNCTION_PREFIX
3396: : XQuery.DEFAULT_ELEMENT_PREFIX;
3397: String uri = QNameUtils.lookupPrefix(prefix,
3398: constructorNamespaces, prologNamespaces);
3399:
3400: if (uri == null) {
3401: if (colon < 0)
3402: uri = "";
3403: else if (!comp.isPedantic()) {
3404: try {
3405: Class cl = Class.forName(prefix);
3406: uri = "class:" + prefix;
3407: } catch (Exception ex) {
3408: uri = null;
3409: }
3410: }
3411: if (uri == null) {
3412: error('e', "unknown namespace prefix '" + prefix + "'",
3413: "XPST0081");
3414: uri = "(unknown namespace)";
3415: }
3416: }
3417: String local = colon < 0 ? name : name.substring(colon + 1);
3418: return Symbol.make((String) uri, local, prefix);
3419: }
3420:
3421: void parseSeparator() throws java.io.IOException, SyntaxException {
3422: int startLine = port.getLineNumber() + 1;
3423: int startColumn = port.getColumnNumber() + 1;
3424: int next = skipSpace(nesting != 0);
3425: if (next == ';')
3426: return;
3427: if (warnOldVersion && next != '\n') {
3428: curLine = startLine;
3429: curColumn = startColumn;
3430: error('w', "missing ';' after declaration");
3431: }
3432: if (next >= 0)
3433: unread(next);
3434: }
3435:
3436: public static final QuoteExp getExternalFunction = QuoteExp
3437: .getInstance(new PrimProcedure("gnu.xquery.lang.XQuery",
3438: "getExternal", 2));
3439:
3440: /** Parse an expression.
3441: * Return null on EOF. */
3442: public Expression parse(Compilation comp)
3443: throws java.io.IOException, SyntaxException {
3444: this .comp = comp;
3445: int ch = skipSpace();
3446: if (ch < 0)
3447: return null;
3448: parseCount++;
3449: unread(ch);
3450: int startLine = getLineNumber() + 1;
3451: int startColumn = getColumnNumber() + 1;
3452:
3453: // Handle Unix #!PROGRAM convention. */
3454: if (ch == '#' && startLine == 1 && startColumn == 1) {
3455: read();
3456: if ((ch = read()) != '!' || (ch = read()) != '/')
3457: error("'#' is only allowed in initial '#!/PROGRAM'");
3458: while (ch != '\r' && ch != '\n' && ch >= 0)
3459: ch = read();
3460: }
3461:
3462: if (getRawToken() == EOF_TOKEN)
3463: return null;
3464: peekOperand();
3465:
3466: if (curToken == NCNAME_TOKEN
3467: && "namespace".equals((String) curValue)) {
3468: if (warnOldVersion)
3469: error('w',
3470: "use 'declare namespace' instead of 'namespace'");
3471: curToken = DECLARE_NAMESPACE_TOKEN;
3472: }
3473:
3474: int declLine, declColumn, next;
3475: Declaration decl;
3476: String prefix, uri;
3477: Object val;
3478: Expression exp;
3479: switch (curToken) {
3480: case DEFINE_QNAME_TOKEN:
3481: declLine = getLineNumber() + 1;
3482: declColumn = getColumnNumber() + 1;
3483: next = peekNonSpace("unexpected end-of-file after 'define QName'");
3484: if (next == '(') {
3485: syntaxError("'missing 'function' after 'define'");
3486: curToken = NCNAME_TOKEN;
3487: return parseFunctionDefinition(declLine, declColumn);
3488: } else
3489: return syntaxError("missing keyword after 'define'");
3490:
3491: case DECLARE_FUNCTION_TOKEN:
3492: declLine = getLineNumber() + 1;
3493: declColumn = getColumnNumber() + 1;
3494: getRawToken();
3495: peekNonSpace("unexpected end-of-file after 'define function'");
3496: char save = pushNesting('d');
3497: exp = parseFunctionDefinition(declLine, declColumn);
3498: popNesting(save);
3499: parseSeparator();
3500: maybeSetLine(exp, startLine, startColumn);
3501: seenDeclaration = true;
3502: return exp;
3503:
3504: case DECLARE_VARIABLE_TOKEN:
3505: getRawToken();
3506: decl = parseVariableDeclaration();
3507: if (decl == null)
3508: return syntaxError("missing Variable");
3509: Object name = decl.getSymbol();
3510: if (name instanceof String)
3511: decl.setSymbol(namespaceResolve((String) name, false));
3512: if (libraryModuleNamespace != null) {
3513: uri = ((Symbol) decl.getSymbol()).getNamespaceURI();
3514: if (uri != libraryModuleNamespace
3515: && (!XQuery.LOCAL_NAMESPACE.equals(uri) || comp
3516: .isPedantic()))
3517: error(
3518: 'e',
3519: "variable not in namespace of library module",
3520: "XQST0048");
3521: }
3522: comp.currentScope().addDeclaration(decl);
3523: getRawToken();
3524: Expression type = parseOptionalTypeDeclaration();
3525: decl.setCanRead(true);
3526: //decl.setFlag(Declaration.NONSTATIC_SPECIFIED);
3527: decl.setFlag(Declaration.IS_CONSTANT);
3528: Expression init = null;
3529: boolean sawEq = false;
3530: if (curToken == OP_EQU || curToken == COLON_EQUAL_TOKEN) {
3531: if (curToken == OP_EQU)
3532: error("declare variable contains '=' instead of ':='");
3533: getRawToken();
3534: sawEq = true;
3535: }
3536: if (curToken == '{') {
3537: warnOldVersion("obsolete '{' in variable declaration");
3538: init = parseEnclosedExpr();
3539: parseSeparator();
3540: } else if (match("external")) {
3541: Expression[] args = {
3542: castQName(new QuoteExp(decl.getSymbol())),
3543: type == null ? QuoteExp.nullExp : type };
3544: init = new ApplyExp(getExternalFunction, args);
3545: maybeSetLine(init, curLine, curColumn);
3546: getRawToken();
3547: } else {
3548: init = parseExpr();
3549: Expression err = null;
3550: if (!sawEq || init == null)
3551: err = syntaxError("expected ':= init' or 'external'");
3552: if (init == null)
3553: init = err;
3554: }
3555: if (type != null)
3556: init = Convert.makeCoercion(init, type);
3557: decl.noteValue(init);
3558: exp = SetExp.makeDefinition(decl, init);
3559: maybeSetLine(exp, startLine, startColumn);
3560: seenDeclaration = true;
3561: return exp;
3562:
3563: case DECLARE_NAMESPACE_TOKEN:
3564: case MODULE_NAMESPACE_TOKEN:
3565: int command = curToken;
3566: if (command == MODULE_NAMESPACE_TOKEN
3567: && libraryModuleNamespace != null)
3568: error('e', "duplicate module declaration");
3569: else if (seenDeclaration && !interactive)
3570: error('e',
3571: "namespace declared after function/variable/option");
3572: next = skipSpace(nesting != 0);
3573: if (next >= 0) {
3574: unread();
3575: if (XName.isNameStart((char) next)) {
3576: getRawToken();
3577: if (curToken != NCNAME_TOKEN)
3578: return syntaxError("missing namespace prefix");
3579: prefix = new String(tokenBuffer, 0,
3580: tokenBufferLength);
3581: getRawToken();
3582: if (curToken != OP_EQU)
3583: return syntaxError("missing '=' in namespace declaration");
3584: getRawToken();
3585: if (curToken != STRING_TOKEN)
3586: return syntaxError("missing uri in namespace declaration");
3587: uri = new String(tokenBuffer, 0, tokenBufferLength)
3588: .intern();
3589: prefix = prefix.intern();
3590: for (NamespaceBinding ns = prologNamespaces; ns != builtinNamespaces; ns = ns
3591: .getNext()) {
3592: if (ns.getPrefix() == prefix) {
3593: error('e',
3594: "duplicate declarations for the same namespace prefix '"
3595: + prefix + "'", "XQST0033");
3596: break;
3597: }
3598: }
3599: pushNamespace(prefix, uri);
3600: checkAllowedNamespaceDeclaration(prefix, uri, false);
3601: parseSeparator();
3602: if (command == MODULE_NAMESPACE_TOKEN) {
3603: ModuleExp module = comp.getModule();
3604: String className = Compilation.mangleURI(uri)
3605: + '.'
3606: + XQuery.makeClassName(module
3607: .getFileName());
3608: module.setName(className);
3609: comp.mainClass = new ClassType(className);
3610: module.setType(comp.mainClass);
3611: ModuleManager manager = ModuleManager
3612: .getInstance();
3613: ModuleInfo info = manager.find(comp);
3614: info.setNamespaceUri(uri);
3615: module.setType(comp.mainClass);
3616: if (uri.length() == 0)
3617: return syntaxError(
3618: "zero-length module namespace",
3619: "XQST0088");
3620: libraryModuleNamespace = uri;
3621: }
3622: return QuoteExp.voidExp;
3623: }
3624: }
3625:
3626: case IMPORT_SCHEMA_TOKEN:
3627: fatal("'import schema' not implemented", "XQST0009");
3628:
3629: case IMPORT_MODULE_TOKEN:
3630: getRawToken();
3631: prefix = null;
3632: if (match("namespace")) {
3633: getRawToken();
3634: if (curToken != NCNAME_TOKEN)
3635: return syntaxError("missing namespace prefix");
3636: prefix = new String(tokenBuffer, 0, tokenBufferLength);
3637: getRawToken();
3638: if (curToken != OP_EQU)
3639: return syntaxError("missing '=' in namespace declaration");
3640: getRawToken();
3641: }
3642: if (curToken != STRING_TOKEN)
3643: return syntaxError("missing uri in namespace declaration");
3644: if (tokenBufferLength == 0)
3645: return syntaxError("zero-length target namespace",
3646: "XQST0088");
3647: uri = new String(tokenBuffer, 0, tokenBufferLength)
3648: .intern();
3649: if (prefix != null) {
3650: checkAllowedNamespaceDeclaration(prefix, uri, false);
3651: pushNamespace(prefix.intern(), uri);
3652: }
3653: getRawToken();
3654: // Make sure we have a ModuleInfo before we call importDefinitions.
3655: ModuleManager.getInstance().find(comp);
3656:
3657: String at;
3658: ModuleExp module = comp.getModule();
3659: Vector forms = new Vector();
3660: String packageName = Compilation.mangleURI(uri);
3661: comp.setLine(port.getName(), startLine, startColumn);
3662: if (match("at")) {
3663: for (;;) {
3664: getRawToken();
3665: if (curToken != STRING_TOKEN)
3666: return syntaxError("missing module location");
3667: at = new String(tokenBuffer, 0, tokenBufferLength);
3668: String className = Compilation.mangleURI(uri) + '.'
3669: + XQuery.makeClassName(at);
3670:
3671: ModuleInfo info = require
3672: .lookupModuleFromSourcePath(at, module);
3673: if (info == null)
3674: comp.error('e', "malformed URL: " + at);
3675: require.importDefinitions(className, info, uri,
3676: forms, module, comp);
3677: next = skipSpace(nesting != 0);
3678: if (next != ',') {
3679: unread(next);
3680: break;
3681: }
3682: }
3683: parseSeparator();
3684: } else {
3685: ModuleManager manager = ModuleManager.getInstance();
3686: int n = 0;
3687: try {
3688: manager.loadPackageInfo(packageName);
3689: } catch (ClassNotFoundException ex) {
3690: // Do nothing. If there is no such module,
3691: // that will be reported below.
3692: } catch (Throwable ex) {
3693: error('e', "error loading map for " + uri + " - "
3694: + ex);
3695: }
3696: for (ModuleInfo info = manager.firstModule(); info != null; info = info
3697: .nextModule()) {
3698: if (!uri.equals(info.getNamespaceUri()))
3699: continue;
3700: n++;
3701: require.importDefinitions(info.className, info,
3702: uri, forms, module, comp);
3703: }
3704: if (n == 0)
3705: error('e', "no module found for " + uri);
3706: at = null;
3707: if (curToken != ';')
3708: parseSeparator();
3709: }
3710: if (comp.pendingImports != null
3711: && comp.pendingImports.size() > 0) {
3712: error('e', "module import forms a cycle", "XQST0073");
3713: }
3714: Expression[] inits = new Expression[forms.size()];
3715: forms.toArray(inits);
3716: return BeginExp.canonicalize(inits);
3717:
3718: case DEFAULT_COLLATION_TOKEN:
3719: if (defaultCollator != null && !interactive)
3720: error('e', "duplicate default collation declaration",
3721: "XQST0038");
3722: val = parseURILiteral();
3723: if (val instanceof Expression) // an ErrorExp
3724: return (Expression) val;
3725: String collation = (String) val;
3726: try {
3727: collation = resolveAgainstBaseUri(collation);
3728: defaultCollator = NamedCollator.make(collation);
3729: } catch (Exception ex) {
3730: defaultCollator = NamedCollator.codepointCollation;
3731: error('e', "unknown collation '" + collation + "'",
3732: "XQST0038");
3733: }
3734: parseSeparator();
3735: return QuoteExp.voidExp;
3736:
3737: case DEFAULT_ELEMENT_TOKEN:
3738: case DEFAULT_FUNCTION_TOKEN:
3739: boolean forFunctions = curToken == DEFAULT_FUNCTION_TOKEN;
3740: prefix = forFunctions ? XQuery.DEFAULT_FUNCTION_PREFIX
3741: : XQuery.DEFAULT_ELEMENT_PREFIX;
3742: if (prologNamespaces.resolve(prefix, builtinNamespaces) != null)
3743: error('e', "duplicate default namespace declaration",
3744: "XQST0066");
3745: getRawToken();
3746: if (match("namespace"))
3747: getRawToken();
3748: else {
3749: String msg = "expected 'namespace' keyword";
3750: if (curToken != STRING_TOKEN && curToken != OP_EQU)
3751: return declError(msg);
3752: else
3753: warnOldVersion(msg);
3754: }
3755: if (curToken == OP_EQU || curToken == COLON_EQUAL_TOKEN) {
3756: warnOldVersion("extra '=' in default namespace declaration");
3757: getRawToken();
3758: }
3759: if (curToken != STRING_TOKEN)
3760: return declError("missing namespace uri");
3761: uri = new String(tokenBuffer, 0, tokenBufferLength);
3762: if (forFunctions) {
3763: functionNamespacePath = new Namespace[1];
3764: functionNamespacePath[0] = Namespace.getInstance(uri);
3765: } else {
3766: defaultElementNamespace = uri;
3767: }
3768: pushNamespace(prefix, uri);
3769: checkAllowedNamespaceDeclaration(prefix, uri, false);
3770: parseSeparator();
3771: return QuoteExp.voidExp;
3772:
3773: case DECLARE_BOUNDARY_SPACE_TOKEN:
3774: getRawToken();
3775: if (curToken == OP_EQU) {
3776: warnOldVersion("obsolate '=' in boundary-space declaration");
3777: getRawToken();
3778: }
3779: if (boundarySpaceDeclarationSeen && !interactive)
3780: syntaxError("duplicate 'declare boundary-space' seen",
3781: "XQST0068");
3782: boundarySpaceDeclarationSeen = true;
3783: if (match("preserve"))
3784: boundarySpacePreserve = true;
3785: else if (match("strip"))
3786: boundarySpacePreserve = false;
3787: else if (match("skip")) {
3788: warnOldVersion("update: declare boundary-space skip -> strip");
3789: boundarySpacePreserve = false;
3790: } else
3791: return syntaxError("boundary-space declaration must be preserve or strip");
3792: parseSeparator();
3793: return QuoteExp.voidExp;
3794:
3795: case DECLARE_CONSTRUCTION_TOKEN:
3796: getRawToken();
3797: if (constructionModeDeclarationSeen && !interactive)
3798: syntaxError("duplicate 'declare construction' seen",
3799: "XQST0067");
3800: constructionModeDeclarationSeen = true;
3801: if (match("strip"))
3802: constructionModeStrip = true;
3803: else if (match("preserve"))
3804: constructionModeStrip = false;
3805: else
3806: return syntaxError("construction declaration must be strip or preserve");
3807: parseSeparator();
3808: return QuoteExp.voidExp;
3809:
3810: case DECLARE_COPY_NAMESPACES_TOKEN:
3811: getRawToken();
3812: if (copyNamespacesDeclarationSeen && !interactive)
3813: syntaxError("duplicate 'declare copy-namespaces' seen",
3814: "XQST0055");
3815: copyNamespacesDeclarationSeen = true;
3816: if (match("preserve"))
3817: copyNamespacesMode |= XMLFilter.COPY_NAMESPACES_PRESERVE;
3818: else if (match("no-preserve"))
3819: copyNamespacesMode &= ~XMLFilter.COPY_NAMESPACES_PRESERVE;
3820: else
3821: return syntaxError("expected 'preserve' or 'no-preserve' after 'declare copy-namespaces'");
3822: getRawToken();
3823: if (curToken != ',')
3824: return syntaxError("missing ',' in copy-namespaces declaration");
3825: getRawToken();
3826: if (match("inherit"))
3827: copyNamespacesMode |= XMLFilter.COPY_NAMESPACES_INHERIT;
3828: else if (match("no-inherit"))
3829: copyNamespacesMode &= ~XMLFilter.COPY_NAMESPACES_INHERIT;
3830: else
3831: return syntaxError("expected 'inherit' or 'no-inherit' in copy-namespaces declaration");
3832: parseSeparator();
3833: return QuoteExp.voidExp;
3834:
3835: case DEFAULT_ORDER_TOKEN:
3836: getRawToken();
3837: boolean sawEmpty = match("empty");
3838: if (emptyOrderDeclarationSeen && !interactive)
3839: syntaxError(
3840: "duplicate 'declare default empty order' seen",
3841: "XQST0069");
3842: emptyOrderDeclarationSeen = true;
3843: if (sawEmpty)
3844: getRawToken();
3845: else
3846: syntaxError("expected 'empty greatest' or 'empty least'");
3847: if (match("greatest"))
3848: defaultEmptyOrder = 'G';
3849: else if (match("least"))
3850: defaultEmptyOrder = 'L';
3851: else
3852: return syntaxError("expected 'empty greatest' or 'empty least'");
3853: parseSeparator();
3854: return QuoteExp.voidExp;
3855:
3856: case DECLARE_OPTION_TOKEN:
3857: getRawToken();
3858: if (curToken != QNAME_TOKEN)
3859: syntaxError("expected QName after 'declare option'");
3860: else {
3861: String str = new String(tokenBuffer, 0,
3862: tokenBufferLength);
3863: getRawToken();
3864: if (curToken != STRING_TOKEN)
3865: syntaxError("expected string literal after 'declare option <QName>'");
3866: else
3867: handleOption(namespaceResolve(str, false),
3868: new String(tokenBuffer, 0,
3869: tokenBufferLength));
3870: }
3871: parseSeparator();
3872: seenDeclaration = true;
3873: return QuoteExp.voidExp;
3874:
3875: case DECLARE_ORDERING_TOKEN:
3876: if (orderingModeSeen && !interactive)
3877: syntaxError("duplicate 'declare ordering' seen",
3878: "XQST0065");
3879: orderingModeSeen = true;
3880: getRawToken();
3881: if (match("ordered"))
3882: orderingModeUnordered = false;
3883: else if (match("unordered"))
3884: orderingModeUnordered = true;
3885: else
3886: return syntaxError("ordering declaration must be ordered or unordered");
3887: parseSeparator();
3888: return QuoteExp.voidExp;
3889:
3890: case XQUERY_VERSION_TOKEN:
3891: if (parseCount != 1)
3892: error('e', "'xquery version' does not start module");
3893: else if (commentCount > 0)
3894: error('w',
3895: "comments should not precede 'xquery version'");
3896: getRawToken();
3897: if (curToken == STRING_TOKEN) {
3898: String version = new String(tokenBuffer, 0,
3899: tokenBufferLength);
3900: if (!version.equals("1.0"))
3901: error('e',
3902: "unrecognized xquery version " + version,
3903: "XQST0031");
3904: getRawToken();
3905: } else
3906: return syntaxError("missing version string after 'xquery version'");
3907: if (match("encoding")) {
3908: getRawToken();
3909: if (curToken != STRING_TOKEN)
3910: return syntaxError("invalid encoding specification");
3911: else {
3912: String encoding = new String(tokenBuffer, 0,
3913: tokenBufferLength);
3914: int i = tokenBufferLength;
3915: boolean bad = i == 0;
3916: while (--i >= 0 && !bad) {
3917: ch = tokenBuffer[i];
3918: if ((ch >= 'A' && ch <= 'Z')
3919: || (ch >= 'a' && ch <= 'z'))
3920: continue;
3921: if (i == 0
3922: || !((ch >= '0' && ch <= '9')
3923: || ch == '.' || ch == '_' || ch == '-'))
3924: bad = true;
3925: }
3926: if (bad)
3927: error('e', "invalid encoding name syntax",
3928: "XQST0087");
3929: // ignore encoding specification.
3930: getRawToken();
3931: }
3932: }
3933: if (curToken != ';')
3934: syntaxError("missing ';'");
3935: return QuoteExp.voidExp;
3936:
3937: case DECLARE_BASE_URI_TOKEN:
3938: if (baseURIDeclarationSeen && !interactive)
3939: syntaxError("duplicate 'declare base-uri' seen",
3940: "XQST0032");
3941: baseURIDeclarationSeen = true;
3942: val = parseURILiteral();
3943: if (val instanceof Expression) // an ErrorExp
3944: return (Expression) val;
3945: parseSeparator();
3946: setStaticBaseUri((String) val);
3947: return QuoteExp.voidExp;
3948: }
3949: exp = parseExprSequence(EOF_TOKEN, true);
3950: if (curToken == EOL_TOKEN)
3951: unread('\n');
3952: maybeSetLine(exp, startLine, startColumn);
3953: return exp;
3954: }
3955:
3956: public void handleOption(Symbol name, String value) {
3957: // Nothing, for now.
3958: }
3959:
3960: public final static String[] axisNames = new String[COUNT_OP_AXIS];
3961: static {
3962: axisNames[AXIS_ANCESTOR] = "ancestor";
3963: axisNames[AXIS_ANCESTOR_OR_SELF] = "ancestor-or-self";
3964: axisNames[AXIS_ATTRIBUTE] = "attribute";
3965: axisNames[AXIS_CHILD] = "child";
3966: axisNames[AXIS_DESCENDANT] = "descendant";
3967: axisNames[AXIS_DESCENDANT_OR_SELF] = "descendant-or-self";
3968: axisNames[AXIS_FOLLOWING] = "following";
3969: axisNames[AXIS_FOLLOWING_SIBLING] = "following-sibling";
3970: axisNames[AXIS_NAMESPACE] = "namespace";
3971: axisNames[AXIS_PARENT] = "parent";
3972: axisNames[AXIS_PRECEDING] = "preceding";
3973: axisNames[AXIS_PRECEDING_SIBLING] = "preceding-sibling";
3974: axisNames[AXIS_SELF] = "self";
3975: }
3976:
3977: public static Expression makeFunctionExp(String className,
3978: String name) {
3979: return makeFunctionExp(className, Compilation
3980: .mangleNameIfNeeded(name), name);
3981: }
3982:
3983: public static Expression makeFunctionExp(String className,
3984: String fieldName, String name) {
3985: return new ReferenceExp(name, Declaration
3986: .getDeclarationValueFromStatic(className, fieldName,
3987: name));
3988: }
3989:
3990: /** Helper method for debugging. */
3991: String tokenString() {
3992: switch (curToken) {
3993: case STRING_TOKEN:
3994: StringBuffer sbuf = new StringBuffer();
3995: sbuf.append('"');
3996: for (int i = 0; i < tokenBufferLength; i++) {
3997: char ch = tokenBuffer[i];
3998: if (ch == '"')
3999: sbuf.append('"');
4000: sbuf.append(ch);
4001: }
4002: sbuf.append('"');
4003: return sbuf.toString();
4004: case FNAME_TOKEN:
4005: return new String(tokenBuffer, 0, tokenBufferLength)
4006: + " + '('";
4007: case NCNAME_TOKEN:
4008: case QNAME_TOKEN:
4009: return new String(tokenBuffer, 0, tokenBufferLength);
4010: case EOF_TOKEN:
4011: return "<EOF>";
4012: default:
4013: if (curToken >= OP_AXIS_FIRST
4014: && curToken - OP_AXIS_FIRST < COUNT_OP_AXIS)
4015: return axisNames[curToken - OP_AXIS_FIRST] + "::-axis("
4016: + curToken + ")";
4017: return Integer.toString(curToken);
4018: }
4019: }
4020:
4021: public void error(char severity, String message, String code) {
4022: SourceMessages messages = getMessages();
4023: SourceError err = new SourceError(severity, port.getName(),
4024: curLine, curColumn, message);
4025: err.code = code;
4026: messages.error(err);
4027: }
4028:
4029: public void error(char severity, String message) {
4030: error(severity, message, null);
4031: }
4032:
4033: public Expression declError(String message)
4034: throws java.io.IOException, SyntaxException {
4035: if (interactive)
4036: return syntaxError(message);
4037: error(message);
4038: for (;;) {
4039: if (curToken == ';' || curToken == EOF_TOKEN)
4040: break;
4041: getRawToken();
4042: }
4043: return new ErrorExp(message);
4044: }
4045:
4046: /**
4047: * Handle syntax errors (at rewrite time).
4048: * @param message an error message to print out
4049: * @return an ErrorExp
4050: */
4051: public Expression syntaxError(String message, String code)
4052: throws java.io.IOException, SyntaxException {
4053: error('e', message, code);
4054: if (interactive) {
4055: curToken = 0;
4056: curValue = null;
4057: nesting = 0;
4058: ((InPort) getPort()).readState = '\n';
4059: for (;;) {
4060: int ch = read();
4061: if (ch < 0)
4062: break;
4063: if (ch == '\r' || ch == '\n') {
4064: unread(ch);
4065: break;
4066: }
4067: }
4068: throw new SyntaxException(getMessages());
4069: }
4070: return new ErrorExp(message);
4071: }
4072:
4073: public Expression syntaxError(String message)
4074: throws java.io.IOException, SyntaxException {
4075: return syntaxError(message, "XPST0003");
4076: }
4077:
4078: public void eofError(String msg) throws SyntaxException {
4079: fatal(msg, "XPST0003");
4080: }
4081:
4082: public void fatal(String msg, String code) throws SyntaxException {
4083: SourceMessages messages = getMessages();
4084: SourceError err = new SourceError('f', port.getName(), curLine,
4085: curColumn, msg);
4086: err.code = code;
4087: messages.error(err);
4088: throw new SyntaxException(messages);
4089: }
4090:
4091: void warnOldVersion(String message) {
4092: if (warnOldVersion || comp.isPedantic())
4093: error(comp.isPedantic() ? 'e' : 'w', message);
4094: }
4095:
4096: public void maybeSetLine(Expression exp, int line, int column) {
4097: String file = getName();
4098: if (file != null) {
4099: exp.setFile(file);
4100: exp.setLine(line, column);
4101: }
4102: }
4103:
4104: public void maybeSetLine(Declaration decl, int line, int column) {
4105: String file = getName();
4106: if (file != null) {
4107: decl.setFile(file);
4108: decl.setLine(line, column);
4109: }
4110: }
4111: }
|