From b2a10419ce0b902c51545678bc34860edd29c972 Mon Sep 17 00:00:00 2001 From: "alan.invents" Date: Wed, 1 Jul 2020 18:52:31 -0400 Subject: [PATCH] Finish implementing Scala --- src/scala/scala.contribution.ts | 15 +++ src/scala/scala.test.ts | 38 +++++++ src/scala/scala.ts | 176 ++++++++++++++++++++++++-------- 3 files changed, 187 insertions(+), 42 deletions(-) create mode 100644 src/scala/scala.contribution.ts create mode 100644 src/scala/scala.test.ts diff --git a/src/scala/scala.contribution.ts b/src/scala/scala.contribution.ts new file mode 100644 index 00000000..84bd2178 --- /dev/null +++ b/src/scala/scala.contribution.ts @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { registerLanguage } from '../_.contribution'; + +registerLanguage({ + id: 'scala', + extensions: ['.scala', '.sbt', '.sc'], + aliases: ['Scala', 'scala', 'SBT', 'Sbt', 'sbt', 'Dotty', 'dotty'], + mimetypes: ['text/x-scala', 'text/x-sbt', 'text/x-dotty'], + loader: () => import('./scala') +}); diff --git a/src/scala/scala.test.ts b/src/scala/scala.test.ts new file mode 100644 index 00000000..2f93a17d --- /dev/null +++ b/src/scala/scala.test.ts @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import { testTokenization } from '../test/testRunner'; + +testTokenization('scala', [ + [{ + line: '//', + tokens: [ + {startIndex: 0, type: 'comment.scala'} + ] + }], + + [{ + line: ' // a comment', + tokens: [ + {startIndex: 0, type: 'white.scala'}, + {startIndex: 4, type: 'comment.scala'} + ] + }], + + [{ + line: 'var a = 1', + tokens: [ + {startIndex: 0, type: 'keyword.scala'}, + {startIndex: 3, type: 'white.scala'}, + {startIndex: 4, type: 'variable.scala'}, + {startIndex: 5, type: 'white.scala'}, + {startIndex: 6, type: 'operator.scala'}, + {startIndex: 7, type: 'white.scala'}, + {startIndex: 8, type: 'number.scala'} + ] + }] +]); diff --git a/src/scala/scala.ts b/src/scala/scala.ts index dfb52e5d..03b87972 100644 --- a/src/scala/scala.ts +++ b/src/scala/scala.ts @@ -9,8 +9,48 @@ import IRichLanguageConfiguration = monaco.languages.LanguageConfiguration; import ILanguage = monaco.languages.IMonarchLanguage; export const conf: IRichLanguageConfiguration = { + /* + * `...` is allowed as an identifier. + * $ is allowed in identifiers. + * unary_ is allowed as an identifier. + * _= is allowed as an identifier. + */ + wordPattern: /(unary_[@~!#%^&*()\-=+\\|:<>\/?]+)|([a-zA-Z_$][\w$]*?_=)|(`[^`]+`)|([a-zA-Z_$][\w$]*)/g, + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'], + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: '\'', close: '\'' }, + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: '\'', close: '\'' }, + ], + folding: { + markers: { + start: new RegExp("^\\s*//\\s*(?:(?:#?region\\b)|(?:))") + } + } +}; + +export const language = { tokenPostfix: '.scala', + // We can't easily add everything from Dotty, but we can at least add some of its keywords keywords: [ 'asInstanceOf', 'catch', 'class', 'classOf', @@ -18,7 +58,7 @@ export const conf: IRichLanguageConfiguration = { 'else', 'extends', 'finally', 'for', 'foreach', 'forSome', 'if', 'import', 'isInstanceOf', - 'match', + 'macro', 'match', 'new', 'object', 'package', @@ -27,7 +67,16 @@ export const conf: IRichLanguageConfiguration = { 'until', 'val', 'var', 'while', 'with', - 'yield' + 'yield', + + // Dotty-specific: + 'given', 'enum', 'then' + ], + + // Dotty-specific: + softKeywords: [ + 'as', 'export', 'extension', 'end', + 'derives', 'on' ], constants: [ @@ -40,10 +89,16 @@ export const conf: IRichLanguageConfiguration = { 'private', 'protected', 'sealed' ], - name: /[a-z_$][\w$]*/, + // Dotty-specific: + softModifiers: [ + 'inline', 'opaque', 'open', 'transparent', 'using' + ], + + name: /(?:[a-z_$][\w$]*|`[^`]+`)/, + type: /(?:[A-Z][\w$]*)/, // we include these common regular expressions - symbols: /[=>))/, ['@brackets', 'white', 'variable']], + [/\b(def[ \t]+)((?:unary_)?@symbols|@name(?:_=)|@name)/, ['keyword', 'keyword.flow']], + [/@name(?=[ \t]*:(?!:))/, 'variable'], + [/(\.)(@name|@symbols)/, ['operator', {token: 'keyword.flow', next: '@allowMethod'}]], + [/([{(])(\s*)(@name(?=\s*=>))/, ['@brackets', 'white', 'variable']], [/@name/, {cases: { '@keywords': 'keyword', + '@softKeywords': 'keyword', '@modifiers': 'tag.id.pug', - '@constants': 'constant', - '@default': 'identifier' + '@softModifiers': 'tag.id.pug', + '@constants': {token: 'constant', next: '@allowMethod'}, + '@default': {token: 'identifier', next: '@allowMethod'} }}], - [/[A-Z]\w*/, 'type.identifier'], + [/@type/, 'type', '@allowMethod'], // whitespace {include: '@whitespace'}, - + // @ annotations. [/@[a-zA-Z_$][\w$]*(?:\.[a-zA-Z_$][\w$]*)*/, 'annotation'], // delimiters and operators - [/[{}()]/, '@brackets'], - [/[\[\]]/, 'operator.scss'], - [/[=-]>|<-|>:|<:|<%/, 'keyword'], + [/[{(]/, '@brackets'], + [/[})]/, '@brackets', '@allowMethod'], + [/\[/, 'operator.scss'], + [/](?!\s*(?:va[rl]|def|type)\b)/, 'operator.scss', '@allowMethod'], + [/]/, 'operator.scss'], + [/([=-]>|<-|>:|<:|:>|<%)(?=[\s\w()[\]{},\."'`])/, 'keyword'], [/@symbols/, 'operator'], // delimiter: after number because of .\d floats - [/[;,.]/, 'delimiter'], + [/[;,\.]/, 'delimiter'], + + // symbols + [/'[a-zA-Z$][\w$]*(?!')/, 'attribute.name'], // characters - [/'[^\\']'/, 'string'], - [/(')(@escapes)(')/, ['string', 'string.escape', 'string']], + [/'[^\\']'/, 'string', '@allowMethod'], + [/(')(@escapes)(')/, ['string', 'string.escape', {token: 'string', next: '@allowMethod'}]], [/'/, 'string.invalid'] ], + import: [ + [/;/, 'delimiter', '@pop'], + [/^|$/, '', '@pop'], + [/[ \t]+/, 'white'], + [/[\n\r]+/, 'white', '@pop'], + [/\/\*/, 'comment', '@comment'], + [/@name|@type/, 'type'], + [/[(){}]/, '@brackets'], + [/[[\]]/, 'operator.scss'], + [/[\.,]/, 'delimiter'], + ], + + allowMethod: [ + [/^|$/, '', '@pop'], + [/[ \t]+/, 'white'], + [/[\n\r]+/, 'white', '@pop'], + [/\/\*/, 'comment', '@comment'], + [/(?==>[\s\w([{])/, 'keyword', '@pop'], + [/(@name|@symbols)(?=[ \t]*[[({"'`]|[ \t]+(?:[+-]?\.?\d|\w))/, { + cases: { + '@keywords': {token: 'keyword', next: '@pop'}, + '->|<-|>:|<:|<%': {token: 'keyword', next: '@pop'}, + '@default': {token: 'keyword.flow', next: '@pop'} + } + }], + ["", "", "@pop"] + ], + comment: [ [/[^\/*]+/, 'comment'], [/\/\*/, 'comment', '@push'], // nested comment - ["\\*/", 'comment', '@pop'], + [/\*\//, 'comment', '@pop'], [/[\/*]/, 'comment'] ], case: [ [/\b_\*/, 'key'], - [/\b(_|true|false|null|this|super)\b/, 'keyword'], + [/\b(_|true|false|null|this|super)\b/, 'keyword', '@allowMethod'], [/\bif\b|=>/, 'keyword', '@pop'], - [/`@name`/, 'identifier'], - [/@name/, 'variable'], + [/`[^`]+`/, 'identifier', '@allowMethod'], + [/@name/, 'variable', '@allowMethod'], [/:::?|\||@(?![a-z_$])/, 'keyword'], {include: '@root'} ], @@ -137,7 +225,7 @@ export const conf: IRichLanguageConfiguration = { [/\b(_|true|false|null|this|super)\b/, 'keyword'], [/@name/, 'variable'], [/:::?|\||@(?![a-z_$])/, 'keyword'], - [/[=:]/, 'operator', '@pop'], + [/=|:(?!:)/, 'operator', '@pop'], [/$/, 'white', '@pop'], {include: '@root'} ], @@ -146,20 +234,21 @@ export const conf: IRichLanguageConfiguration = { [/[^\\"\n\r]+/, 'string'], [/@escapes/, 'string.escape'], [/\\./, 'string.escape.invalid'], - [/"/, {token: 'string.quote', bracket: '@close', next: '@pop'}], + [/"/, {token: 'string.quote', bracket: '@close', switchTo: '@allowMethod'}], ], stringt: [ [/[^\\"\n\r]+/, 'string'], [/@escapes/, 'string.escape'], [/\\./, 'string.escape.invalid'], - [/"""/, {token: 'string.quote', bracket: '@close', next: '@pop'}], + [/"(?=""")/, 'string'], + [/"""/, {token: 'string.quote', bracket: '@close', switchTo: '@allowMethod'}], [/"/, 'string'] ], fstring: [ [/@escapes/, 'string.escape'], - [/"/, {token: 'string.quote', bracket: '@close', next: '@pop'}], + [/"/, {token: 'string.quote', bracket: '@close', switchTo: '@allowMethod'}], [/\$\$/, 'string'], [/(\$)([a-z_]\w*)/, ['operator', 'identifier']], [/\$\{/, 'operator', '@interp'], @@ -173,7 +262,8 @@ export const conf: IRichLanguageConfiguration = { fstringt: [ [/@escapes/, 'string.escape'], - [/"""/, {token: 'string.quote', bracket: '@close', next: '@pop'}], + [/"(?=""")/, 'string'], + [/"""/, {token: 'string.quote', bracket: '@close', switchTo: '@allowMethod'}], [/\$\$/, 'string'], [/(\$)([a-z_]\w*)/, ['operator', 'identifier']], [/\$\{/, 'operator', '@interp'], @@ -187,7 +277,7 @@ export const conf: IRichLanguageConfiguration = { sstring: [ [/@escapes/, 'string.escape'], - [/"/, {token: 'string.quote', bracket: '@close', next: '@pop'}], + [/"/, {token: 'string.quote', bracket: '@close', switchTo: '@allowMethod'}], [/\$\$/, 'string'], [/(\$)([a-z_]\w*)/, ['operator', 'identifier']], [/\$\{/, 'operator', '@interp'], @@ -196,7 +286,8 @@ export const conf: IRichLanguageConfiguration = { sstringt: [ [/@escapes/, 'string.escape'], - [/"""/, {token: 'string.quote', bracket: '@close', next: '@pop'}], + [/"(?=""")/, 'string'], + [/"""/, {token: 'string.quote', bracket: '@close', switchTo: '@allowMethod'}], [/\$\$/, 'string'], [/(\$)([a-z_]\w*)/, ['operator', 'identifier']], [/\$\{/, 'operator', '@interp'], @@ -204,19 +295,20 @@ export const conf: IRichLanguageConfiguration = { ], interp: [ - [/\{/, 'operator', '@push'], - [/\}/, 'operator', '@pop'], + [/{/, 'operator', '@push'], + [/}/, 'operator', '@pop'], {include: '@root'} ], rawstring: [ [/[^"]/, 'string'], - [/"/, {token: 'string.quote', bracket: '@close', next: '@pop'}] + [/"/, {token: 'string.quote', bracket: '@close', switchTo: '@allowMethod'}] ], rawstringt: [ [/[^"]/, 'string'], - [/"""/, {token: 'string.quote', bracket: '@close', next: '@pop'}], + [/"(?=""")/, 'string'], + [/"""/, {token: 'string.quote', bracket: '@close', switchTo: '@allowMethod'}], [/"/, 'string'] ],