Codemirror IMPROVEMENT
- Codemirror tenia varias opciones que eran incompatibles con la version de procesmaker y ie. - Se pudo el codmirror antiguo para las secciones del Designer en el xml y javascript para evitar esos errores. - se pudo el mismo codigo para las 3 navegadores chrome, firefox, ie.
This commit is contained in:
23
gulliver/js/codemirrorOld/contrib/scheme/LICENSE
Normal file
23
gulliver/js/codemirrorOld/contrib/scheme/LICENSE
Normal file
@@ -0,0 +1,23 @@
|
||||
Copyright (c) 2010 Danny Yoo
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any
|
||||
damages arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any
|
||||
purpose, including commercial applications, and to alter it and
|
||||
redistribute it freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must
|
||||
not claim that you wrote the original software. If you use this
|
||||
software in a product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must
|
||||
not be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
Danny Yoo
|
||||
dyoo@cs.wpi.edu
|
||||
@@ -0,0 +1,45 @@
|
||||
html {
|
||||
cursor: text;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.editbox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0pt;
|
||||
padding: 0;
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
color: black;
|
||||
}
|
||||
|
||||
|
||||
|
||||
pre.code, .editbox {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.editbox p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
span.scheme-string {color: green;}
|
||||
span.scheme-number {color: blue;}
|
||||
span.scheme-boolean {color: darkred;}
|
||||
span.scheme-character {color: orange;}
|
||||
span.scheme-symbol {color: steelblue;}
|
||||
span.scheme-punctuation {color: black;}
|
||||
span.scheme-lparen {color: black;}
|
||||
span.scheme-rparen {color: black;}
|
||||
span.scheme-comment { color: orange; }
|
||||
|
||||
span.good-matching-paren {
|
||||
font-weight: bold;
|
||||
color: #3399FF;
|
||||
}
|
||||
span.bad-matching-paren {
|
||||
font-weight: bold;
|
||||
color: red;
|
||||
}
|
||||
82
gulliver/js/codemirrorOld/contrib/scheme/index.html
Normal file
82
gulliver/js/codemirrorOld/contrib/scheme/index.html
Normal file
@@ -0,0 +1,82 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script src="../../js/codemirror.js" type="text/javascript"></script>
|
||||
<script src="../../js/mirrorframe.js" type="text/javascript"></script>
|
||||
<title>CodeMirror: Scheme demonstration</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../style/docs.css"/>
|
||||
|
||||
<style type="text/css">
|
||||
.CodeMirror-line-numbers {
|
||||
width: 2.2em;
|
||||
color: #aaa;
|
||||
background-color: #eee;
|
||||
text-align: right;
|
||||
padding-right: .3em;
|
||||
font-size: 10pt;
|
||||
font-family: monospace;
|
||||
padding-top: .4em;
|
||||
line-height: normal;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="padding: 20px;">
|
||||
|
||||
<p>This page demonstrates <a href="index.html">CodeMirror</a>'s
|
||||
Scheme parser. (<a href="LICENSE">license</a>)</p>
|
||||
|
||||
<div style="border-top: 1px solid black; border-bottom: 1px solid black;">
|
||||
<textarea id="code" cols="120" rows="30">
|
||||
(define (factorial x)
|
||||
(cond
|
||||
[(= x 0)
|
||||
1]
|
||||
[else
|
||||
(* x (factorial (sub1 x)))]))
|
||||
|
||||
(list "This is a string"
|
||||
'boolean
|
||||
true
|
||||
3.14)
|
||||
|
||||
(local [(define x 42)]
|
||||
(printf "ok~n"))
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
function addClass(element, className) {
|
||||
if (!editor.win.hasClass(element, className)) {
|
||||
element.className = ((element.className.split(" ")).concat([className])).join(" ");
|
||||
}
|
||||
}
|
||||
|
||||
function removeClass(element, className) {
|
||||
if (editor.win.hasClass(element, className)) {
|
||||
var classes = element.className.split(" ");
|
||||
for (var i = classes.length - 1 ; i >= 0; i--) {
|
||||
if (classes[i] === className) {
|
||||
classes.splice(i, 1);
|
||||
}
|
||||
}
|
||||
element.className = classes.join(" ");
|
||||
}
|
||||
}
|
||||
|
||||
var textarea = document.getElementById('code');
|
||||
var editor = new CodeMirror(CodeMirror.replace(textarea), {
|
||||
height: "350px",
|
||||
content: textarea.value,
|
||||
path: "../../js/",
|
||||
parserfile: ["../contrib/scheme/js/tokenizescheme.js",
|
||||
"../contrib/scheme/js/parsescheme.js"],
|
||||
stylesheet: "style/schemecolors.css",
|
||||
autoMatchParens: true,
|
||||
disableSpellcheck: true,
|
||||
lineNumbers: true,
|
||||
markParen: function(span, good) {addClass(span, good ? "good-matching-paren" : "bad-matching-paren");},
|
||||
unmarkParen: function(span) {removeClass(span, "good-matching-paren"); removeClass(span, "bad-matching-paren");}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
428
gulliver/js/codemirrorOld/contrib/scheme/js/parsescheme.js
Normal file
428
gulliver/js/codemirrorOld/contrib/scheme/js/parsescheme.js
Normal file
@@ -0,0 +1,428 @@
|
||||
var SchemeParser = Editor.Parser = (function() {
|
||||
|
||||
|
||||
// isLparen: char -> boolean
|
||||
var isLparen = function(ch) {
|
||||
return ch === '(' || ch === '[' || ch === '{';
|
||||
};
|
||||
|
||||
// isRparen: char -> boolean
|
||||
var isRparen = function(ch) {
|
||||
return ch === ')' || ch === ']' || ch === '}';
|
||||
};
|
||||
|
||||
// isMatchingParens: char char -> boolean
|
||||
var isMatchingParens = function(lparen, rparen) {
|
||||
return ((lparen === '(' && rparen === ')') ||
|
||||
(lparen === '[' && rparen === ']') ||
|
||||
(lparen === '{' && rparen === '}'));
|
||||
};
|
||||
|
||||
|
||||
// Compute the indentation context enclosing the end of the token
|
||||
// sequence tokens.
|
||||
// The context is the token sequence of the enclosing s-expression,
|
||||
// augmented with column information.
|
||||
var getIndentationContext = function(tokenStack) {
|
||||
var EMPTY_CONTEXT = [];
|
||||
|
||||
var pendingParens = [], i = 0, j, line, column, context;
|
||||
var tokens = [];
|
||||
|
||||
// Scan for the start of the indentation context, accumulating tokens.
|
||||
while (! isEmptyPair(tokenStack)) {
|
||||
i++;
|
||||
tokens.push(pairFirst(tokenStack));
|
||||
if (isLparen(pairFirst(tokenStack).type)) {
|
||||
if (pendingParens.length === 0) {
|
||||
break;
|
||||
} else {
|
||||
if (isMatchingParens(pairFirst(tokenStack).value,
|
||||
pendingParens[pendingParens.length - 1])) {
|
||||
pendingParens.pop();
|
||||
} else {
|
||||
// Error condition: we see mismatching parens,
|
||||
// so we exit with no known indentation context.
|
||||
return EMPTY_CONTEXT;
|
||||
}
|
||||
}
|
||||
} else if (isRparen(pairFirst(tokenStack).type)) {
|
||||
pendingParens.push(pairFirst(tokenStack).type);
|
||||
}
|
||||
tokenStack = pairRest(tokenStack);
|
||||
}
|
||||
|
||||
// If we scanned backward too far, we couldn't find a context. Just
|
||||
// return the empty context.
|
||||
if (isEmptyPair(tokenStack)) {
|
||||
return EMPTY_CONTEXT;
|
||||
}
|
||||
|
||||
// Position tokenStack to the next token beyond.
|
||||
tokenStack = pairRest(tokenStack);
|
||||
|
||||
// We now scan backwards to closest newline to figure out the column
|
||||
// number:
|
||||
while (! isEmptyPair(tokenStack)) {
|
||||
if(pairFirst(tokenStack).type === 'whitespace' &&
|
||||
pairFirst(tokenStack).value === '\n') {
|
||||
break;
|
||||
}
|
||||
tokens.push(pairFirst(tokenStack));
|
||||
tokenStack = pairRest(tokenStack);
|
||||
}
|
||||
|
||||
line = 0;
|
||||
column = 0;
|
||||
context = [];
|
||||
// Start generating the context, walking forward.
|
||||
for (j = tokens.length-1; j >= 0; j--) {
|
||||
if (j < i) {
|
||||
context.push({ type: tokens[j].type,
|
||||
value: tokens[j].value,
|
||||
line: line,
|
||||
column: column });
|
||||
}
|
||||
|
||||
if (tokens[j].type === 'whitespace' &&
|
||||
tokens[j].value === '\n') {
|
||||
column = 0;
|
||||
line++;
|
||||
} else {
|
||||
column += tokens[j].value.length;
|
||||
}
|
||||
}
|
||||
return context;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// calculateIndentationFromContext: indentation-context number -> number
|
||||
var calculateIndentationFromContext = function(context, currentIndentation) {
|
||||
if (context.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
if (isBeginLikeContext(context)) {
|
||||
return beginLikeIndentation(context);
|
||||
}
|
||||
if (isDefineLikeContext(context)) {
|
||||
return defineLikeIndentation(context);
|
||||
}
|
||||
if (isLambdaLikeContext(context)) {
|
||||
return lambdaLikeIndentation(context);
|
||||
}
|
||||
return beginLikeIndentation(context, 0);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// findContextElement: indentation-context number -> index or -1
|
||||
var findContextElement = function(context, index) {
|
||||
var depth = 0;
|
||||
for(var i = 0; i < context.length; i++) {
|
||||
if (context[i].type !== 'whitespace' && depth === 1) {
|
||||
if (index === 0)
|
||||
return i;
|
||||
else
|
||||
index--;
|
||||
}
|
||||
|
||||
if (isLparen(context[i].type)) {
|
||||
depth++;
|
||||
}
|
||||
if (isRparen(context[i].type)) {
|
||||
depth = Math.max(depth - 1, 0);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
// contextElement: context -> (arrayof index)
|
||||
var contextElements = function(context) {
|
||||
var i = 0, index, results = [];
|
||||
|
||||
while ((index = findContextElement(context, i++)) != -1) {
|
||||
results.push(index);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
var BEGIN_LIKE_KEYWORDS = ["case-lambda",
|
||||
"compound-unit",
|
||||
"compound-unit/sig",
|
||||
"cond",
|
||||
"delay",
|
||||
"inherit",
|
||||
"match-lambda",
|
||||
"match-lambda*",
|
||||
"override",
|
||||
"private",
|
||||
"public",
|
||||
"sequence",
|
||||
"unit"];
|
||||
|
||||
var isBeginLikeContext = function(context) {
|
||||
var j = findContextElement(context, 0);
|
||||
if (j === -1) { return false; }
|
||||
return (/^begin/.test(context[j].value) ||
|
||||
isMember(context[j].value, BEGIN_LIKE_KEYWORDS));
|
||||
};
|
||||
|
||||
|
||||
// Begin: if there's no elements within the begin context,
|
||||
// the indentation is that of the begin keyword's column + offset.
|
||||
// Otherwise, find the leading element on the last line.
|
||||
// Also used for default indentation.
|
||||
var beginLikeIndentation = function(context, offset) {
|
||||
if (typeof(offset) === 'undefined') { offset = 1; }
|
||||
|
||||
var indices = contextElements(context), j;
|
||||
if (indices.length === 0) {
|
||||
return context[0].column + 1;
|
||||
} else if (indices.length === 1) {
|
||||
// if we only see the begin keyword, indentation is based
|
||||
// off the keyword.
|
||||
return context[indices[0]].column + offset;
|
||||
} else {
|
||||
// Otherwise, we scan for the contextElement of the last line
|
||||
for (j = indices.length -1; j > 1; j--) {
|
||||
if (context[indices[j]].line !==
|
||||
context[indices[j-1]].line) {
|
||||
return context[indices[j]].column;
|
||||
}
|
||||
}
|
||||
return context[indices[j]].column;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
var DEFINE_LIKE_KEYWORDS = ["local"];
|
||||
|
||||
var isDefineLikeContext = function(context) {
|
||||
var j = findContextElement(context, 0);
|
||||
if (j === -1) { return false; }
|
||||
return (/^def/.test(context[j].value) ||
|
||||
isMember(context[j].value, DEFINE_LIKE_KEYWORDS));
|
||||
};
|
||||
|
||||
|
||||
var defineLikeIndentation = function(context) {
|
||||
var i = findContextElement(context, 0);
|
||||
if (i === -1) { return 0; }
|
||||
return context[i].column +1;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
var LAMBDA_LIKE_KEYWORDS = ["cases",
|
||||
"instantiate",
|
||||
"super-instantiate",
|
||||
"syntax/loc",
|
||||
"quasisyntax/loc",
|
||||
"lambda",
|
||||
"let",
|
||||
"let*",
|
||||
"letrec",
|
||||
"recur",
|
||||
"lambda/kw",
|
||||
"letrec-values",
|
||||
"with-syntax",
|
||||
"with-continuation-mark",
|
||||
"module",
|
||||
"match",
|
||||
"match-let",
|
||||
"match-let*",
|
||||
"match-letrec",
|
||||
"let/cc",
|
||||
"let/ec",
|
||||
"letcc",
|
||||
"catch",
|
||||
"let-syntax",
|
||||
"letrec-syntax",
|
||||
"fluid-let-syntax",
|
||||
"letrec-syntaxes+values",
|
||||
"for",
|
||||
"for/list",
|
||||
"for/hash",
|
||||
"for/hasheq",
|
||||
"for/and",
|
||||
"for/or",
|
||||
"for/lists",
|
||||
"for/first",
|
||||
"for/last",
|
||||
"for/fold",
|
||||
"for*",
|
||||
"for*/list",
|
||||
"for*/hash",
|
||||
"for*/hasheq",
|
||||
"for*/and",
|
||||
"for*/or",
|
||||
"for*/lists",
|
||||
"for*/first",
|
||||
"for*/last",
|
||||
"for*/fold",
|
||||
"kernel-syntax-case",
|
||||
"syntax-case",
|
||||
"syntax-case*",
|
||||
"syntax-rules",
|
||||
"syntax-id-rules",
|
||||
"let-signature",
|
||||
"fluid-let",
|
||||
"let-struct",
|
||||
"let-macro",
|
||||
"let-values",
|
||||
"let*-values",
|
||||
"case",
|
||||
"when",
|
||||
"unless",
|
||||
"let-enumerate",
|
||||
"class",
|
||||
"class*",
|
||||
"class-asi",
|
||||
"class-asi*",
|
||||
"class*/names",
|
||||
"class100",
|
||||
"class100*",
|
||||
"class100-asi",
|
||||
"class100-asi*",
|
||||
"class100*/names",
|
||||
"rec",
|
||||
"make-object",
|
||||
"mixin",
|
||||
"define-some",
|
||||
"do",
|
||||
"opt-lambda",
|
||||
"send*",
|
||||
"with-method",
|
||||
"define-record",
|
||||
"catch",
|
||||
"shared",
|
||||
"unit/sig",
|
||||
"unit/lang",
|
||||
"with-handlers",
|
||||
"interface",
|
||||
"parameterize",
|
||||
"call-with-input-file",
|
||||
"call-with-input-file*",
|
||||
"with-input-from-file",
|
||||
"with-input-from-port",
|
||||
"call-with-output-file",
|
||||
"with-output-to-file",
|
||||
"with-output-to-port",
|
||||
"for-all"];
|
||||
|
||||
|
||||
var isLambdaLikeContext = function(context) {
|
||||
var j = findContextElement(context, 0);
|
||||
if (j === -1) { return false; }
|
||||
return (isMember(context[j].value, LAMBDA_LIKE_KEYWORDS));
|
||||
};
|
||||
|
||||
|
||||
var lambdaLikeIndentation = function(context) {
|
||||
var i = findContextElement(context, 0);
|
||||
if (i === -1) { return 0; }
|
||||
var j = findContextElement(context, 1);
|
||||
if (j === -1) {
|
||||
return context[i].column + 4;
|
||||
} else {
|
||||
return context[i].column + 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
var isMember = function(x, l) {
|
||||
for (var i = 0; i < l.length; i++) {
|
||||
if (x === l[i]) { return true; }
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
var pair = function(x, y) {
|
||||
return [x,y];
|
||||
};
|
||||
var EMPTY_PAIR = [];
|
||||
var pairFirst = function(p) { return p[0]; }
|
||||
var pairRest = function(p) { return p[1]; }
|
||||
var isEmptyPair = function(p) { return p === EMPTY_PAIR; }
|
||||
var pairLength = function(p) {
|
||||
var l = 0;
|
||||
while (! isEmptyPair(p)) {
|
||||
p = pairRest(p);
|
||||
}
|
||||
return l;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
|
||||
var indentTo = function(tokenStack) {
|
||||
return function(tokenText, currentIndentation, direction) {
|
||||
|
||||
// If we're in the middle of an unclosed token,
|
||||
// do not change indentation.
|
||||
if ((! isEmptyPair(tokenStack)) &&
|
||||
(! isEmptyPair(pairRest(tokenStack))) &&
|
||||
(pairFirst(pairRest(tokenStack)).isUnclosed)) {
|
||||
return currentIndentation;
|
||||
}
|
||||
|
||||
var indentationContext =
|
||||
getIndentationContext(tokenStack);
|
||||
return calculateIndentationFromContext(indentationContext,
|
||||
currentIndentation);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
var startParse = function(source) {
|
||||
source = tokenizeScheme(source);
|
||||
var tokenStack = EMPTY_PAIR;
|
||||
var iter = {
|
||||
next: function() {
|
||||
var tok = source.next();
|
||||
tokenStack = pair(tok, tokenStack);
|
||||
if (tok.type === "whitespace") {
|
||||
if (tok.value === "\n") {
|
||||
tok.indentation = indentTo(tokenStack);
|
||||
}
|
||||
}
|
||||
return tok;
|
||||
},
|
||||
|
||||
copy: function() {
|
||||
var _tokenStack = tokenStack;
|
||||
var _tokenState = source.state;
|
||||
return function(_source) {
|
||||
tokenStack = _tokenStack;
|
||||
source = tokenizeScheme(_source, _tokenState);
|
||||
return iter;
|
||||
};
|
||||
}
|
||||
};
|
||||
return iter;
|
||||
};
|
||||
return { make: startParse };
|
||||
})();
|
||||
241
gulliver/js/codemirrorOld/contrib/scheme/js/tokenizescheme.js
Normal file
241
gulliver/js/codemirrorOld/contrib/scheme/js/tokenizescheme.js
Normal file
@@ -0,0 +1,241 @@
|
||||
/* Tokenizer for Scheme code */
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
TODO: follow the definitions in:
|
||||
|
||||
http://docs.racket-lang.org/reference/reader.html
|
||||
|
||||
to the letter; at the moment, we've just done something quick-and-dirty.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
var tokenizeScheme = (function() {
|
||||
var isWhiteSpace = function(ch) {
|
||||
// The messy regexp is because IE's regexp matcher is of the
|
||||
// opinion that non-breaking spaces are no whitespace.
|
||||
return ch != "\n" && /^[\s\u00a0]*$/.test(ch);
|
||||
};
|
||||
|
||||
|
||||
// scanUntilUnescaped: string-stream char -> boolean
|
||||
// Advances the stream until the given character (not preceded by a
|
||||
// backslash) is encountered.
|
||||
// Returns true if we hit end of line without closing.
|
||||
// Returns false otherwise.
|
||||
var scanUntilUnescaped = function(source, end) {
|
||||
var escaped = false;
|
||||
while (true) {
|
||||
if (source.endOfLine()) {
|
||||
return true;
|
||||
}
|
||||
var next = source.next();
|
||||
if (next == end && !escaped)
|
||||
return false;
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Advance the stream until endline.
|
||||
var scanUntilEndline = function(source, end) {
|
||||
while (!source.endOfLine()) {
|
||||
source.next();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Some helper regexps
|
||||
var isHexDigit = /[0-9A-Fa-f]/;
|
||||
|
||||
|
||||
var whitespaceChar = new RegExp("[\\s\\u00a0]");
|
||||
|
||||
var isDelimiterChar =
|
||||
new RegExp("[\\s\\\(\\\)\\\[\\\]\\\{\\\}\\\"\\\,\\\'\\\`\\\;]");
|
||||
|
||||
var isNotDelimiterChar =
|
||||
new RegExp("[^\\s\\\(\\\)\\\[\\\]\\\{\\\}\\\"\\\,\\\'\\\`\\\;]");
|
||||
|
||||
|
||||
var numberHeader = ("(?:(?:\\d+\\/\\d+)|"+
|
||||
( "(?:(?:\\d+\\.\\d+|\\d+\\.|\\.\\d+)(?:[eE][+\\-]?\\d+)?)|")+
|
||||
( "(?:\\d+(?:[eE][+\\-]?\\d+)?))"));
|
||||
var numberPatterns = [
|
||||
// complex numbers
|
||||
new RegExp("^((?:(?:\\#[ei])?[+\\-]?" + numberHeader +")?"
|
||||
+ "(?:[+\\-]" + numberHeader + ")i$)"),
|
||||
/^((?:\#[ei])?[+-]inf.0)$/,
|
||||
/^((?:\#[ei])?[+-]nan.0)$/,
|
||||
new RegExp("^((?:\\#[ei])?[+\\-]?" + numberHeader + "$)"),
|
||||
new RegExp("^0[xX][0-9A-Fa-f]+$")];
|
||||
|
||||
|
||||
// looksLikeNumber: string -> boolean
|
||||
// Returns true if string s looks like a number.
|
||||
var looksLikeNumber = function(s) {
|
||||
for (var i = 0; i < numberPatterns.length; i++) {
|
||||
if (numberPatterns[i].test(s)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
var UNCLOSED_STRING = function(source, setState) {
|
||||
var readNewline = function() {
|
||||
var content = source.get();
|
||||
return { type:'whitespace', style:'whitespace', content: content };
|
||||
};
|
||||
|
||||
var ch = source.peek();
|
||||
if (ch === '\n') {
|
||||
source.next();
|
||||
return readNewline();
|
||||
} else {
|
||||
var isUnclosedString = scanUntilUnescaped(source, '"');
|
||||
if (isUnclosedString) {
|
||||
setState(UNCLOSED_STRING);
|
||||
} else {
|
||||
setState(START);
|
||||
}
|
||||
var content = source.get();
|
||||
return {type: "string", style: "scheme-string", content: content,
|
||||
isUnclosed: isUnclosedString};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
var START = function(source, setState) {
|
||||
// Read a word, look it up in keywords. If not found, it is a
|
||||
// variable, otherwise it is a keyword of the type found.
|
||||
var readWordOrNumber = function() {
|
||||
source.nextWhileMatches(isNotDelimiterChar);
|
||||
var word = source.get();
|
||||
if (looksLikeNumber(word)) {
|
||||
return {type: "number", style: "scheme-number", content: word};
|
||||
} else {
|
||||
return {type: "variable", style: "scheme-symbol", content: word};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var readString = function(quote) {
|
||||
var isUnclosedString = scanUntilUnescaped(source, quote);
|
||||
if (isUnclosedString) {
|
||||
setState(UNCLOSED_STRING);
|
||||
}
|
||||
var word = source.get();
|
||||
return {type: "string", style: "scheme-string", content: word,
|
||||
isUnclosed: isUnclosedString};
|
||||
};
|
||||
|
||||
|
||||
var readPound = function() {
|
||||
var text;
|
||||
// FIXME: handle special things here
|
||||
if (source.equals(";")) {
|
||||
source.next();
|
||||
text = source.get();
|
||||
return {type: text,
|
||||
style:"scheme-symbol",
|
||||
content: text};
|
||||
} else {
|
||||
text = source.get();
|
||||
|
||||
return {type : "symbol",
|
||||
style: "scheme-symbol",
|
||||
content: text};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var readLineComment = function() {
|
||||
scanUntilEndline(source);
|
||||
var text = source.get();
|
||||
return { type: "comment", style: "scheme-comment", content: text};
|
||||
};
|
||||
|
||||
|
||||
var readWhitespace = function() {
|
||||
source.nextWhile(isWhiteSpace);
|
||||
var content = source.get();
|
||||
return { type: 'whitespace', style:'whitespace', content: content };
|
||||
};
|
||||
|
||||
var readNewline = function() {
|
||||
var content = source.get();
|
||||
return { type:'whitespace', style:'whitespace', content: content };
|
||||
};
|
||||
|
||||
|
||||
// Fetch the next token. Dispatches on first character in the
|
||||
// stream, or first two characters when the first is a slash.
|
||||
var ch = source.next();
|
||||
if (ch === '\n') {
|
||||
return readNewline();
|
||||
} else if (whitespaceChar.test(ch)) {
|
||||
return readWhitespace();
|
||||
} else if (ch === "#") {
|
||||
return readPound();
|
||||
} else if (ch ===';') {
|
||||
return readLineComment();
|
||||
} else if (ch === "\"") {
|
||||
return readString(ch);
|
||||
} else if (isDelimiterChar.test(ch)) {
|
||||
return {type: ch, style: "scheme-punctuation"};
|
||||
} else {
|
||||
return readWordOrNumber();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var makeTokenizer = function(source, state) {
|
||||
// Newlines are always a separate token.
|
||||
|
||||
var tokenizer = {
|
||||
state: state,
|
||||
|
||||
take: function(type) {
|
||||
if (typeof(type) == "string")
|
||||
type = {style: type, type: type};
|
||||
|
||||
type.content = (type.content || "") + source.get();
|
||||
type.value = type.content;
|
||||
return type;
|
||||
},
|
||||
|
||||
next: function () {
|
||||
if (!source.more()) throw StopIteration;
|
||||
|
||||
var type;
|
||||
while (!type) {
|
||||
type = tokenizer.state(source, function(s) {
|
||||
tokenizer.state = s;
|
||||
});
|
||||
}
|
||||
var result = this.take(type);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
return tokenizer;
|
||||
};
|
||||
|
||||
|
||||
// The external interface to the tokenizer.
|
||||
return function(source, startState) {
|
||||
return makeTokenizer(source, startState || START);
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user