Skip to content

Commit

Permalink
feat: syntax and formatting for literal types (#529)
Browse files Browse the repository at this point in the history
Closes partially #80.

### Summary of Changes

* Add syntax for literal types:
  ```
  literal<1, 1.0, true, false, null, "">
  ```
* Update formatter to handle literal types

---------

Co-authored-by: megalinter-bot <[email protected]>
  • Loading branch information
lars-reimann and megalinter-bot authored Jul 11, 2023
1 parent e204fe9 commit 32aca34
Show file tree
Hide file tree
Showing 20 changed files with 143 additions and 85 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ coverage/
dist/
dist-ssr/
out/
DSL/syntaxes/safe-ds.tmLanguage.json

# Node
.npm/
Expand Down
31 changes: 28 additions & 3 deletions DSL/src/language-server/formatting/safe-ds-formatter.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
Expand Down
25 changes: 25 additions & 0 deletions DSL/src/language-server/grammar/safe-ds.langium
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,7 @@ SdsType returns SdsType:

SdsPrimaryType returns SdsType:
SdsCallableType
| SdsLiteralType
| SdsNamedType
| SdsUnionType
;
Expand All @@ -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
Expand Down Expand Up @@ -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*/
Expand Down
8 changes: 4 additions & 4 deletions DSL/src/language-server/helpers/astShortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {
isSdsDeclaration,
SdsAnnotatedObject,
SdsAnnotationCall,
SdsClass,
SdsObject,
SdsLiteral,
SdsLiteralType,
SdsTypeArgument,
SdsTypeArgumentList,
} from '../generated/ast';
Expand All @@ -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[] {
Expand Down
78 changes: 0 additions & 78 deletions DSL/syntaxes/safe-ds.tmLanguage.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
segment s(
f: literal<1.0 , null , >
) {}

// -----------------------------------------------------------------------------

segment s(
f: literal<1.0, null,>
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
segment mySegment(x: literal < >) {}

// -----------------------------------------------------------------------------

segment mySegment(x: literal<>) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
segment mySegment(
x: literal < 1.0 , null >
) {}

// -----------------------------------------------------------------------------

segment mySegment(
x: literal<1.0, null>
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
segment mySegment(
x: literal < > . InnerClass
) {}

// -----------------------------------------------------------------------------

segment mySegment(
x: literal<>.InnerClass
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
segment mySegment(
x: literal < > . InnerClass ?
) {}

// -----------------------------------------------------------------------------

segment mySegment(
x: literal<>.InnerClass?
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// $TEST$ syntax_error

class literal
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// $TEST$ no_syntax_error

segment s(
f: literal<true, false, >
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// $TEST$ syntax_error

segment mySegment(
x: literal<literal<>>
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// $TEST$ syntax_error

segment mySegment(
x: literal<
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// $TEST$ no_syntax_error

segment mySegment(
x: literal<>
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// $TEST$ no_syntax_error

segment mySegment(
x: literal<null, true, false, 1, 1.0, "s">
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// $TEST$ syntax_error

segment mySegment(
x: OuterClass.literal<>
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// $TEST$ no_syntax_error

segment mySegment(
x: literal<>.InnerClass
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// $TEST$ no_syntax_error

segment mySegment(
x: literal<>.InnerClass?
) {}
1 change: 1 addition & 0 deletions DSL/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ export default defineConfig({
include: ['src'],
exclude: ['**/generated'],
},
exclude: ['out'],
},
});

0 comments on commit 32aca34

Please sign in to comment.