diff --git a/Makefile.dryice.js b/Makefile.dryice.js
index 4b1dfcb4..a8cf3e68 100755
--- a/Makefile.dryice.js
+++ b/Makefile.dryice.js
@@ -241,7 +241,7 @@ function buildAce(aceProject, options) {
"tomorrow_night_blue", "tomorrow_night_bright", "tomorrow_night_eighties",
"twilight", "vibrant_ink"
],
- workers: ["javascript", "coffee", "css", "json"],
+ workers: ["javascript", "coffee", "css", "json", "xquery"],
keybindings: ["vim", "emacs"]
};
diff --git a/build/demo/kitchen-sink/mode-coffee-uncompressed.js b/build/demo/kitchen-sink/mode-coffee-uncompressed.js
index 0e7c3b9f..de5d31b0 100644
--- a/build/demo/kitchen-sink/mode-coffee-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-coffee-uncompressed.js
@@ -657,7 +657,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-coldfusion-uncompressed.js b/build/demo/kitchen-sink/mode-coldfusion-uncompressed.js
index 7c752ee5..4c83e3d1 100644
--- a/build/demo/kitchen-sink/mode-coldfusion-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-coldfusion-uncompressed.js
@@ -1926,7 +1926,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-css-uncompressed.js b/build/demo/kitchen-sink/mode-css-uncompressed.js
index f3d6edbf..07c79a61 100644
--- a/build/demo/kitchen-sink/mode-css-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-css-uncompressed.js
@@ -483,7 +483,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-groovy-uncompressed.js b/build/demo/kitchen-sink/mode-groovy-uncompressed.js
index 2fca0ad9..6576df28 100644
--- a/build/demo/kitchen-sink/mode-groovy-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-groovy-uncompressed.js
@@ -867,7 +867,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-html-uncompressed.js b/build/demo/kitchen-sink/mode-html-uncompressed.js
index cbbe24bd..62e709f7 100644
--- a/build/demo/kitchen-sink/mode-html-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-html-uncompressed.js
@@ -926,7 +926,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-java-uncompressed.js b/build/demo/kitchen-sink/mode-java-uncompressed.js
index 23854c78..dfbf3680 100644
--- a/build/demo/kitchen-sink/mode-java-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-java-uncompressed.js
@@ -868,7 +868,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-javascript-uncompressed.js b/build/demo/kitchen-sink/mode-javascript-uncompressed.js
index 66b47e15..296069a1 100644
--- a/build/demo/kitchen-sink/mode-javascript-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-javascript-uncompressed.js
@@ -843,7 +843,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-json-uncompressed.js b/build/demo/kitchen-sink/mode-json-uncompressed.js
index 17b9d306..144bb932 100644
--- a/build/demo/kitchen-sink/mode-json-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-json-uncompressed.js
@@ -751,7 +751,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-markdown-uncompressed.js b/build/demo/kitchen-sink/mode-markdown-uncompressed.js
index 17e27e45..e8ce538a 100644
--- a/build/demo/kitchen-sink/mode-markdown-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-markdown-uncompressed.js
@@ -924,7 +924,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-scala-uncompressed.js b/build/demo/kitchen-sink/mode-scala-uncompressed.js
index c59a625f..6831517a 100644
--- a/build/demo/kitchen-sink/mode-scala-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-scala-uncompressed.js
@@ -868,7 +868,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-svg-uncompressed.js b/build/demo/kitchen-sink/mode-svg-uncompressed.js
index 45759dc8..3f5053d4 100644
--- a/build/demo/kitchen-sink/mode-svg-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-svg-uncompressed.js
@@ -1933,7 +1933,14 @@ var WorkerClient = function(topLevelNamespaces, packagedJs, mod, classname) {
this.$worker = new Worker(config.get("workerPath") + "/" + packagedJs);
}
else {
- var workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ var workerUrl;
+ if (typeof require.supports !== "undefined" && require.supports.indexOf("ucjs2-pinf-0") >= 0) {
+ // We are running in the sourcemint loader.
+ workerUrl = require.nameToUrl("ace/worker/worker_sourcemint");
+ } else {
+ // We are running in RequireJS.
+ workerUrl = this.$normalizePath(require.nameToUrl("ace/worker/worker", null, "_"));
+ }
this.$worker = new Worker(workerUrl);
var tlns = {};
diff --git a/build/demo/kitchen-sink/mode-xquery-uncompressed.js b/build/demo/kitchen-sink/mode-xquery-uncompressed.js
index 1f35638f..fef5b873 100644
--- a/build/demo/kitchen-sink/mode-xquery-uncompressed.js
+++ b/build/demo/kitchen-sink/mode-xquery-uncompressed.js
@@ -1,24 +1,44 @@
-/*
- * eXide - web-based XQuery IDE
- *
- * Copyright (C) 2011 Wolfgang Meier
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
*
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see To avoid English-only error messages and to generally make things
+ * as flexible as possible, these exceptions are not created with strings,
+ * but rather the information necessary to generate an error. Then
+ * the various reporting methods in Parser and Lexer can be overridden
+ * to generate a localized error message. For example, MismatchedToken
+ * exceptions are built with the expected token type.
+ * So, don't expect getMessage() to return anything. ANTLR generates code that throws exceptions upon recognition error and
+ * also generates code to catch these exceptions in each rule. If you
+ * want to quit upon first error, you can turn off the automatic error
+ * handling mechanism using rulecatch action, but you still need to
+ * override methods mismatch and recoverFromMismatchSet. In general, the recognition exceptions can track where in a grammar a
+ * problem occurred and/or what was the expected input. While the parser
+ * knows its state (such as current input symbol and line info) that
+ * state can change before the exception is reported so current token index
+ * is computed and stored at exception time. From this info, you can
+ * perhaps print an entire line of input not just a single token, for example.
+ * Better to just say the recognizer had a problem and then let the parser
+ * figure out a fancy report. JavaScript Note: There is no good way to implement something like this in
+ * JavaScript. JS has no true int type, arrays are usually implemented as
+ * hashes, etc. This class should probably be nixed for something that is
+ * similarly (in)efficient, but more clear. Operates in a number of modes:
+ *
+ * If `newLineMode == unix`, `\n` is returned.
+ * If `newLineMode == auto`, the value of `autoNewLine` is returned.
+ *
+ * Returns the newline character that's being used, depending on the value of `newLineMode`.
+ *
+ *
+ *
+ **/
+ this.getNewLineCharacter = function() {
+ switch (this.$newLineMode) {
+ case "windows":
+ return "\r\n";
+
+ case "unix":
+ return "\n";
+
+ case "auto":
+ return this.$autoNewLine;
+ }
+ };
+
+ this.$autoNewLine = "\n";
+ this.$newLineMode = "auto";
+ /**
+ * Document.setNewLineMode(newLineMode) -> Void
+ * - newLineMode(String): [The newline mode to use; can be either `windows`, `unix`, or `auto`]{: #Document.setNewLineMode.param}
+ *
+ * [Sets the new line mode.]{: #Document.setNewLineMode.desc}
+ **/
+ this.setNewLineMode = function(newLineMode) {
+ if (this.$newLineMode === newLineMode)
+ return;
+
+ this.$newLineMode = newLineMode;
+ };
+
+ /**
+ * Document.getNewLineMode() -> String
+ *
+ * [Returns the type of newlines being used; either `windows`, `unix`, or `auto`]{: #Document.getNewLineMode}
+ *
+ **/
+ this.getNewLineMode = function() {
+ return this.$newLineMode;
+ };
+
+ /**
+ * Document.isNewLine(text) -> Boolean
+ * - text (String): The text to check
+ *
+ * Returns `true` if `text` is a newline character (either `\r\n`, `\r`, or `\n`).
+ *
+ **/
+ this.isNewLine = function(text) {
+ return (text == "\r\n" || text == "\r" || text == "\n");
+ };
+
+ /**
+ * Document.getLine(row) -> String
+ * - row (Number): The row index to retrieve
+ *
+ * Returns a verbatim copy of the given line as it is in the document
+ *
+ **/
+ this.getLine = function(row) {
+ return this.$lines[row] || "";
+ };
+
+ /**
+ * Document.getLines(firstRow, lastRow) -> [String]
+ * - firstRow (Number): The first row index to retrieve
+ * - lastRow (Number): The final row index to retrieve
+ *
+ * Returns an array of strings of the rows between `firstRow` and `lastRow`. This function is inclusive of `lastRow`.
+ *
+ **/
+ this.getLines = function(firstRow, lastRow) {
+ return this.$lines.slice(firstRow, lastRow + 1);
+ };
+
+ /**
+ * Document.getAllLines() -> [String]
+ *
+ * Returns all lines in the document as string array. Warning: The caller should not modify this array!
+ **/
+ this.getAllLines = function() {
+ return this.getLines(0, this.getLength());
+ };
+
+ /**
+ * Document.getLength() -> Number
+ *
+ * Returns the number of rows in the document.
+ **/
+ this.getLength = function() {
+ return this.$lines.length;
+ };
+
+ /**
+ * Document.getTextRange(range) -> String
+ * - range (Range): The range to work with
+ *
+ * [Given a range within the document, this function returns all the text within that range as a single string.]{: #Document.getTextRange.desc}
+ **/
+ this.getTextRange = function(range) {
+ if (range.start.row == range.end.row) {
+ return this.$lines[range.start.row].substring(range.start.column,
+ range.end.column);
+ }
+ else {
+ var lines = this.getLines(range.start.row+1, range.end.row-1);
+ lines.unshift((this.$lines[range.start.row] || "").substring(range.start.column));
+ lines.push((this.$lines[range.end.row] || "").substring(0, range.end.column));
+ return lines.join(this.getNewLineCharacter());
+ }
+ };
+
+ /** internal, hide
+ * Document.$clipPosition(position) -> Number
+ *
+ *
+ **/
+ this.$clipPosition = function(position) {
+ var length = this.getLength();
+ if (position.row >= length) {
+ position.row = Math.max(0, length - 1);
+ position.column = this.getLine(length-1).length;
+ }
+ return position;
+ };
+
+ /**
+ * Document.insert(position, text) -> Number
+ * - position (Number): The position to start inserting at
+ * - text (String): A chunk of text to insert
+ * + (Number): The position of the last line of `text`. If the length of `text` is 0, this function simply returns `position`.
+ * Inserts a block of `text` and the indicated `position`.
+ *
+ *
+ **/
+ this.insert = function(position, text) {
+ if (!text || text.length === 0)
+ return position;
+
+ position = this.$clipPosition(position);
+
+ // only detect new lines if the document has no line break yet
+ if (this.getLength() <= 1)
+ this.$detectNewLine(text);
+
+ var lines = this.$split(text);
+ var firstLine = lines.splice(0, 1)[0];
+ var lastLine = lines.length == 0 ? null : lines.splice(lines.length - 1, 1)[0];
+
+ position = this.insertInLine(position, firstLine);
+ if (lastLine !== null) {
+ position = this.insertNewLine(position); // terminate first line
+ position = this.insertLines(position.row, lines);
+ position = this.insertInLine(position, lastLine || "");
+ }
+ return position;
+ };
+
+ /**
+ * Document.insertLines(row, lines) -> Object
+ * - row (Number): The index of the row to insert at
+ * - lines (Array): An array of strings
+ * + (Object): Returns an object containing the final row and column, like this:
+ * ```{row: endRow, column: 0}```
+ * If `lines` is empty, this function returns an object containing the current row, and column, like this:
+ * ```{row: row, column: 0}```
+ *
+ * Inserts the elements in `lines` into the document, starting at the row index given by `row`. This method also triggers the `'change'` event.
+ *
+ *
+ **/
+ this.insertLines = function(row, lines) {
+ if (lines.length == 0)
+ return {row: row, column: 0};
+
+ var args = [row, 0];
+ args.push.apply(args, lines);
+ this.$lines.splice.apply(this.$lines, args);
+
+ var range = new Range(row, 0, row + lines.length, 0);
+ var delta = {
+ action: "insertLines",
+ range: range,
+ lines: lines
+ };
+ this._emit("change", { data: delta });
+ return range.end;
+ };
+
+ /**
+ * Document.insertNewLine(position) -> Object
+ * - position (String): The position to insert at
+ * + (Object): Returns an object containing the final row and column, like this:
+ * ```{row: endRow, column: 0}```
+ *
+ * Inserts a new line into the document at the current row's `position`. This method also triggers the `'change'` event.
+ *
+ *
+ *
+ **/
+ this.insertNewLine = function(position) {
+ position = this.$clipPosition(position);
+ var line = this.$lines[position.row] || "";
+
+ this.$lines[position.row] = line.substring(0, position.column);
+ this.$lines.splice(position.row + 1, 0, line.substring(position.column, line.length));
+
+ var end = {
+ row : position.row + 1,
+ column : 0
+ };
+
+ var delta = {
+ action: "insertText",
+ range: Range.fromPoints(position, end),
+ text: this.getNewLineCharacter()
+ };
+ this._emit("change", { data: delta });
+
+ return end;
+ };
+
+ /**
+ * Document.insertInLine(position, text) -> Object | Number
+ * - position (Number): The position to insert at
+ * - text (String): A chunk of text
+ * + (Object): Returns an object containing the final row and column, like this:
+ * ```{row: endRow, column: 0}```
+ * + (Number): If `text` is empty, this function returns the value of `position`
+ *
+ * Inserts `text` into the `position` at the current row. This method also triggers the `'change'` event.
+ *
+ *
+ *
+ **/
+ this.insertInLine = function(position, text) {
+ if (text.length == 0)
+ return position;
+
+ var line = this.$lines[position.row] || "";
+
+ this.$lines[position.row] = line.substring(0, position.column) + text
+ + line.substring(position.column);
+
+ var end = {
+ row : position.row,
+ column : position.column + text.length
+ };
+
+ var delta = {
+ action: "insertText",
+ range: Range.fromPoints(position, end),
+ text: text
+ };
+ this._emit("change", { data: delta });
+
+ return end;
+ };
+
+ /**
+ * Document.remove(range) -> Object
+ * - range (Range): A specified Range to remove
+ * + (Object): Returns the new `start` property of the range, which contains `startRow` and `startColumn`. If `range` is empty, this function returns the unmodified value of `range.start`.
+ *
+ * Removes the `range` from the document.
+ *
+ *
+ **/
+ this.remove = function(range) {
+ // clip to document
+ range.start = this.$clipPosition(range.start);
+ range.end = this.$clipPosition(range.end);
+
+ if (range.isEmpty())
+ return range.start;
+
+ var firstRow = range.start.row;
+ var lastRow = range.end.row;
+
+ if (range.isMultiLine()) {
+ var firstFullRow = range.start.column == 0 ? firstRow : firstRow + 1;
+ var lastFullRow = lastRow - 1;
+
+ if (range.end.column > 0)
+ this.removeInLine(lastRow, 0, range.end.column);
+
+ if (lastFullRow >= firstFullRow)
+ this.removeLines(firstFullRow, lastFullRow);
+
+ if (firstFullRow != firstRow) {
+ this.removeInLine(firstRow, range.start.column, this.getLine(firstRow).length);
+ this.removeNewLine(range.start.row);
+ }
+ }
+ else {
+ this.removeInLine(firstRow, range.start.column, range.end.column);
+ }
+ return range.start;
+ };
+
+ /**
+ * Document.removeInLine(row, startColumn, endColumn) -> Object
+ * - row (Number): The row to remove from
+ * - startColumn (Number): The column to start removing at
+ * - endColumn (Number): The column to stop removing at
+ * + (Object): Returns an object containing `startRow` and `startColumn`, indicating the new row and column values.
If `startColumn` is equal to `endColumn`, this function returns nothing.
+ *
+ * Removes the specified columns from the `row`. This method also triggers the `'change'` event.
+ *
+ *
+ **/
+ this.removeInLine = function(row, startColumn, endColumn) {
+ if (startColumn == endColumn)
+ return;
+
+ var range = new Range(row, startColumn, row, endColumn);
+ var line = this.getLine(row);
+ var removed = line.substring(startColumn, endColumn);
+ var newLine = line.substring(0, startColumn) + line.substring(endColumn, line.length);
+ this.$lines.splice(row, 1, newLine);
+
+ var delta = {
+ action: "removeText",
+ range: range,
+ text: removed
+ };
+ this._emit("change", { data: delta });
+ return range.start;
+ };
+
+ /**
+ * Document.removeLines(firstRow, lastRow) -> [String]
+ * - firstRow (Number): The first row to be removed
+ * - lastRow (Number): The last row to be removed
+ * + ([String]): Returns all the removed lines.
+ *
+ * Removes a range of full lines. This method also triggers the `'change'` event.
+ *
+ *
+ **/
+ this.removeLines = function(firstRow, lastRow) {
+ var range = new Range(firstRow, 0, lastRow + 1, 0);
+ var removed = this.$lines.splice(firstRow, lastRow - firstRow + 1);
+
+ var delta = {
+ action: "removeLines",
+ range: range,
+ nl: this.getNewLineCharacter(),
+ lines: removed
+ };
+ this._emit("change", { data: delta });
+ return removed;
+ };
+
+ /**
+ * Document.removeNewLine(row) -> Void
+ * - row (Number): The row to check
+ *
+ * Removes the new line between `row` and the row immediately following it. This method also triggers the `'change'` event.
+ *
+ **/
+ this.removeNewLine = function(row) {
+ var firstLine = this.getLine(row);
+ var secondLine = this.getLine(row+1);
+
+ var range = new Range(row, firstLine.length, row+1, 0);
+ var line = firstLine + secondLine;
+
+ this.$lines.splice(row, 2, line);
+
+ var delta = {
+ action: "removeText",
+ range: range,
+ text: this.getNewLineCharacter()
+ };
+ this._emit("change", { data: delta });
+ };
+
+ /**
+ * Document.replace(range, text) -> Object
+ * - range (Range): A specified Range to replace
+ * - text (String): The new text to use as a replacement
+ * + (Object): Returns an object containing the final row and column, like this:
+ * {row: endRow, column: 0}
+ * If the text and range are empty, this function returns an object containing the current `range.start` value.
+ * If the text is the exact same as what currently exists, this function returns an object containing the current `range.end` value.
+ *
+ * Replaces a range in the document with the new `text`.
+ *
+ **/
+ this.replace = function(range, text) {
+ if (text.length == 0 && range.isEmpty())
+ return range.start;
+
+ // Shortcut: If the text we want to insert is the same as it is already
+ // in the document, we don't have to replace anything.
+ if (text == this.getTextRange(range))
+ return range.end;
+
+ this.remove(range);
+ if (text) {
+ var end = this.insert(range.start, text);
+ }
+ else {
+ end = range.start;
+ }
+
+ return end;
+ };
+
+ /**
+ * Document.applyDeltas(deltas) -> Void
+ *
+ * Applies all the changes previously accumulated. These can be either `'includeText'`, `'insertLines'`, `'removeText'`, and `'removeLines'`.
+ **/
+ this.applyDeltas = function(deltas) {
+ for (var i=0; i
+ *
+ * * `-2`: (B) is in front of (A), and doesn't intersect with (A)
+ * * `-1`: (B) begins before (A) but ends inside of (A)
+ * * `0`: (B) is completely inside of (A) OR (A) is completely inside of (B)
+ * * `+1`: (B) begins inside of (A) but ends outside of (A)
+ * * `+2`: (B) is after (A) and doesn't intersect with (A)
+ * * `42`: FTW state: (B) ends in (A) but starts outside of (A)
+ *
+ * Compares `this` range (A) with another range (B).
+ *
+ **/
+ this.compareRange = function(range) {
+ var cmp,
+ end = range.end,
+ start = range.start;
+
+ cmp = this.compare(end.row, end.column);
+ if (cmp == 1) {
+ cmp = this.compare(start.row, start.column);
+ if (cmp == 1) {
+ return 2;
+ } else if (cmp == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else if (cmp == -1) {
+ return -2;
+ } else {
+ cmp = this.compare(start.row, start.column);
+ if (cmp == -1) {
+ return -1;
+ } else if (cmp == 1) {
+ return 42;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ /** related to: Range.compare
+ * Range.comparePoint(p) -> Number
+ * - p (Range): A point to compare with
+ * + (Number): This method returns one of the following numbers:
+ * * `0` if the two points are exactly equal
+ * * `-1` if `p.row` is less then the calling range
+ * * `1` if `p.row` is greater than the calling range
+ *
+ * If the starting row of the calling range is equal to `p.row`, and:
+ * * `p.column` is greater than or equal to the calling range's starting column, this returns `0`
+ * * Otherwise, it returns -1
+ *
+ * If the ending row of the calling range is equal to `p.row`, and:
+ * * `p.column` is less than or equal to the calling range's ending column, this returns `0`
+ * * Otherwise, it returns 1
+ *
+ * Checks the row and column points of `p` with the row and column points of the calling range.
+ *
+ *
+ *
+ **/
+ this.comparePoint = function(p) {
+ return this.compare(p.row, p.column);
+ }
+
+ /** related to: Range.comparePoint
+ * Range.containsRange(range) -> Boolean
+ * - range (Range): A range to compare with
+ *
+ * Checks the start and end points of `range` and compares them to the calling range. Returns `true` if the `range` is contained within the caller's range.
+ *
+ **/
+ this.containsRange = function(range) {
+ return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
+ }
+
+ /**
+ * Range.intersects(range) -> Boolean
+ * - range (Range): A range to compare with
+ *
+ * Returns `true` if passed in `range` intersects with the one calling this method.
+ *
+ **/
+ this.intersects = function(range) {
+ var cmp = this.compareRange(range);
+ return (cmp == -1 || cmp == 0 || cmp == 1);
+ }
+
+ /**
+ * Range.isEnd(row, column) -> Boolean
+ * - row (Number): A row point to compare with
+ * - column (Number): A column point to compare with
+ *
+ * Returns `true` if the caller's ending row point is the same as `row`, and if the caller's ending column is the same as `column`.
+ *
+ **/
+ this.isEnd = function(row, column) {
+ return this.end.row == row && this.end.column == column;
+ }
+
+ /**
+ * Range.isStart(row, column) -> Boolean
+ * - row (Number): A row point to compare with
+ * - column (Number): A column point to compare with
+ *
+ * Returns `true` if the caller's starting row point is the same as `row`, and if the caller's starting column is the same as `column`.
+ *
+ **/
+ this.isStart = function(row, column) {
+ return this.start.row == row && this.start.column == column;
+ }
+
+ /**
+ * Range.setStart(row, column)
+ * - row (Number): A row point to set
+ * - column (Number): A column point to set
+ *
+ * Sets the starting row and column for the range.
+ *
+ **/
+ this.setStart = function(row, column) {
+ if (typeof row == "object") {
+ this.start.column = row.column;
+ this.start.row = row.row;
+ } else {
+ this.start.row = row;
+ this.start.column = column;
+ }
+ }
+
+ /**
+ * Range.setEnd(row, column)
+ * - row (Number): A row point to set
+ * - column (Number): A column point to set
+ *
+ * Sets the starting row and column for the range.
+ *
+ **/
+ this.setEnd = function(row, column) {
+ if (typeof row == "object") {
+ this.end.column = row.column;
+ this.end.row = row.row;
+ } else {
+ this.end.row = row;
+ this.end.column = column;
+ }
+ }
+
+ /** related to: Range.compare
+ * Range.inside(row, column) -> Boolean
+ * - row (Number): A row point to compare with
+ * - column (Number): A column point to compare with
+ *
+ * Returns `true` if the `row` and `column` are within the given range.
+ *
+ **/
+ this.inside = function(row, column) {
+ if (this.compare(row, column) == 0) {
+ if (this.isEnd(row, column) || this.isStart(row, column)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** related to: Range.compare
+ * Range.insideStart(row, column) -> Boolean
+ * - row (Number): A row point to compare with
+ * - column (Number): A column point to compare with
+ *
+ * Returns `true` if the `row` and `column` are within the given range's starting points.
+ *
+ **/
+ this.insideStart = function(row, column) {
+ if (this.compare(row, column) == 0) {
+ if (this.isEnd(row, column)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** related to: Range.compare
+ * Range.insideEnd(row, column) -> Boolean
+ * - row (Number): A row point to compare with
+ * - column (Number): A column point to compare with
+ *
+ * Returns `true` if the `row` and `column` are within the given range's ending points.
+ *
+ **/
+ this.insideEnd = function(row, column) {
+ if (this.compare(row, column) == 0) {
+ if (this.isStart(row, column)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Range.compare(row, column) -> Number
+ * - row (Number): A row point to compare with
+ * - column (Number): A column point to compare with
+ * + (Number): This method returns one of the following numbers:
+ * * `0` if the two points are exactly equal
+ * * `-1` if `p.row` is less then the calling range
+ * * `1` if `p.row` is greater than the calling range
+ *
+ * If the starting row of the calling range is equal to `p.row`, and:
+ * * `p.column` is greater than or equal to the calling range's starting column, this returns `0`
+ * * Otherwise, it returns -1
+ *
+ * If the ending row of the calling range is equal to `p.row`, and:
+ * * `p.column` is less than or equal to the calling range's ending column, this returns `0`
+ * * Otherwise, it returns 1
+ *
+ * Checks the row and column points with the row and column points of the calling range.
+ *
+ *
+ **/
+ this.compare = function(row, column) {
+ if (!this.isMultiLine()) {
+ if (row === this.start.row) {
+ return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
+ };
+ }
+
+ if (row < this.start.row)
+ return -1;
+
+ if (row > this.end.row)
+ return 1;
+
+ if (this.start.row === row)
+ return column >= this.start.column ? 0 : -1;
+
+ if (this.end.row === row)
+ return column <= this.end.column ? 0 : 1;
+
+ return 0;
+ };
+
+ /**
+ * Range.compareStart(row, column) -> Number
+ * - row (Number): A row point to compare with
+ * - column (Number): A column point to compare with
+ * + (Number): This method returns one of the following numbers:
+ *
+ * * `0` if the two points are exactly equal
+ * * `-1` if `p.row` is less then the calling range
+ * * `1` if `p.row` is greater than the calling range, or if `isStart` is `true`.
+ *
+ * If the starting row of the calling range is equal to `p.row`, and:
+ * * `p.column` is greater than or equal to the calling range's starting column, this returns `0`
+ * * Otherwise, it returns -1
+ *
+ * If the ending row of the calling range is equal to `p.row`, and:
+ * * `p.column` is less than or equal to the calling range's ending column, this returns `0`
+ * * Otherwise, it returns 1
+ *
+ * Checks the row and column points with the row and column points of the calling range.
+ *
+ *
+ *
+ **/
+ this.compareStart = function(row, column) {
+ if (this.start.row == row && this.start.column == column) {
+ return -1;
+ } else {
+ return this.compare(row, column);
+ }
+ }
+
+ /**
+ * Range.compareEnd(row, column) -> Number
+ * - row (Number): A row point to compare with
+ * - column (Number): A column point to compare with
+ * + (Number): This method returns one of the following numbers:
+ * * `0` if the two points are exactly equal
+ * * `-1` if `p.row` is less then the calling range
+ * * `1` if `p.row` is greater than the calling range, or if `isEnd` is `true.
+ *
+ * If the starting row of the calling range is equal to `p.row`, and:
+ * * `p.column` is greater than or equal to the calling range's starting column, this returns `0`
+ * * Otherwise, it returns -1
+ *
+ * If the ending row of the calling range is equal to `p.row`, and:
+ * * `p.column` is less than or equal to the calling range's ending column, this returns `0`
+ * * Otherwise, it returns 1
+ *
+ * Checks the row and column points with the row and column points of the calling range.
+ *
+ *
+ **/
+ this.compareEnd = function(row, column) {
+ if (this.end.row == row && this.end.column == column) {
+ return 1;
+ } else {
+ return this.compare(row, column);
+ }
+ }
+
+ /**
+ * Range.compareInside(row, column) -> Number
+ * - row (Number): A row point to compare with
+ * - column (Number): A column point to compare with
+ * + (Number): This method returns one of the following numbers:
+ * * `1` if the ending row of the calling range is equal to `row`, and the ending column of the calling range is equal to `column`
+ * * `-1` if the starting row of the calling range is equal to `row`, and the starting column of the calling range is equal to `column`
+ *
+ * Otherwise, it returns the value after calling [[Range.compare `compare()`]].
+ *
+ * Checks the row and column points with the row and column points of the calling range.
+ *
+ *
+ *
+ **/
+ this.compareInside = function(row, column) {
+ if (this.end.row == row && this.end.column == column) {
+ return 1;
+ } else if (this.start.row == row && this.start.column == column) {
+ return -1;
+ } else {
+ return this.compare(row, column);
+ }
+ }
+
+ /**
+ * Range.clipRows(firstRow, lastRow) -> Range
+ * - firstRow (Number): The starting row
+ * - lastRow (Number): The ending row
+ *
+ * Returns the part of the current `Range` that occurs within the boundaries of `firstRow` and `lastRow` as a new `Range` object.
+ *
+ **/
+ this.clipRows = function(firstRow, lastRow) {
+ if (this.end.row > lastRow) {
+ var end = {
+ row: lastRow+1,
+ column: 0
+ };
+ }
+
+ if (this.start.row > lastRow) {
+ var start = {
+ row: lastRow+1,
+ column: 0
+ };
+ }
+
+ if (this.start.row < firstRow) {
+ var start = {
+ row: firstRow,
+ column: 0
+ };
+ }
+
+ if (this.end.row < firstRow) {
+ var end = {
+ row: firstRow,
+ column: 0
+ };
+ }
+ return Range.fromPoints(start || this.start, end || this.end);
+ };
+
+ /**
+ * Range.extend(row, column) -> Range
+ * - row (Number): A new row to extend to
+ * - column (Number): A new column to extend to
+ *
+ * Changes the row and column points for the calling range for both the starting and ending points. This method returns that range with a new row.
+ *
+ **/
+ this.extend = function(row, column) {
+ var cmp = this.compare(row, column);
+
+ if (cmp == 0)
+ return this;
+ else if (cmp == -1)
+ var start = {row: row, column: column};
+ else
+ var end = {row: row, column: column};
+
+ return Range.fromPoints(start || this.start, end || this.end);
+ };
+
+ this.isEmpty = function() {
+ return (this.start.row == this.end.row && this.start.column == this.end.column);
+ };
+
+ /**
+ * Range.isMultiLine() -> Boolean
+ *
+ * Returns true if the range spans across multiple lines.
+ *
+ **/
+ this.isMultiLine = function() {
+ return (this.start.row !== this.end.row);
+ };
+
+ /**
+ * Range.clone() -> Range
+ *
+ * Returns a duplicate of the calling range.
+ *
+ **/
+ this.clone = function() {
+ return Range.fromPoints(this.start, this.end);
+ };
+
+ /**
+ * Range.collapseRows() -> Range
+ *
+ * Returns a range containing the starting and ending rows of the original range, but with a column value of `0`.
+ *
+ **/
+ this.collapseRows = function() {
+ if (this.end.column == 0)
+ return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0)
+ else
+ return new Range(this.start.row, 0, this.end.row, 0)
+ };
+
+ /**
+ * Range.toScreenRange(session) -> Range
+ * - session (EditSession): The `EditSession` to retrieve coordinates from
+ *
+ * Given the current `Range`, this function converts those starting and ending points into screen positions, and then returns a new `Range` object.
+ **/
+ this.toScreenRange = function(session) {
+ var screenPosStart =
+ session.documentToScreenPosition(this.start);
+ var screenPosEnd =
+ session.documentToScreenPosition(this.end);
+
+ return new Range(
+ screenPosStart.row, screenPosStart.column,
+ screenPosEnd.row, screenPosEnd.column
+ );
+ };
+
+}).call(Range.prototype);
+
+/**
+ * Range.fromPoints(start, end) -> Range
+ * - start (Range): A starting point to use
+ * - end (Range): An ending point to use
+ *
+ * Creates and returns a new `Range` based on the row and column of the given parameters.
+ *
+**/
+Range.fromPoints = function(start, end) {
+ return new Range(start.row, start.column, end.row, end.column);
+};
+
+exports.Range = Range;
+});
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Ajax.org Code Editor (ACE).
+ *
+ * The Initial Developer of the Original Code is
+ * Ajax.org B.V.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Fabian Jakobs
+ * org.antlr.namespace("really.long.nested.namespace");
+ *
+ * This fails because "long" is a future reserved word in ECMAScript
+ *
+ * @static
+ * @param {String*} arguments 1-n namespaces to create
+ * @return {Object} A reference to the last namespace object created
+ * @example
+ * org.antlr.namespace("org.antlr.property.package");
+ */
+org.antlr.namespace = function() {
+ var a=arguments, o=null, i, j, d;
+ for (i=0; i
+ *
+ *
+ * ((BitSet)obj).get(k) == this.get(k)
+ *
+ * must be true. The current sizes of the two bit sets are not compared.
+ * @param {Object} other the object to compare with.
+ * @returns {Boolean} if the objects are the same; false otherwise.
+ */
+ equals: function(other) {
+ if ( !other || !(other instanceof org.antlr.runtime.BitSet) ) {
+ return false;
+ }
+
+ var otherSet = other,
+ i,
+ n = Math.min(this.bits.length, otherSet.bits.length);
+
+ // for any bits in common, compare
+ for (i=0; iFor every index for which this BitSet contains a bit in the set state, + * the decimal representation of that index is included in the result. + * Such indices are listed in order from lowest to highest, separated by + * ", " (a comma and a space) and surrounded by braces, resulting in the + * usual mathematical notation for a set of integers.
+ * + *If a grammar g is passed, print g.getTokenDisplayName(i) for each set + * index instead of the numerical index.
+ * + * <>If two arguments are passed, the first will be used as a custom + * separator string. The second argument is an array whose i-th element + * will be added if the corresponding bit is set. + * + * @param {Object|String} [arg1] an Object with function property + * getTokenDispalyName or a String that will be used as a list + * separator. + * @param {Array} [vocabulary] array from which the i-th value will be + * drawn if the corresponding bit is set. Must pass a string as the + * first argument if using this option. + * @return A commma-separated list of values + */ + toString: function() { + if (arguments.length===0) { + return this.toString1(null); + } else { + if (org.antlr.lang.isString(arguments[0])) { + if (!org.antlr.lang.isValue(arguments[1])) { + return this.toString1(null); + } else { + return this.toString2(arguments[0], arguments[1]); + } + } else { + return this.toString1(arguments[0]); + } + } + }, + + /** + * Transform a bit set into a string by formatting each element as an + * integer separator The string to put in between elements + * @private + * @return A commma-separated list of values + */ + toString1: function(g) { + var buf = "{", + separator = ",", + i, + havePrintedAnElement = false; + + for (i = 0; i < (this.bits.length << org.antlr.runtime.BitSet.LOG_BITS); i++) { + if (this.member(i)) { + if (i > 0 && havePrintedAnElement ) { + buf += separator; + } + if ( g ) { + buf += g.getTokenDisplayName(i); + } + else { + buf += i.toString(); + } + havePrintedAnElement = true; + } + } + return buf + "}"; + }, + + /** + * Create a string representation where instead of integer elements, the + * ith element of vocabulary is displayed instead. Vocabulary is a Vector + * of Strings. + * separator The string to put in between elements + * @private + * @return A commma-separated list of character constants. + */ + toString2: function(separator, vocabulary) { + var str = "", + i; + for (i = 0; i < (this.bits.length << org.antlr.runtime.BitSet.LOG_BITS); i++) { + if (this.member(i)) { + if (str.length > 0) { + str += separator; + } + if (i >= vocabulary.size()) { + str += "'" + i + "'"; + } + else if (!org.antlr.lang.isValue(vocabulary.get(i))) { + str += "'" + i + "'"; + } + else { + str += vocabulary.get(i); + } + } + } + return str; + } + + /* + * Dump a comma-separated list of the words making up the bit set. + * Split each 32 bit number into two more manageable 16 bit numbers. + * @returns {String} comma separated list view of the this.bits property. + * + toStringOfHalfWords: function() { + var s = "", + tmp, + i; + for (i = 0; i < this.bits.length; i++) { + if (i !== 0) { + s+=", "; + } + tmp = this.bits[i]; + tmp &= 0xFFFF; + s += tmp + "UL, "; + tmp = this.bits[i] >> 16; + tmp &= 0xFFFF; + s += tmp+"UL"; + } + return s; + }, + */ + + /* + * Dump a comma-separated list of the words making up the bit set. + * This generates a comma-separated list of Java-like long int constants. + * + toStringOfWords: function() { + var s="", + i; + for (i = 0; i < this.bits.length; i++) { + if (i !== 0) { + s+=", "; + } + s += this.bits[i]+"L"; + } + return s; + }, + + toStringWithRanges: function() { + return this.toString(); + } + */ +}; + +/* + * + * +org.antlr.runtime.IntervalSet = function() { + throw new Error("not implemented"); +}; +*/ +org.antlr.runtime.CharStream = { + EOF: -1 +}; +org.antlr.runtime.CommonToken = function() { + var oldToken; + + this.charPositionInLine = -1; // set to invalid position + this.channel = 0; // org.antlr.runtime.CommonToken.DEFAULT_CHANNEL + this.index = -1; + + if (arguments.length == 1) { + if (org.antlr.lang.isNumber(arguments[0])) { + this.type = arguments[0]; + } else { + oldToken = arguments[0]; + this.text = oldToken.getText(); + this.type = oldToken.getType(); + this.line = oldToken.getLine(); + this.index = oldToken.getTokenIndex(); + this.charPositionInLine = oldToken.getCharPositionInLine(); + this.channel = oldToken.getChannel(); + if ( oldToken instanceof org.antlr.runtime.CommonToken ) { + this.start = oldToken.start; + this.stop = oldToken.stop; + } + } + } else if (arguments.length == 2) { + this.type = arguments[0]; + this.text = arguments[1]; + this.channel = 0; // org.antlr.runtime.CommonToken.DEFAULT_CHANNEL + } else if (arguments.length == 5) { + this.input = arguments[0]; + this.type = arguments[1]; + this.channel = arguments[2]; + this.start = arguments[3]; + this.stop = arguments[4]; + } +}; + +org.antlr.runtime.CommonToken.prototype = { + getType: function() { + return this.type; + }, + + setLine: function(line) { + this.line = line; + }, + + getText: function() { + if ( org.antlr.lang.isString(this.text) ) { + return this.text; + } + if ( !this.input ) { + return null; + } + this.text = this.input.substring(this.start,this.stop); + return this.text; + }, + + /** Override the text for this token. getText() will return this text + * rather than pulling from the buffer. Note that this does not mean + * that start/stop indexes are not valid. It means that that input + * was converted to a new string in the token object. + */ + setText: function(text) { + this.text = text; + }, + + getLine: function() { + return this.line; + }, + + getCharPositionInLine: function() { + return this.charPositionInLine; + }, + + setCharPositionInLine: function(charPositionInLine) { + this.charPositionInLine = charPositionInLine; + }, + + getChannel: function() { + return this.channel; + }, + + setChannel: function(channel) { + this.channel = channel; + }, + + setType: function(type) { + this.type = type; + }, + + getStartIndex: function() { + return this.start; + }, + + setStartIndex: function(start) { + this.start = start; + }, + + getStopIndex: function() { + return this.stop; + }, + + setStopIndex: function(stop) { + this.stop = stop; + }, + + getTokenIndex: function() { + return this.index; + }, + + setTokenIndex: function(index) { + this.index = index; + }, + + getInputStream: function() { + return this.input; + }, + + setInputStream: function(input) { + this.input = input; + }, + + toString: function() { + var channelStr = ""; + if ( this.channel>0 ) { + channelStr=",channel="+this.channel; + } + var txt = this.getText(); + if ( !org.antlr.lang.isNull(txt) ) { + txt = txt.replace(/\n/g,"\\\\n"); + txt = txt.replace(/\r/g,"\\\\r"); + txt = txt.replace(/\t/g,"\\\\t"); + } + else { + txt = "Marking is a mechanism for storing the current position of a stream + * in a stack. This corresponds with the predictive look-ahead mechanism + * used in Lexers.
+ * @returns {Number} the current size of the mark stack. + */ + mark: function() { + if ( !this.markers ) { + this.markers = []; + this.markers.push(null); // depth 0 means no backtracking, leave blank + } + this.markDepth++; + var state = null; + if ( this.markDepth>=this.markers.length ) { + state = {}; + this.markers.push(state); + } + else { + state = this.markers[this.markDepth]; + } + state.p = this.p; + state.line = this.line; + state.charPositionInLine = this.charPositionInLine; + this.lastMarker = this.markDepth; + return this.markDepth; + }, + + /** + * Rewind to the input position of the last marker. + * Used currently only after a cyclic DFA and just + * before starting a sem/syn predicate to get the + * input position back to the start of the decision. + * Do not "pop" the marker off the state. mark(i) + * and rewind(i) should balance still. It is + * like invoking rewind(last marker) but it should not "pop" + * the marker off. It's like seek(last marker's input position). + * @param {Number} [m] the index in the mark stack to load instead of the + * last. + */ + rewind: function(m) { + if (!org.antlr.lang.isNumber(m)) { + m = this.lastMarker; + } + + var state = this.markers[m]; + // restore stream state + this.seek(state.p); + this.line = state.line; + this.charPositionInLine = state.charPositionInLine; + this.release(m); + }, + + /** + * You may want to commit to a backtrack but don't want to force the + * stream to keep bookkeeping objects around for a marker that is + * no longer necessary. This will have the same behavior as + * rewind() except it releases resources without the backward seek. + * This must throw away resources for all markers back to the marker + * argument. So if you're nested 5 levels of mark(), and then release(2) + * you have to release resources for depths 2..5. + * @param {Number} marker the mark depth above which all mark states will + * be released. + */ + release: function(marker) { + // unwind any other markers made after m and release m + this.markDepth = marker; + // release this marker + this.markDepth--; + }, + + /** + * Set the input cursor to the position indicated by index. This is + * normally used to seek ahead in the input stream. No buffering is + * required to do this unless you know your stream will use seek to + * move backwards such as when backtracking. + * + *This is different from rewind in its multi-directional + * requirement and in that its argument is strictly an input cursor + * (index).
+ * + *For char streams, seeking forward must update the stream state such + * as line number. For seeking backwards, you will be presumably + * backtracking using the mark/rewind mechanism that restores state and + * so this method does not need to update state when seeking backwards.
+ * + *Currently, this method is only used for efficient backtracking using + * memoization, but in the future it may be used for incremental + * parsing.
+ * + *The index is 0..n-1. A seek to position i means that LA(1) will + * return the ith symbol. So, seeking to 0 means LA(1) will return the + * first element in the stream.
+ * + *Esentially this method method moves the input position, + * {@link #consume}-ing data if necessary.
+ * + * @param {Number} index the position to seek to. + */ + seek: function(index) { + if ( index<=this.p ) { + this.p = index; // just jump; don't update stream state (line, ...) + return; + } + // seek forward, consume until p hits index + while ( this.pThis class should not be instantiated directly. Instead, use one of its + * subclasses.
+ * + * @class + * @param {org.antlr.runtime.RecognizerSharedState} [state] optional state object + * with which to initialize this recognizer. + */ +org.antlr.runtime.BaseRecognizer = function(state) { + /** State of a lexer, parser, or tree parser are collected into a state + * object so the state can be shared. This sharing is needed to + * have one grammar import others and share same error variables + * and other state variables. It's a kind of explicit multiple + * inheritance via delegation of methods and shared state. + */ + this.state = state || new org.antlr.runtime.RecognizerSharedState(); +}; + +/* static vars, methods */ +org.antlr.lang.augmentObject(org.antlr.runtime.BaseRecognizer, { + MEMO_RULE_FAILED: -2, + MEMO_RULE_UNKNOWN: -1, + INITIAL_FOLLOW_STACK_SIZE: 100, + MEMO_RULE_FAILED_I: -2, + DEFAULT_TOKEN_CHANNEL: org.antlr.runtime.Token.DEFAULT_CHANNEL, + HIDDEN: org.antlr.runtime.Token.HIDDEN_CHANNEL, + NEXT_TOKEN_RULE_NAME: "nextToken" +}); + +org.antlr.runtime.BaseRecognizer.prototype = { + /** Reset the parser's state. Subclasses must rewinds the input stream */ + reset: function() { + var i, len; + + // wack everything related to error recovery + if (!this.state) { + return; // no shared state work to do + } + this.state._fsp = -1; + this.state.errorRecovery = false; + this.state.lastErrorIndex = -1; + this.state.failed = false; + this.state.syntaxErrors = 0; + // wack everything related to backtracking and memoization + this.state.backtracking = 0; + // wipe cache + if (this.state.ruleMemo) { + for (i=0, len=this.state.ruleMemo.length; iThis method sets errorRecovery to indicate the parser is recovering + * not parsing. Once in recovery mode, no errors are generated. + * To get out of recovery mode, the parser must successfully match + * a token (after a resync). So it will go:
+ *If you override, make sure to update this.state.syntaxErrors if you + * care about that.
+ * @param {org.antlr.runtime.RecognitionException} e the error to be reported. + */ + reportError: function(e) { + if(this.input.size() != 0) { + var token = this.input.get(e.index); + var errorMessage = ""; + var column = 0; + var line = 0; + if(token.getType() == -1) { + token = this.input.get(this.input.size() - 1); + } + errorMessage = this.getErrorMessage(e, this.getTokenNames()); + column = token.getStartIndex(); + line = token.getLine() - 1; + + var error = { + line: line, + message: errorMessage, + column: column + }; + this.addError(error); + } + // if we've already reported an error and have not matched a token + // yet successfully, don't report any errors. + if ( this.state.errorRecovery ) { + return; + } + this.state.syntaxErrors++; + this.state.errorRecovery = true; + + this.displayRecognitionError(this.getTokenNames(), e); + }, + + /** + * Assemble recognition error message. + * @param {Array} tokenNames array of token names (strings). + * @param {org.antlr.runtime.RecognitionException} e the error to be reported. + */ + displayRecognitionError: function(tokenNames, e) { + var hdr = this.getErrorHeader(e), + msg = this.getErrorMessage(e, tokenNames); + this.emitErrorMessage(hdr+" "+msg); + }, + + /** + * Create error header message. Format isline + * lineNumber:positionInLine. + * @param {org.antlr.runtime.RecognitionException} e the error to be reported. + * @returns {String} The error header. + */ + getErrorHeader: function(e) { + /* handle null input */ + if (!org.antlr.lang.isNumber(e.line)) { + e.line = 0; + } + return "line "+e.line+":"+e.charPositionInLine; + }, + + /** + * Override this method to change where error messages go. + * Defaults to "alert"-ing the error in browsers and "print"-ing the error + * in other environments (e.g. Rhino, SpiderMonkey). + * @param {String} msg the error message to be displayed. + */ + emitErrorMessage: function(msg) { + //throw msg; + console.log(msg); + }, + + /** What error message should be generated for the various + * exception types? + * + *
Not very object-oriented code, but I like having all error message + * generation within one method rather than spread among all of the + * exception classes. This also makes it much easier for the exception + * handling because the exception classes do not have to have pointers back + * to this object to access utility routines and so on. Also, changing + * the message for an exception type would be difficult because you + * would have to be subclassing exceptions, but then somehow get ANTLR + * to make those kinds of exception objects instead of the default.
+ * + *For grammar debugging, you will want to override this to add + * more information such as the stack frame and no viable alts.
+ * + *Override this to change the message generated for one or more + * exception types.
+ * + * @param {Array} tokenNames array of token names (strings). + * @param {org.antlr.runtime.RecognitionException} e the error to be reported. + * @returns {String} the error message to be emitted. + */ + getErrorMessage: function(e, tokenNames) { + var msg = (e && e.getMessage) ? e.getMessage() : null, + mte, + tokenName; + if ( e instanceof org.antlr.runtime.UnwantedTokenException ) { + var ute = e; + tokenName="