diff --git a/_includes/footer.html b/_includes/footer.html
index b00049db89..82d0ba252d 100644
--- a/_includes/footer.html
+++ b/_includes/footer.html
@@ -53,6 +53,9 @@
+
+
+
diff --git a/_overviews/scala3-book/first-look-at-types.md b/_overviews/scala3-book/first-look-at-types.md
index 4a822d6edf..1a795c8922 100644
--- a/_overviews/scala3-book/first-look-at-types.md
+++ b/_overviews/scala3-book/first-look-at-types.md
@@ -58,6 +58,7 @@ val list: List[Any] = List(
"a string",
732, // an integer
'c', // a character
+ '\'', // a character with a backslash escape
true, // a boolean value
() => "an anonymous function returning a string"
)
@@ -76,6 +77,7 @@ Here’s the output of the program:
a string
732
c
+'
true
```
@@ -119,7 +121,22 @@ In your code you can also append the characters `L`, `D`, and `F` (and their low
```scala
val x = 1_000L // val x: Long = 1000
val y = 2.2D // val y: Double = 2.2
-val z = 3.3F // val z: Float = 3.3
+val z = -3.3F // val z: Float = -3.3
+```
+
+You may also use hexadecimal notation to format integer numbers (normally `Int`, but which also support the
+`L` suffix to specify that they are `Long`):
+
+```scala
+val a = 0xACE // val a: Int = 2766
+val b = 0xfd_3aL // val b: Long = 64826
+```
+
+Scala supports many different ways to format the same floating point number, e.g.
+```scala
+val q = .25 // val q: Double = 0.25
+val r = 2.5e-1 // val r: Double = 0.25
+val s = .0025e2F // val s: Float = 0.25
```
{% endtab %}
{% endtabs %}
diff --git a/resources/js/functions.js b/resources/js/functions.js
index 8dd9e9ec76..b0b0dd6d68 100644
--- a/resources/js/functions.js
+++ b/resources/js/functions.js
@@ -67,6 +67,7 @@ $(document).ready(function() {
hljs.configure({
languages: ["scala", "bash"]
})
+ hljs.registerLanguage("scala", highlightDotty);
hljs.highlightAll();
});
@@ -431,7 +432,7 @@ $(document).ready(function() {
function setupTabs(tabs, namespace, defaultValue) {
const PreferenceStorage = Storage('org.scala-lang.docs.preferences');
const preferredValue = PreferenceStorage.getPreference(namespace, defaultValue);
-
+
activateTab(tabs, preferredValue)
// setup listeners to record new preferred Scala version.
diff --git a/resources/js/hljs-scala3.js b/resources/js/hljs-scala3.js
new file mode 100644
index 0000000000..0ba80087ef
--- /dev/null
+++ b/resources/js/hljs-scala3.js
@@ -0,0 +1,476 @@
+function highlightDotty(hljs) {
+
+ // identifiers
+ const capitalizedId = /\b[A-Z][$\w]*\b/
+ const alphaId = /[a-zA-Z$_][$\w]*/
+ const op1 = /[^\s\w\d,;"'()[\]{}=:]/
+ const op2 = /[^\s\w\d,;"'()[\]{}]/
+ const compound = `[a-zA-Z$][a-zA-Z0-9$]*_${op2.source}` // e.g. value_=
+ const id = new RegExp(`(${compound}|${alphaId.source}|${op2.source}{2,}|${op1.source}+|\`.+?\`)`)
+
+ // numbers
+ const hexDigit = '[a-fA-F0-9]'
+ const hexNumber = `0[xX](${hexDigit})+(_(${hexDigit})+)*[lL]?`
+ const wholePart = `(\\d+)(_\\d+)*`
+ const decPoint = `\\.\\d+`
+ const floatingSuffix = `([eE][-+]?\\d+)?[fFdD]?`
+ const intOrFloat = `${decPoint}${floatingSuffix}|\\b${wholePart}([lLfFdD]|(${decPoint})?${floatingSuffix})`
+ const number = new RegExp(`(-?)((\\b(${hexNumber})|${intOrFloat}))`)
+
+ // Regular Keywords
+ // The "soft" keywords (e.g. 'using') are added later where necessary
+ const alwaysKeywords = {
+ $pattern: /(\w+|\?=>|\?{1,3}|=>>|=>|<:|>:|_|#|<-|\.nn)/,
+ keyword:
+ 'abstract case catch class def do else enum export extends final finally for given ' +
+ 'if implicit import lazy match new object package private protected override return ' +
+ 'sealed then throw trait true try type val var while with yield =>> => ?=> <: >: _ ? <- #',
+ literal: 'true false null this super',
+ built_in: '??? asInstanceOf isInstanceOf assert implicitly locally summon valueOf .nn'
+ }
+ const modifiers = 'abstract|final|implicit|override|private|protected|sealed'
+
+ // End of class, enum, etc. header
+ const templateDeclEnd = /(\/[/*]|{|:(?= *\n)|\n(?! *(extends|with|derives)))/
+
+ // all the keywords + soft keywords, separated by spaces
+ function withSoftKeywords(kwd) {
+ return {
+ $pattern: alwaysKeywords.$pattern,
+ keyword: kwd + ' ' + alwaysKeywords.keyword,
+ literal: alwaysKeywords.literal,
+ built_in: alwaysKeywords.built_in
+ }
+ }
+
+ // title inside of a complex token made of several parts, but colored as a type (e.g. class)
+ const TP_TITLE = {
+ className: 'type',
+ begin: id,
+ returnEnd: true,
+ keywords: alwaysKeywords.keyword,
+ literal: alwaysKeywords.literal,
+ built_in: alwaysKeywords.built_in
+ }
+
+ // title inside of a complex token made of several parts (e.g. class)
+ const TITLE = {
+ className: 'title',
+ begin: id,
+ returnEnd: true,
+ keywords: alwaysKeywords.keyword,
+ literal: alwaysKeywords.literal,
+ built_in: alwaysKeywords.built_in
+ }
+
+ // title that goes to the end of a simple token (e.g. val)
+ const TITLE2 = {
+ className: 'title',
+ begin: id,
+ excludeEnd: true,
+ endsWithParent: true
+ }
+
+ const TYPED = {
+ begin: /: (?=[a-zA-Z()?])/,
+ end: /\/\/|\/\*|\n/,
+ endsWithParent: true,
+ returnEnd: true,
+ contains: [
+ {
+ // works better than the usual way of defining keyword,
+ // in this specific situation
+ className: 'keyword',
+ begin: /\?\=>|=>>|[=:][><]|\?/,
+ },
+ {
+ className: 'type',
+ begin: alphaId
+ }
+ ]
+ }
+
+ const PROBABLY_TYPE = {
+ className: 'type',
+ begin: capitalizedId,
+ relevance: 0
+ }
+
+ const NUMBER = {
+ className: 'number',
+ begin: number,
+ relevance: 0,
+ }
+
+ const CHAR = {
+ className: 'string',
+ begin: /\'([^'\\]|\\[\s\S])\'/,
+ relevance: 0,
+ }
+
+ // type parameters within [square brackets]
+ const TPARAMS = {
+ begin: /\[/, end: /\]/,
+ keywords: {
+ $pattern: /<:|>:|[+-?_:]/,
+ keyword: '<: >: : + - ? _'
+ },
+ contains: [
+ hljs.C_BLOCK_COMMENT_MODE,
+ {
+ className: 'type',
+ begin: alphaId
+ },
+ ],
+ relevance: 3
+ }
+
+ // Class or method parameters declaration
+ const PARAMS = {
+ className: 'params',
+ begin: /\(/, end: /\)/,
+ excludeBegin: true,
+ excludeEnd: true,
+ keywords: withSoftKeywords('inline using'),
+ contains: [
+ hljs.C_BLOCK_COMMENT_MODE,
+ hljs.QUOTE_STRING_MODE,
+ PROBABLY_TYPE
+ ]
+ }
+
+ // (using T1, T2, T3)
+ const CTX_PARAMS = {
+ className: 'params',
+ begin: /\(using (?!\w+:)/, end: /\)/,
+ excludeBegin: false,
+ excludeEnd: true,
+ relevance: 5,
+ keywords: withSoftKeywords('using'),
+ contains: [
+ PROBABLY_TYPE
+ ]
+ }
+
+ // String interpolation
+ const SUBST = {
+ className: 'subst',
+ variants: [
+ { begin: /\$[a-zA-Z_]\w*/ },
+ {
+ begin: /\${/, end: /}/,
+ contains: [
+ NUMBER,
+ hljs.QUOTE_STRING_MODE
+ ]
+ }
+ ]
+ }
+
+ // "string" or """string""", with or without interpolation
+ const STRING = {
+ className: 'string',
+ variants: [
+ hljs.QUOTE_STRING_MODE,
+ {
+ begin: '"""', end: '"""',
+ contains: [hljs.BACKSLASH_ESCAPE],
+ relevance: 10
+ },
+ {
+ begin: alphaId.source + '"', end: '"',
+ contains: [hljs.BACKSLASH_ESCAPE, SUBST],
+ illegal: /\n/,
+ relevance: 5
+ },
+ {
+ begin: alphaId.source + '"""', end: '"""',
+ contains: [hljs.BACKSLASH_ESCAPE, SUBST],
+ relevance: 10
+ }
+ ]
+ }
+
+ // Class or method apply
+ const APPLY = {
+ begin: /\(/, end: /\)/,
+ excludeBegin: true, excludeEnd: true,
+ keywords: {
+ $pattern: alwaysKeywords.$pattern,
+ keyword: 'using ' + alwaysKeywords.keyword,
+ literal: alwaysKeywords.literal,
+ built_in: alwaysKeywords.built_in
+ },
+ contains: [
+ STRING,
+ NUMBER,
+ CHAR,
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ PROBABLY_TYPE,
+ ]
+ }
+
+ // @annot(...) or @my.package.annot(...)
+ const ANNOTATION = {
+ className: 'meta',
+ begin: `@${id.source}(\\.${id.source})*`,
+ contains: [
+ APPLY,
+ hljs.C_BLOCK_COMMENT_MODE
+ ]
+ }
+
+ // Documentation
+ const SCALADOC = hljs.COMMENT('/\\*\\*', '\\*/', {
+ contains: [
+ {
+ className: 'doctag',
+ begin: /@[a-zA-Z]+/
+ },
+ // markdown syntax elements:
+ {
+ className: 'code',
+ variants: [
+ { begin: /```.*\n/, end: /```/ },
+ { begin: /`/, end: /`/ }
+ ],
+ },
+ {
+ className: 'bold',
+ variants: [
+ { begin: /\*\*/, end: /\*\*/ },
+ { begin: /__/, end: /__/ }
+ ],
+ },
+ {
+ className: 'emphasis',
+ variants: [
+ { begin: /\*(?!([\*\s/])|([^\*]*\*[\*/]))/, end: /\*/ },
+ { begin: /_/, end: /_/ }
+ ],
+ },
+ {
+ className: 'bullet', // list item
+ begin: /- (?=\S)/, end: /\s/,
+ },
+ {
+ begin: /\[.*?\]\(/, end: /\)/,
+ contains: [
+ {
+ // mark as "link" only the URL
+ className: 'link',
+ begin: /.*?/,
+ endsWithParent: true
+ }
+ ]
+ }
+ ]
+ })
+
+ // Methods
+ const METHOD = {
+ className: 'function',
+ begin: `((${modifiers}|transparent|inline|infix) +)*def `, end: / =\s|\n/,
+ excludeEnd: true,
+ relevance: 5,
+ keywords: withSoftKeywords('inline infix transparent'),
+ contains: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ TPARAMS,
+ CTX_PARAMS,
+ PARAMS,
+ TYPED, // prevents the ":" (declared type) to become a title
+ PROBABLY_TYPE,
+ TITLE
+ ]
+ }
+
+ // Variables & Constants
+ const VAL = {
+ beginKeywords: 'val var', end: /[=:;\n/]/,
+ excludeEnd: true,
+ contains: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ TITLE2
+ ]
+ }
+
+ // Type declarations
+ const TYPEDEF = {
+ className: 'typedef',
+ begin: `((${modifiers}|opaque) +)*type `, end: /[=;\n]| ?[<>]:/,
+ excludeEnd: true,
+ keywords: withSoftKeywords('opaque'),
+ contains: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ PROBABLY_TYPE,
+ TITLE,
+ ]
+ }
+
+ // Given instances
+ const GIVEN = {
+ begin: `((${modifiers}|transparent|inline) +)*given `, end: / =|[=;\n]/,
+ excludeEnd: true,
+ keywords: withSoftKeywords('inline transparent given using with'),
+ contains: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ PARAMS,
+ CTX_PARAMS,
+ PROBABLY_TYPE,
+ TITLE
+ ]
+ }
+
+ // Extension methods
+ const EXTENSION = {
+ begin: /extension/, end: /(\n|def)/,
+ returnEnd: true,
+ keywords: 'extension implicit using',
+ contains: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ CTX_PARAMS,
+ PARAMS,
+ PROBABLY_TYPE
+ ]
+ }
+
+ // 'end' soft keyword
+ const END = {
+ begin: `end(?= (if|while|for|match|try|given|extension|this|val|${id.source})\\n)`, end: /\s/,
+ keywords: 'end'
+ }
+
+ // Classes, traits, enums, etc.
+ const EXTENDS_PARENT = {
+ begin: ' extends ', end: /( with | derives |\/[/*])/,
+ endsWithParent: true,
+ returnEnd: true,
+ keywords: 'extends',
+ contains: [APPLY, PROBABLY_TYPE]
+ }
+ const WITH_MIXIN = {
+ begin: ' with ', end: / derives |\/[/*]/,
+ endsWithParent: true,
+ returnEnd: true,
+ keywords: 'with',
+ contains: [APPLY, PROBABLY_TYPE],
+ relevance: 10
+ }
+ const DERIVES_TYPECLASS = {
+ begin: ' derives ', end: /\n|\/[/*]/,
+ endsWithParent: true,
+ returnEnd: true,
+ keywords: 'derives',
+ contains: [PROBABLY_TYPE],
+ relevance: 10
+ }
+
+ const CLASS = {
+ className: 'class',
+ begin: `((${modifiers}|open|case|transparent) +)*(class|trait|enum|object|package object)`, end: templateDeclEnd,
+ keywords: withSoftKeywords('open transparent'),
+ excludeEnd: true,
+ contains: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ TPARAMS,
+ CTX_PARAMS,
+ PARAMS,
+ EXTENDS_PARENT,
+ WITH_MIXIN,
+ DERIVES_TYPECLASS,
+ TITLE,
+ PROBABLY_TYPE
+ ]
+ }
+
+ // package declaration with a content
+ const PACKAGE = {
+ className: 'package',
+ begin: /package (?=\w+ *[:{\n])/, end: /[:{\n]/,
+ excludeEnd: true,
+ keywords: alwaysKeywords,
+ contains: [
+ TITLE
+ ]
+ }
+
+ // Case in enum
+ const ENUM_CASE = {
+ begin: /case (?!.*=>)/, end: /\n/,
+ keywords: 'case',
+ excludeEnd: true,
+ contains: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ PARAMS,
+ EXTENDS_PARENT,
+ WITH_MIXIN,
+ DERIVES_TYPECLASS,
+ TP_TITLE,
+ PROBABLY_TYPE
+ ]
+ }
+
+ // Case in pattern matching
+ const MATCH_CASE = {
+ begin: /case/, end: /=>|\n/,
+ keywords: 'case',
+ excludeEnd: true,
+ contains: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ {
+ begin: /[@_]/,
+ keywords: {
+ $pattern: /[@_]/,
+ keyword: '@ _'
+ }
+ },
+ NUMBER,
+ STRING,
+ PROBABLY_TYPE
+ ]
+ }
+
+ // inline someVar[andMaybeTypeParams] match
+ const INLINE_MATCH = {
+ begin: /inline [^\n:]+ match/,
+ keywords: 'inline match'
+ }
+
+ return {
+ name: 'Scala3',
+ aliases: ['scala', 'dotty'],
+ keywords: alwaysKeywords,
+ contains: [
+ NUMBER,
+ CHAR,
+ STRING,
+ SCALADOC,
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ METHOD,
+ VAL,
+ TYPEDEF,
+ PACKAGE,
+ CLASS,
+ GIVEN,
+ EXTENSION,
+ ANNOTATION,
+ ENUM_CASE,
+ MATCH_CASE,
+ INLINE_MATCH,
+ END,
+ APPLY,
+ PROBABLY_TYPE
+ ]
+ }
+}