Commit 9a49f78f57f84739babaa0e4c8ad12b2863b7d70

Michael Schmidt 2020-04-07T20:32:39

Scheme: Improvements (#2263)

diff --git a/components/prism-scheme.js b/components/prism-scheme.js
index 13a0f6d..ad5d000 100644
--- a/components/prism-scheme.js
+++ b/components/prism-scheme.js
@@ -1,13 +1,22 @@
 Prism.languages.scheme = {
 	'comment': /;.*/,
 	'string': {
-		pattern: /"(?:[^"\\]|\\.)*"|'[^()#'\s]+/,
+		pattern: /"(?:[^"\\]|\\.)*"/,
+		greedy: true
+	},
+	'symbol': {
+		pattern: /'[^()#'\s]+/,
 		greedy: true
 	},
 	'character': {
-		pattern: /#\\(?:[ux][a-fA-F\d]+|[a-zA-Z]+|\S)/,
+		pattern: /#\\(?:[ux][a-fA-F\d]+|[-a-zA-Z]+|\S)/,
+		greedy: true,
 		alias: 'string'
 	},
+	'lambda-parameter': {
+		pattern: /(\(lambda\s+\()[^()'\s]+/,
+		lookbehind: true
+	},
 	'keyword': {
 		pattern: /(\()(?:define(?:-syntax|-library|-values)?|(?:case-)?lambda|let(?:\*|rec)?(?:-values)?|else|if|cond|begin|delay(?:-force)?|parameterize|guard|set!|(?:quasi-)?quote|syntax-rules)(?=[()\s])/,
 		lookbehind: true
@@ -17,7 +26,22 @@ Prism.languages.scheme = {
 		lookbehind: true
 	},
 	'number': {
-		pattern: /([\s()])[-+]?(?:\d+\/\d+|\d*\.?\d+(?:\s*[-+]\s*\d*\.?\d+i)?)\b/,
+		// This pattern (apart from the lookarounds) works like this:
+		//
+		// Decimal numbers
+		// <dec real>       := \d*\.?\d+(?:[eE][+-]?\d+)?|\d+\/\d+
+		// <dec complex>    := <dec real>(?:[+-]<dec real>i)?|<dec real>i
+		// <dec prefix>     := (?:#d(?:#[ei])?|#[ei](?:#d)?)?
+		// <dec number>     := <dec prefix>[+-]?<complex>
+		//
+		// Binary, octal, and hexadecimal numbers
+		// <b.o.x. real>    := [\da-fA-F]+(?:\/[\da-fA-F]+)?
+		// <b.o.x. complex> := <b.o.x. real>(?:[+-]<b.o.x. real>i)?|<b.o.x. real>i
+		// <b.o.x. prefix>  := #[box](?:#[ei])?|#[ei](?:#[box])?
+		// <b.o.x. number>  := <b.o.x. prefix>[+-]?<b.o.x. complex>
+		//
+		// <number>         := <dec number>|<b.o.x. number>
+		pattern: /([\s()])(?:(?:#d(?:#[ei])?|#[ei](?:#d)?)?[+-]?(?:(?:\d*\.?\d+(?:[eE][+-]?\d+)?|\d+\/\d+)(?:[+-](?:\d*\.?\d+(?:[eE][+-]?\d+)?|\d+\/\d+)i)?|(?:\d*\.?\d+(?:[eE][+-]?\d+)?|\d+\/\d+)i)|(?:#[box](?:#[ei])?|#[ei](?:#[box])?)[+-]?(?:[\da-fA-F]+(?:\/[\da-fA-F]+)?(?:[+-][\da-fA-F]+(?:\/[\da-fA-F]+)?i)?|[\da-fA-F]+(?:\/[\da-fA-F]+)?i))(?=[\s()]|$)/,
 		lookbehind: true
 	},
 	'boolean': /#[tf]/,
@@ -26,7 +50,7 @@ Prism.languages.scheme = {
 		lookbehind: true
 	},
 	'function': {
-		pattern: /(\()[^()'\s]+(?=[()\s)]|$)/,
+		pattern: /(\()[^()'\s]+(?=[()\s]|$)/,
 		lookbehind: true
 	},
 	'punctuation': /[()']/
diff --git a/components/prism-scheme.min.js b/components/prism-scheme.min.js
index 04bc6c1..4a2d1fa 100644
--- a/components/prism-scheme.min.js
+++ b/components/prism-scheme.min.js
@@ -1 +1 @@
-Prism.languages.scheme={comment:/;.*/,string:{pattern:/"(?:[^"\\]|\\.)*"|'[^()#'\s]+/,greedy:!0},character:{pattern:/#\\(?:[ux][a-fA-F\d]+|[a-zA-Z]+|\S)/,alias:"string"},keyword:{pattern:/(\()(?:define(?:-syntax|-library|-values)?|(?:case-)?lambda|let(?:\*|rec)?(?:-values)?|else|if|cond|begin|delay(?:-force)?|parameterize|guard|set!|(?:quasi-)?quote|syntax-rules)(?=[()\s])/,lookbehind:!0},builtin:{pattern:/(\()(?:(?:cons|car|cdr|list|call-with-current-continuation|call\/cc|append|abs|apply|eval)\b|null\?|pair\?|boolean\?|eof-object\?|char\?|procedure\?|number\?|port\?|string\?|vector\?|symbol\?|bytevector\?)(?=[()\s])/,lookbehind:!0},number:{pattern:/([\s()])[-+]?(?:\d+\/\d+|\d*\.?\d+(?:\s*[-+]\s*\d*\.?\d+i)?)\b/,lookbehind:!0},boolean:/#[tf]/,operator:{pattern:/(\()(?:[-+*%\/]|[<>]=?|=>?)(?=\s|$)/,lookbehind:!0},function:{pattern:/(\()[^()'\s]+(?=[()\s)]|$)/,lookbehind:!0},punctuation:/[()']/};
\ No newline at end of file
+Prism.languages.scheme={comment:/;.*/,string:{pattern:/"(?:[^"\\]|\\.)*"/,greedy:!0},symbol:{pattern:/'[^()#'\s]+/,greedy:!0},character:{pattern:/#\\(?:[ux][a-fA-F\d]+|[-a-zA-Z]+|\S)/,greedy:!0,alias:"string"},"lambda-parameter":{pattern:/(\(lambda\s+\()[^()'\s]+/,lookbehind:!0},keyword:{pattern:/(\()(?:define(?:-syntax|-library|-values)?|(?:case-)?lambda|let(?:\*|rec)?(?:-values)?|else|if|cond|begin|delay(?:-force)?|parameterize|guard|set!|(?:quasi-)?quote|syntax-rules)(?=[()\s])/,lookbehind:!0},builtin:{pattern:/(\()(?:(?:cons|car|cdr|list|call-with-current-continuation|call\/cc|append|abs|apply|eval)\b|null\?|pair\?|boolean\?|eof-object\?|char\?|procedure\?|number\?|port\?|string\?|vector\?|symbol\?|bytevector\?)(?=[()\s])/,lookbehind:!0},number:{pattern:/([\s()])(?:(?:#d(?:#[ei])?|#[ei](?:#d)?)?[+-]?(?:(?:\d*\.?\d+(?:[eE][+-]?\d+)?|\d+\/\d+)(?:[+-](?:\d*\.?\d+(?:[eE][+-]?\d+)?|\d+\/\d+)i)?|(?:\d*\.?\d+(?:[eE][+-]?\d+)?|\d+\/\d+)i)|(?:#[box](?:#[ei])?|#[ei](?:#[box])?)[+-]?(?:[\da-fA-F]+(?:\/[\da-fA-F]+)?(?:[+-][\da-fA-F]+(?:\/[\da-fA-F]+)?i)?|[\da-fA-F]+(?:\/[\da-fA-F]+)?i))(?=[\s()]|$)/,lookbehind:!0},boolean:/#[tf]/,operator:{pattern:/(\()(?:[-+*%\/]|[<>]=?|=>?)(?=\s|$)/,lookbehind:!0},function:{pattern:/(\()[^()'\s]+(?=[()\s]|$)/,lookbehind:!0},punctuation:/[()']/};
\ No newline at end of file
diff --git a/known-failures.html b/known-failures.html
index b03f034..6083199 100644
--- a/known-failures.html
+++ b/known-failures.html
@@ -287,6 +287,20 @@ not supported */</code></pre>
 </section>
 
 
+<section class="language-scheme">
+
+<h3>The first argument of <code>case-lambda</code> argument lists are highlighted as functions</h3>
+<pre><code>(define plus
+	(case-lambda
+		(() 0)
+		((x) x)
+		((x y) (+ x y))
+		((x y z) (+ (+ x y) z))
+		(args (apply + args))))</code></pre>
+
+</section>
+
+
 <section class="language-swift">
 
 <h3>Nested block comments</h3>
diff --git a/tests/languages/scheme/character_feature.test b/tests/languages/scheme/character_feature.test
index 06185b5..f95cb70 100644
--- a/tests/languages/scheme/character_feature.test
+++ b/tests/languages/scheme/character_feature.test
@@ -1,5 +1,15 @@
-#\a
-#\space
+#\a                     ; lowercase letter
+#\A                     ; uppercase letter
+#\(                     ; left parenthesis
+#\space                 ; the space character
+#\newline               ; the newline character
+
+#\c-a                   ; Control-a
+#\meta-b                ; Meta-b
+#\c-s-m-h-a             ; Control-Meta-Super-Hyper-A
+
+#\; #\' #\"
+
 #\u0041
 #\x10FFFF
 #\λ
@@ -9,7 +19,27 @@
 
 [
 	["character", "#\\a"],
+	["comment", "; lowercase letter"],
+	["character", "#\\A"],
+	["comment", "; uppercase letter"],
+	["character", "#\\("],
+	["comment", "; left parenthesis"],
 	["character", "#\\space"],
+	["comment", "; the space character"],
+	["character", "#\\newline"],
+	["comment", "; the newline character"],
+
+	["character", "#\\c-a"],
+	["comment", "; Control-a"],
+	["character", "#\\meta-b"],
+	["comment", "; Meta-b"],
+	["character", "#\\c-s-m-h-a"],
+	["comment", "; Control-Meta-Super-Hyper-A"],
+
+	["character", "#\\;"],
+	["character", "#\\'"],
+	["character", "#\\\""],
+
 	["character", "#\\u0041"],
 	["character", "#\\x10FFFF"],
 	["character", "#\\λ"],
diff --git a/tests/languages/scheme/lambda_parameter_feature.test b/tests/languages/scheme/lambda_parameter_feature.test
new file mode 100644
index 0000000..afc03ab
--- /dev/null
+++ b/tests/languages/scheme/lambda_parameter_feature.test
@@ -0,0 +1,21 @@
+(lambda (foo bar) (concat foo bar))
+
+----------------------------------------------------
+
+[
+	["punctuation", "("],
+	["keyword", "lambda"],
+	["punctuation", "("],
+	["lambda-parameter", "foo"],
+	" bar",
+	["punctuation", ")"],
+	["punctuation", "("],
+	["function", "concat"],
+	" foo bar",
+	["punctuation", ")"],
+	["punctuation", ")"]
+]
+
+----------------------------------------------------
+
+Checks for lambda parameters.
diff --git a/tests/languages/scheme/number_feature.test b/tests/languages/scheme/number_feature.test
index bdd2af4..15f1ca2 100644
--- a/tests/languages/scheme/number_feature.test
+++ b/tests/languages/scheme/number_feature.test
@@ -1,19 +1,95 @@
-(foo 42)
-(foo 3.14159)
+(foo 42 +42 -42)
+(foo 1e3 +1e3 -1e3)
+(foo 1e+3 1e-3 3.14159 3.14159e-1)
 (foo 8/3)
-(foo 3+4i)
-(foo 2.5+0.0i)
-(foo 3+0i)
+(foo 3+4i 2.5+0.0i 2.5+0.0i -2.5e4+0.0e4i 3+0i -2e-5i)
+(list 10i +10i -10i 10.10i 10+10i 10.10+10.10i 10-10i 10e+10i 10+10e+10i)
+
+(list #d123 #e#d123e-4 #d#i12 #i-1.234i)
+
+(list #xBAD #b1110011 #o777)
+(list #i#x10 #i#x10+10i #b10+10i)
+
+; not a number but a symbol
+(define 1+2 10)
 
 ----------------------------------------------------
 
 [
-	["punctuation", "("], ["function", "foo"], ["number", "42"], ["punctuation", ")"],
-	["punctuation", "("], ["function", "foo"], ["number", "3.14159"], ["punctuation", ")"],
-	["punctuation", "("], ["function", "foo"], ["number", "8/3"], ["punctuation", ")"],
-	["punctuation", "("], ["function", "foo"], ["number", "3+4i"], ["punctuation", ")"],
-	["punctuation", "("], ["function", "foo"], ["number", "2.5+0.0i"], ["punctuation", ")"],
-	["punctuation", "("], ["function", "foo"], ["number", "3+0i"], ["punctuation", ")"]
+	["punctuation", "("],
+	["function", "foo"],
+	["number", "42"],
+	["number", "+42"],
+	["number", "-42"],
+	["punctuation", ")"],
+
+	["punctuation", "("],
+	["function", "foo"],
+	["number", "1e3"],
+	["number", "+1e3"],
+	["number", "-1e3"],
+	["punctuation", ")"],
+
+	["punctuation", "("],
+	["function", "foo"],
+	["number", "1e+3"],
+	["number", "1e-3"],
+	["number", "3.14159"],
+	["number", "3.14159e-1"],
+	["punctuation", ")"],
+
+	["punctuation", "("],
+	["function", "foo"],
+	["number", "8/3"],
+	["punctuation", ")"],
+
+	["punctuation", "("],
+	["function", "foo"],
+	["number", "3+4i"],
+	["number", "2.5+0.0i"],
+	["number", "2.5+0.0i"],
+	["number", "-2.5e4+0.0e4i"],
+	["number", "3+0i"],
+	["number", "-2e-5i"],
+	["punctuation", ")"],
+
+	["punctuation", "("],
+	["builtin", "list"],
+	["number", "10i"],
+	["number", "+10i"],
+	["number", "-10i"],
+	["number", "10.10i"],
+	["number", "10+10i"],
+	["number", "10.10+10.10i"],
+	["number", "10-10i"],
+	["number", "10e+10i"],
+	["number", "10+10e+10i"],
+	["punctuation", ")"],
+
+	["punctuation", "("],
+	["builtin", "list"],
+	["number", "#d123"],
+	["number", "#e#d123e-4"],
+	["number", "#d#i12"],
+	["number", "#i-1.234i"],
+	["punctuation", ")"],
+
+	["punctuation", "("],
+	["builtin", "list"],
+	["number", "#xBAD"],
+	["number", "#b1110011"],
+	["number", "#o777"],
+	["punctuation", ")"],
+
+	["punctuation", "("],
+	["builtin", "list"],
+	["number", "#i#x10"],
+	["number", "#i#x10+10i"],
+	["number", "#b10+10i"],
+	["punctuation", ")"],
+
+	["comment", "; not a number but a symbol"],
+	["punctuation", "("], ["keyword", "define"], " 1+2 ", ["number", "10"], ["punctuation", ")"]
 ]
 
 ----------------------------------------------------
diff --git a/tests/languages/scheme/string_feature.test b/tests/languages/scheme/string_feature.test
index 821f1ff..0361b51 100644
--- a/tests/languages/scheme/string_feature.test
+++ b/tests/languages/scheme/string_feature.test
@@ -4,19 +4,15 @@
 multi
 line
 "
-'turkey
-(define a 'foo)
 
 ----------------------------------------------------
 
 [
 	["string", "\"\""],
 	["string", "\"fo\\\"obar\""],
-	["string", "\"\r\nmulti\r\nline\r\n\""],
-	["string", "'turkey"],
-	["punctuation", "("], ["keyword", "define"], " a ", ["string","'foo"], ["punctuation",")"]
+	["string", "\"\r\nmulti\r\nline\r\n\""]
 ]
 
 ----------------------------------------------------
 
-Checks for strings and symbols.
+Checks for strings.
diff --git a/tests/languages/scheme/symbol_feature.test b/tests/languages/scheme/symbol_feature.test
new file mode 100644
index 0000000..3cdf4cb
--- /dev/null
+++ b/tests/languages/scheme/symbol_feature.test
@@ -0,0 +1,13 @@
+'turkey
+(define a 'foo)
+
+----------------------------------------------------
+
+[
+	["symbol", "'turkey"],
+	["punctuation", "("], ["keyword", "define"], " a ", ["symbol","'foo"], ["punctuation",")"]
+]
+
+----------------------------------------------------
+
+Checks for symbols.