From 714c05750703bc9c88a545e9654d9bb531bad87d Mon Sep 17 00:00:00 2001 From: Ken Rockot <ken@kenrockot.com> Date: Mon, 11 Jun 2012 06:40:07 +0000 Subject: [PATCH] [scheme] implement correct parsing of all numeric formats defined in R5RS --- mode/scheme/scheme.js | 66 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/mode/scheme/scheme.js b/mode/scheme/scheme.js index 8872edafe..f981b235b 100644 --- a/mode/scheme/scheme.js +++ b/mode/scheme/scheme.js @@ -29,6 +29,30 @@ CodeMirror.defineMode("scheme", function (config, mode) { state.indentStack = state.indentStack.prev; } + var binaryMatcher = new RegExp(/^(?:[-+]i|[-+][01]+#*(?:\/[01]+#*)?i|[-+]?[01]+#*(?:\/[01]+#*)?@[-+]?[01]+#*(?:\/[01]+#*)?|[-+]?[01]+#*(?:\/[01]+#*)?[-+](?:[01]+#*(?:\/[01]+#*)?)?i|[-+]?[01]+#*(?:\/[01]+#*)?)(?=[()\s;"]|$)/i); + var octalMatcher = new RegExp(/^(?:[-+]i|[-+][0-7]+#*(?:\/[0-7]+#*)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?@[-+]?[0-7]+#*(?:\/[0-7]+#*)?|[-+]?[0-7]+#*(?:\/[0-7]+#*)?[-+](?:[0-7]+#*(?:\/[0-7]+#*)?)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?)(?=[()\s;"]|$)/i); + var hexMatcher = new RegExp(/^(?:[-+]i|[-+][\da-f]+#*(?:\/[\da-f]+#*)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?@[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?[-+](?:[\da-f]+#*(?:\/[\da-f]+#*)?)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?)(?=[()\s;"]|$)/i); + var decimalMatcher = new RegExp(/^(?:[-+]i|[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)i|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)@[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)?i|(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*))(?=[()\s;"]|$)/i); + + function isBinaryNumber (stream) { + return stream.match(binaryMatcher); + } + + function isOctalNumber (stream) { + return stream.match(octalMatcher); + } + + function isDecimalNumber (stream, backup) { + if (backup === true) { + stream.backUp(1); + } + return stream.match(decimalMatcher); + } + + function isHexNumber (stream) { + return stream.match(hexMatcher); + } + return { startState: function () { return { @@ -97,22 +121,50 @@ CodeMirror.defineMode("scheme", function (config, mode) { } else if (ch == "'") { returnType = ATOM; } else if (ch == '#') { - if (stream.eat("|")) { // Multi-line comment + if (stream.eat("|")) { // Multi-line comment state.mode = "comment"; // toggle to comment mode returnType = COMMENT; - } else if (stream.eat(/[tf]/)) { // #t/#f (atom) + } else if (stream.eat(/[tf]/i)) { // #t/#f (atom) returnType = ATOM; - } else if (stream.eat(';')) { // S-Expr comment + } else if (stream.eat(';')) { // S-Expr comment state.mode = "s-expr-comment"; returnType = COMMENT; + } else { + var numTest = null, hasExactness = false, hasRadix = true; + if (stream.eat(/[ei]/i)) { + hasExactness = true; + } else { + stream.backUp(1); // must be radix specifier + } + if (stream.match(/^#b/i)) { + numTest = isBinaryNumber; + } else if (stream.match(/^#o/i)) { + numTest = isOctalNumber; + } else if (stream.match(/^#x/i)) { + numTest = isHexNumber; + } else if (stream.match(/^#d/i)) { + numTest = isDecimalNumber; + } else if (stream.match(/^[-+0-9.]/, false)) { + hasRadix = false; + numTest = isDecimalNumber; + // re-consume the intial # if all matches failed + } else if (!hasExactness) { + stream.eat('#'); + } + if (numTest != null) { + if (hasRadix && !hasExactness) { + // consume optional exactness after radix + stream.match(/^#[ei]/i); + } + if (numTest(stream)) + returnType = NUMBER; + } } - + } else if (/^[-+0-9.]/.test(ch) && isDecimalNumber(stream, true)) { // match non-prefixed number, must be decimal + returnType = NUMBER; } else if (ch == ";") { // comment stream.skipToEnd(); // rest of the line is a comment returnType = COMMENT; - } else if (/\d/.test(ch) && stream.match(/$|^\d*(?:\/\d+|(?:\.\d+)?(?:[eE][+\-]?\d+)?)\b/) || - ch == "-" && stream.match(/^\d+(?:\/\d+|(?:\.\d+)?(?:[eE][+\-]?\d+)?)\b/)) { - returnType = NUMBER; } else if (ch == "(" || ch == "[") { var keyWord = ''; var indentTemp = stream.column(); /** -- GitLab