From c2c198e0f2f6e780afb218f151aaa23fde6f42a3 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Tue, 11 Jul 2023 16:46:12 +0200 Subject: [PATCH 01/10] test: ignore `out` folder --- DSL/vitest.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/DSL/vitest.config.ts b/DSL/vitest.config.ts index 8a51f9224..b1e860984 100644 --- a/DSL/vitest.config.ts +++ b/DSL/vitest.config.ts @@ -10,5 +10,6 @@ export default defineConfig({ include: ['src'], exclude: ['**/generated'], }, + exclude: ['out'] }, }); From 8009ed75ac306621032cc48d7b5dfab3018f6ca3 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Tue, 11 Jul 2023 16:46:45 +0200 Subject: [PATCH 02/10] chore: remove generated Textmate grammar --- DSL/syntaxes/safe-ds.tmLanguage.json | 78 ---------------------------- 1 file changed, 78 deletions(-) delete mode 100644 DSL/syntaxes/safe-ds.tmLanguage.json diff --git a/DSL/syntaxes/safe-ds.tmLanguage.json b/DSL/syntaxes/safe-ds.tmLanguage.json deleted file mode 100644 index 44789e2b4..000000000 --- a/DSL/syntaxes/safe-ds.tmLanguage.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "name": "safe-ds", - "scopeName": "source.safe-ds", - "fileTypes": [ - ".sdspipe", - ".sdsstub", - ".sdstest" - ], - "patterns": [ - { - "include": "#comments" - }, - { - "name": "keyword.control.safe-ds", - "match": "\\b(and|annotation|as|attr|class|enum|false|fun|import|in|internal|not|null|or|out|package|pipeline|private|schema|segment|static|sub|super|true|union|val|vararg|where|yield)\\b" - }, - { - "name": "string.quoted.double.safe-ds", - "begin": "\"", - "end": "\"", - "patterns": [ - { - "include": "#string-character-escape" - } - ] - } - ], - "repository": { - "comments": { - "patterns": [ - { - "name": "comment.block.safe-ds", - "begin": "/\\*", - "beginCaptures": { - "0": { - "name": "punctuation.definition.comment.safe-ds" - } - }, - "end": "\\*/", - "endCaptures": { - "0": { - "name": "punctuation.definition.comment.safe-ds" - } - } - }, - { - "begin": "//", - "beginCaptures": { - "1": { - "name": "punctuation.whitespace.comment.leading.safe-ds" - } - }, - "end": "(?=$)", - "name": "comment.line.safe-ds" - }, - { - "name": "comment.block.safe-ds", - "begin": "[»«]", - "beginCaptures": { - "0": { - "name": "punctuation.definition.comment.safe-ds" - } - }, - "end": "[»«]", - "endCaptures": { - "0": { - "name": "punctuation.definition.comment.safe-ds" - } - } - } - ] - }, - "string-character-escape": { - "name": "constant.character.escape.safe-ds", - "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" - } - } -} From 84a692fb159618e1371b2663c57aff1aecebe1a6 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Tue, 11 Jul 2023 16:47:35 +0200 Subject: [PATCH 03/10] chore: ignore generated Textmate grammar --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 3d5006540..a6fd283c9 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ coverage/ dist/ dist-ssr/ out/ +DSL/syntaxes/safe-ds.tmLanguage.json # Node .npm/ From 93b73f1b2ea7aa056de949e900bb9fe627c7b35b Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Tue, 11 Jul 2023 16:47:54 +0200 Subject: [PATCH 04/10] test: failing grammar tests for literals --- .../good-literal list of literal type.sdstest | 5 +++++ .../resources/grammar/types/literal types/bad-nested.sdstest | 5 +++++ .../types/literal types/bad-unclosed angle bracket.sdstest | 5 +++++ .../resources/grammar/types/literal types/good-empty.sdstest | 5 +++++ .../grammar/types/literal types/good-with literals.sdstest | 5 +++++ 5 files changed, 25 insertions(+) create mode 100644 DSL/tests/resources/grammar/trailing commas/good-literal list of literal type.sdstest create mode 100644 DSL/tests/resources/grammar/types/literal types/bad-nested.sdstest create mode 100644 DSL/tests/resources/grammar/types/literal types/bad-unclosed angle bracket.sdstest create mode 100644 DSL/tests/resources/grammar/types/literal types/good-empty.sdstest create mode 100644 DSL/tests/resources/grammar/types/literal types/good-with literals.sdstest diff --git a/DSL/tests/resources/grammar/trailing commas/good-literal list of literal type.sdstest b/DSL/tests/resources/grammar/trailing commas/good-literal list of literal type.sdstest new file mode 100644 index 000000000..0253c0984 --- /dev/null +++ b/DSL/tests/resources/grammar/trailing commas/good-literal list of literal type.sdstest @@ -0,0 +1,5 @@ +// $TEST$ no_syntax_error + +segment s( + f: literal +) {} diff --git a/DSL/tests/resources/grammar/types/literal types/bad-nested.sdstest b/DSL/tests/resources/grammar/types/literal types/bad-nested.sdstest new file mode 100644 index 000000000..ce0e69ae0 --- /dev/null +++ b/DSL/tests/resources/grammar/types/literal types/bad-nested.sdstest @@ -0,0 +1,5 @@ +// $TEST$ syntax_error + +segment mySegment( + x: literal> +) {} diff --git a/DSL/tests/resources/grammar/types/literal types/bad-unclosed angle bracket.sdstest b/DSL/tests/resources/grammar/types/literal types/bad-unclosed angle bracket.sdstest new file mode 100644 index 000000000..abf93699d --- /dev/null +++ b/DSL/tests/resources/grammar/types/literal types/bad-unclosed angle bracket.sdstest @@ -0,0 +1,5 @@ +// $TEST$ syntax_error + +segment mySegment( + x: literal< +) {} diff --git a/DSL/tests/resources/grammar/types/literal types/good-empty.sdstest b/DSL/tests/resources/grammar/types/literal types/good-empty.sdstest new file mode 100644 index 000000000..66a936d1b --- /dev/null +++ b/DSL/tests/resources/grammar/types/literal types/good-empty.sdstest @@ -0,0 +1,5 @@ +// $TEST$ no_syntax_error + +segment mySegment( + x: literal<> +) {} diff --git a/DSL/tests/resources/grammar/types/literal types/good-with literals.sdstest b/DSL/tests/resources/grammar/types/literal types/good-with literals.sdstest new file mode 100644 index 000000000..3fbda1b55 --- /dev/null +++ b/DSL/tests/resources/grammar/types/literal types/good-with literals.sdstest @@ -0,0 +1,5 @@ +// $TEST$ no_syntax_error + +segment mySegment( + x: literal +) {} From 249d714c34cfa87e420dee6a7b931eff0b87304f Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Tue, 11 Jul 2023 16:49:51 +0200 Subject: [PATCH 05/10] test: failing tests for formatter --- .../trailing commas/literal list of literal type.sdstest | 9 +++++++++ .../formatting/types/literal types/empty.sdstest | 5 +++++ .../formatting/types/literal types/with literals.sdstest | 9 +++++++++ 3 files changed, 23 insertions(+) create mode 100644 DSL/tests/resources/formatting/trailing commas/literal list of literal type.sdstest create mode 100644 DSL/tests/resources/formatting/types/literal types/empty.sdstest create mode 100644 DSL/tests/resources/formatting/types/literal types/with literals.sdstest diff --git a/DSL/tests/resources/formatting/trailing commas/literal list of literal type.sdstest b/DSL/tests/resources/formatting/trailing commas/literal list of literal type.sdstest new file mode 100644 index 000000000..ccdfc1aae --- /dev/null +++ b/DSL/tests/resources/formatting/trailing commas/literal list of literal type.sdstest @@ -0,0 +1,9 @@ +segment s( + f: literal<1.0 , null , > +) {} + +// ----------------------------------------------------------------------------- + +segment s( + f: literal<1.0, null,> +) {} diff --git a/DSL/tests/resources/formatting/types/literal types/empty.sdstest b/DSL/tests/resources/formatting/types/literal types/empty.sdstest new file mode 100644 index 000000000..0451a59e3 --- /dev/null +++ b/DSL/tests/resources/formatting/types/literal types/empty.sdstest @@ -0,0 +1,5 @@ +segment mySegment(x: literal < >) {} + +// ----------------------------------------------------------------------------- + +segment mySegment(x: literal<>) {} diff --git a/DSL/tests/resources/formatting/types/literal types/with literals.sdstest b/DSL/tests/resources/formatting/types/literal types/with literals.sdstest new file mode 100644 index 000000000..ea0e92057 --- /dev/null +++ b/DSL/tests/resources/formatting/types/literal types/with literals.sdstest @@ -0,0 +1,9 @@ +segment mySegment( + x: literal < 1.0 , null > +) {} + +// ----------------------------------------------------------------------------- + +segment mySegment( + x: literal<1.0, null> +) {} From 97d7e540181f96d6537a364809cb00e1ad7c8345 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Tue, 11 Jul 2023 16:59:09 +0200 Subject: [PATCH 06/10] test: additional failing tests for grammar --- .../grammar/keywords as names/bad-unescaped literal.sdstest | 3 +++ .../types/member types/bad-literal type as member.sdstest | 5 +++++ ...good-receiver (literal) and member (not nullable).sdstest | 5 +++++ .../good-receiver (literal) and member (nullable).sdstest | 5 +++++ 4 files changed, 18 insertions(+) create mode 100644 DSL/tests/resources/grammar/keywords as names/bad-unescaped literal.sdstest create mode 100644 DSL/tests/resources/grammar/types/member types/bad-literal type as member.sdstest create mode 100644 DSL/tests/resources/grammar/types/member types/good-receiver (literal) and member (not nullable).sdstest create mode 100644 DSL/tests/resources/grammar/types/member types/good-receiver (literal) and member (nullable).sdstest diff --git a/DSL/tests/resources/grammar/keywords as names/bad-unescaped literal.sdstest b/DSL/tests/resources/grammar/keywords as names/bad-unescaped literal.sdstest new file mode 100644 index 000000000..8578433b6 --- /dev/null +++ b/DSL/tests/resources/grammar/keywords as names/bad-unescaped literal.sdstest @@ -0,0 +1,3 @@ +// $TEST$ syntax_error + +class literal diff --git a/DSL/tests/resources/grammar/types/member types/bad-literal type as member.sdstest b/DSL/tests/resources/grammar/types/member types/bad-literal type as member.sdstest new file mode 100644 index 000000000..701706f10 --- /dev/null +++ b/DSL/tests/resources/grammar/types/member types/bad-literal type as member.sdstest @@ -0,0 +1,5 @@ +// $TEST$ syntax_error + +segment mySegment( + x: OuterClass.literal<> +) {} diff --git a/DSL/tests/resources/grammar/types/member types/good-receiver (literal) and member (not nullable).sdstest b/DSL/tests/resources/grammar/types/member types/good-receiver (literal) and member (not nullable).sdstest new file mode 100644 index 000000000..6be0c881d --- /dev/null +++ b/DSL/tests/resources/grammar/types/member types/good-receiver (literal) and member (not nullable).sdstest @@ -0,0 +1,5 @@ +// $TEST$ no_syntax_error + +segment mySegment( + x: literal<>.InnerClass +) {} diff --git a/DSL/tests/resources/grammar/types/member types/good-receiver (literal) and member (nullable).sdstest b/DSL/tests/resources/grammar/types/member types/good-receiver (literal) and member (nullable).sdstest new file mode 100644 index 000000000..2c8e93a96 --- /dev/null +++ b/DSL/tests/resources/grammar/types/member types/good-receiver (literal) and member (nullable).sdstest @@ -0,0 +1,5 @@ +// $TEST$ no_syntax_error + +segment mySegment( + x: literal<>.InnerClass? +) {} From d2f03db3e5815040ebb201033596b4744bd7cf43 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Tue, 11 Jul 2023 17:02:18 +0200 Subject: [PATCH 07/10] feat: update grammar to handle literal types --- .../language-server/grammar/safe-ds.langium | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/DSL/src/language-server/grammar/safe-ds.langium b/DSL/src/language-server/grammar/safe-ds.langium index 61dbfe921..25fd0721a 100644 --- a/DSL/src/language-server/grammar/safe-ds.langium +++ b/DSL/src/language-server/grammar/safe-ds.langium @@ -841,6 +841,7 @@ SdsType returns SdsType: SdsPrimaryType returns SdsType: SdsCallableType + | SdsLiteralType | SdsNamedType | SdsUnionType ; @@ -854,6 +855,29 @@ SdsCallableType returns SdsCallableType: resultList=SdsResultList ; +interface SdsLiteralType extends SdsType { + literalList: SdsLiteralList +} + +SdsLiteralType returns SdsLiteralType: + 'literal' literalList=SdsLiteralList +; + +interface SdsLiteralList extends SdsObject { + literals: SdsLiteral[] +} + +SdsLiteralList returns SdsLiteralList: + {SdsLiteralList} + (LESS_THAN | CALL_TYPE_ARGUMENT_LIST_START) + ( + literals+=SdsLiteral + (',' literals+=SdsLiteral)* + ','? + )? + '>' +; + interface SdsNamedType extends SdsType { declaration: @SdsNamedTypeDeclaration typeArgumentList?: SdsTypeArgumentList @@ -1038,6 +1062,7 @@ terminal CALL_TYPE_ARGUMENT_LIST_START: ( '*' // Star projection as positional type argument | 'in' // Contravariant type projection as positional type argument | 'out' // Covariant type projection as positional type argument + | 'literal' // Invariant literal type as positional type argument | 'union' // Invariant union type as positional type argument | '>' // Empty type argument list | ID /\s*/ From 4a78c221a84463224ac4a35fe6e809b75ae1effb Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Tue, 11 Jul 2023 17:08:55 +0200 Subject: [PATCH 08/10] test: additional failing formatter tests --- .../receiver (literal) and member (not nullable).sdstest | 9 +++++++++ .../receiver (literal) and member (nullable).sdstest | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 DSL/tests/resources/formatting/types/member types/receiver (literal) and member (not nullable).sdstest create mode 100644 DSL/tests/resources/formatting/types/member types/receiver (literal) and member (nullable).sdstest diff --git a/DSL/tests/resources/formatting/types/member types/receiver (literal) and member (not nullable).sdstest b/DSL/tests/resources/formatting/types/member types/receiver (literal) and member (not nullable).sdstest new file mode 100644 index 000000000..1020fa44c --- /dev/null +++ b/DSL/tests/resources/formatting/types/member types/receiver (literal) and member (not nullable).sdstest @@ -0,0 +1,9 @@ +segment mySegment( + x: literal < > . InnerClass +) {} + +// ----------------------------------------------------------------------------- + +segment mySegment( + x: union<>.InnerClass +) {} diff --git a/DSL/tests/resources/formatting/types/member types/receiver (literal) and member (nullable).sdstest b/DSL/tests/resources/formatting/types/member types/receiver (literal) and member (nullable).sdstest new file mode 100644 index 000000000..dcbe565db --- /dev/null +++ b/DSL/tests/resources/formatting/types/member types/receiver (literal) and member (nullable).sdstest @@ -0,0 +1,9 @@ +segment mySegment( + x: literal < > . InnerClass ? +) {} + +// ----------------------------------------------------------------------------- + +segment mySegment( + x: literal<>.InnerClass? +) {} From 6ae6923f3ec6e31a19ed2246dc93e2ea0839aed6 Mon Sep 17 00:00:00 2001 From: Lars Reimann Date: Tue, 11 Jul 2023 17:13:55 +0200 Subject: [PATCH 09/10] feat: update formatter to handle literal types --- .../formatting/safe-ds-formatter.ts | 31 +++++++++++++++++-- .../language-server/helpers/astShortcuts.ts | 8 ++--- ...literal) and member (not nullable).sdstest | 2 +- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/DSL/src/language-server/formatting/safe-ds-formatter.ts b/DSL/src/language-server/formatting/safe-ds-formatter.ts index e65c26d68..bc5ada637 100644 --- a/DSL/src/language-server/formatting/safe-ds-formatter.ts +++ b/DSL/src/language-server/formatting/safe-ds-formatter.ts @@ -1,7 +1,7 @@ import { AbstractFormatter, AstNode, CstNode, findCommentNode, Formatting, isAstNode } from 'langium'; import * as ast from '../generated/ast'; import { SdsImport, SdsImportAlias, SdsModule } from '../generated/ast'; -import { annotationCallsOrEmpty, typeArgumentsOrEmpty } from '../helpers/astShortcuts'; +import { annotationCallsOrEmpty, literalsOrEmpty, typeArgumentsOrEmpty } from '../helpers/astShortcuts'; import { FormattingAction, FormattingActionOptions } from 'langium/src/lsp/formatter'; import noSpace = Formatting.noSpace; import newLine = Formatting.newLine; @@ -149,6 +149,10 @@ export class SafeDSFormatter extends AbstractFormatter { this.formatSdsMemberType(node); } else if (ast.isSdsCallableType(node)) { this.formatSdsCallableType(node); + } else if (ast.isSdsLiteralType(node)) { + this.formatSdsLiteralType(node); + } else if (ast.isSdsLiteralList(node)) { + this.formatSdsLiteralList(node); } else if (ast.isSdsNamedType(node)) { this.formatSdsNamedType(node); } else if (ast.isSdsUnionType(node)) { @@ -761,6 +765,25 @@ export class SafeDSFormatter extends AbstractFormatter { formatter.keyword('->').surround(oneSpace()); } + private formatSdsLiteralType(node: ast.SdsLiteralType): void { + const formatter = this.getNodeFormatter(node); + + formatter.keyword('literal').append(noSpace()); + } + + private formatSdsLiteralList(node: ast.SdsLiteralList): void { + const formatter = this.getNodeFormatter(node); + const literals = node.literals ?? []; + + if (literals.length > 0) { + formatter.node(literals[0]).prepend(noSpace()); + formatter.nodes(...literals.slice(1)).prepend(oneSpace()); + } + + formatter.keywords(',').prepend(noSpace()); + formatter.keyword('>').prepend(noSpace()); + } + private formatSdsNamedType(node: ast.SdsNamedType) { const formatter = this.getNodeFormatter(node); @@ -847,10 +870,12 @@ export class SafeDSFormatter extends AbstractFormatter { if (ast.isSdsCallableType(node) || ast.isSdsMemberType(node)) { return true; - } else if (ast.isSdsUnionType(node)) { - return typeArgumentsOrEmpty(node.typeArgumentList).length > 0; + } else if (ast.isSdsLiteralType(node)) { + return literalsOrEmpty(node).length > 0; } else if (ast.isSdsNamedType(node)) { return typeArgumentsOrEmpty(node.typeArgumentList).length > 0; + } else if (ast.isSdsUnionType(node)) { + return typeArgumentsOrEmpty(node.typeArgumentList).length > 0; } else { return false; } diff --git a/DSL/src/language-server/helpers/astShortcuts.ts b/DSL/src/language-server/helpers/astShortcuts.ts index 6301f9a46..3bede7ce5 100644 --- a/DSL/src/language-server/helpers/astShortcuts.ts +++ b/DSL/src/language-server/helpers/astShortcuts.ts @@ -3,8 +3,8 @@ import { isSdsDeclaration, SdsAnnotatedObject, SdsAnnotationCall, - SdsClass, - SdsObject, + SdsLiteral, + SdsLiteralType, SdsTypeArgument, SdsTypeArgumentList, } from '../generated/ast'; @@ -17,8 +17,8 @@ export const annotationCallsOrEmpty = function (node: SdsAnnotatedObject): SdsAn } }; -export const classMembersOrEmpty = function (node: SdsClass): SdsObject[] { - return node.body?.members ?? []; +export const literalsOrEmpty = function (node: SdsLiteralType | undefined): SdsLiteral[] { + return node?.literalList?.literals ?? []; }; export const typeArgumentsOrEmpty = function (node: SdsTypeArgumentList | undefined): SdsTypeArgument[] { diff --git a/DSL/tests/resources/formatting/types/member types/receiver (literal) and member (not nullable).sdstest b/DSL/tests/resources/formatting/types/member types/receiver (literal) and member (not nullable).sdstest index 1020fa44c..d484c6e06 100644 --- a/DSL/tests/resources/formatting/types/member types/receiver (literal) and member (not nullable).sdstest +++ b/DSL/tests/resources/formatting/types/member types/receiver (literal) and member (not nullable).sdstest @@ -5,5 +5,5 @@ segment mySegment( // ----------------------------------------------------------------------------- segment mySegment( - x: union<>.InnerClass + x: literal<>.InnerClass ) {} From 81874afde35cd30025e0354ac8aa9d2aa91f2796 Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:17:03 +0000 Subject: [PATCH 10/10] style: apply automated linter fixes --- DSL/vitest.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSL/vitest.config.ts b/DSL/vitest.config.ts index b1e860984..201219586 100644 --- a/DSL/vitest.config.ts +++ b/DSL/vitest.config.ts @@ -10,6 +10,6 @@ export default defineConfig({ include: ['src'], exclude: ['**/generated'], }, - exclude: ['out'] + exclude: ['out'], }, });