Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: describe schemas in the DSL #78

Merged
merged 3 commits into from
Jun 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DSL/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ tasks.register("generateXtextLanguage") {

standardLanguage {
setName("com.larsreimann.safeds.SafeDS")
setFileExtensions("sdsflow,sdsstub,sdstest")
setFileExtensions("sdsflow,sdsschema,sdsstub,sdstest")
addReferencedResource("platform:/resource/com.larsreimann.safeds/model/SafeDS.genmodel")

setFormatter(
Expand Down
1 change: 1 addition & 0 deletions DSL/com.larsreimann.safeds.vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
],
"extensions": [
".sdsflow",
".sdsschema",
".sdsstub",
".sdstest"
],
Expand Down
13 changes: 12 additions & 1 deletion DSL/com.larsreimann.safeds/model/SafeDS.ecore
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
<eStructuralFeatures xsi:type="ecore:EReference" name="type" eType="#//SdsAbstractType" containment="true" />
</eClassifiers>
<!-- Class -->
<eClassifiers xsi:type="ecore:EClass" name="SdsClass" abstract="false" eSuperTypes="#//SdsAbstractCallable #//SdsAbstractClassMember #//SdsAbstractCompilationUnitMember #//SdsAbstractNamedTypeDeclaration">
<eClassifiers xsi:type="ecore:EClass" name="SdsClass" eSuperTypes="#//SdsAbstractCallable #//SdsAbstractClassMember #//SdsAbstractCompilationUnitMember #//SdsAbstractNamedTypeDeclaration">
<eStructuralFeatures xsi:type="ecore:EReference" name="typeParameterList" eType="#//SdsTypeParameterList" containment="true" />
<eStructuralFeatures xsi:type="ecore:EReference" name="parentTypeList" eType="#//SdsParentTypeList" containment="true" />
<eStructuralFeatures xsi:type="ecore:EReference" name="body" eType="#//SdsClassBody" containment="true" />
Expand Down Expand Up @@ -183,6 +183,17 @@
<eClassifiers xsi:type="ecore:EClass" name="SdsFunctionBody" eSuperTypes="#//SdsAbstractObject">
<eStructuralFeatures xsi:type="ecore:EReference" name="statements" upperBound="-1" eType="#//SdsAbstractObject" containment="true" />
</eClassifiers>
<!-- Schema -->
<eClassifiers xsi:type="ecore:EClass" name="SdsSchema" eSuperTypes="#//SdsAbstractCompilationUnitMember">
<eStructuralFeatures xsi:type="ecore:EReference" name="columnList" eType="#//SdsColumnList" containment="true" />
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="SdsColumnList" eSuperTypes="#//SdsAbstractObject">
<eStructuralFeatures xsi:type="ecore:EReference" name="columns" upperBound="-1" eType="#//SdsColumn" containment="true" />
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="SdsColumn" eSuperTypes="#//SdsAbstractObject">
<eStructuralFeatures xsi:type="ecore:EReference" name="columnName" eType="#//SdsString" containment="true" />
<eStructuralFeatures xsi:type="ecore:EReference" name="columnType" eType="#//SdsAbstractType" containment="true" />
</eClassifiers>
<!-- Step -->
<eClassifiers xsi:type="ecore:EClass" name="SdsStep" eSuperTypes="#//SdsAbstractCallable #//SdsAbstractCompilationUnitMember">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="visibility" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString" />
Expand Down
11 changes: 11 additions & 0 deletions DSL/com.larsreimann.safeds/model/SafeDS.genmodel
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,17 @@
<genClasses ecoreClass="SafeDS.ecore#//SdsFunctionBody">
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference SafeDS.ecore#//SdsFunctionBody/statements" />
</genClasses>
<!-- Schema -->
<genClasses ecoreClass="SafeDS.ecore#//SdsSchema">
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference SafeDS.ecore#//SdsSchema/columnList" />
</genClasses>
<genClasses ecoreClass="SafeDS.ecore#//SdsColumnList">
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference SafeDS.ecore#//SdsColumnList/columns" />
</genClasses>
<genClasses ecoreClass="SafeDS.ecore#//SdsColumn">
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference SafeDS.ecore#//SdsColumn/columnName" />
<genFeatures property="None" children="true" createChild="true" ecoreFeature="ecore:EReference SafeDS.ecore#//SdsColumn/columnType" />
</genClasses>
<!-- Step -->
<genClasses ecoreClass="SafeDS.ecore#//SdsStep">
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute SafeDS.ecore#//SdsStep/visibility" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ SdsCompilationUnitMember returns SdsAbstractAnnotatedObject
resultList=SdsResultList?
body=SdsFunctionBody?

| {SdsPredicate.annotationCallList=current}
'predicate' name=ID
parameterList=SdsParameterList
resultList=SdsResultList?
goalList=SdsGoalList

| {SdsSchema.annotationCallList=current}
'schema' name=ID
columnList=SdsColumnList

| {SdsStep.annotationCallList=current}
visibility=('internal'|'private')?
'step' name=ID
Expand All @@ -59,12 +69,6 @@ SdsCompilationUnitMember returns SdsAbstractAnnotatedObject
| {SdsWorkflow.annotationCallList=current}
'workflow' name=ID
body=SdsBlock

| {SdsPredicate.annotationCallList=current}
'predicate' name=ID
parameterList=SdsParameterList
resultList=SdsResultList?
goalList=SdsGoalList
)
;

Expand Down Expand Up @@ -516,7 +520,7 @@ SdsTemplateStringEnd


/**********************************************************************************************************************
* Predicates
* Predicates / Goals
**********************************************************************************************************************/

SdsGoalList
Expand Down Expand Up @@ -576,6 +580,19 @@ SdsParenthesizedGoalExpression
;


/**********************************************************************************************************************
* Schemas
**********************************************************************************************************************/

SdsColumnList
: {SdsColumnList} '{' ( columns+=SdsColumn (',' columns+=SdsColumn)* ','?)? '}'
;

SdsColumn
: columnName=SdsString ":" columnType=SdsType
;


/**********************************************************************************************************************
* Names
**********************************************************************************************************************/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ enum class SdsFileExtension(val extension: String) {
*/
Flow("sdsflow"),

/**
* Marks the file as a schema file.
*
* @see isInSchemaFile
* @see isSchemaFile
*/
Schema("sdsschema"),

/**
* Marks the file as a stub file, which describes an external API.
*
Expand Down Expand Up @@ -45,6 +53,11 @@ enum class SdsFileExtension(val extension: String) {
*/
fun EObject.isInFlowFile() = this.eResource().isFlowFile()

/**
* Returns whether the object is contained in schema file.
*/
fun EObject.isInSchemaFile() = this.eResource().isSchemaFile()

/**
* Returns whether the object is contained in stub file.
*/
Expand All @@ -60,6 +73,11 @@ fun EObject.isInTestFile() = this.eResource().isTestFile()
*/
fun Resource.isFlowFile() = this.hasExtension(SdsFileExtension.Flow)

/**
* Returns whether the resource represents a schema file.
*/
fun Resource.isSchemaFile() = this.hasExtension(SdsFileExtension.Schema)

/**
* Returns whether the resource represents a stub file.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import com.larsreimann.safeds.safeDS.SdsBoolean
import com.larsreimann.safeds.safeDS.SdsCall
import com.larsreimann.safeds.safeDS.SdsCallableType
import com.larsreimann.safeds.safeDS.SdsClass
import com.larsreimann.safeds.safeDS.SdsColumn
import com.larsreimann.safeds.safeDS.SdsCompilationUnit
import com.larsreimann.safeds.safeDS.SdsConstraint
import com.larsreimann.safeds.safeDS.SdsEnum
Expand Down Expand Up @@ -90,6 +91,7 @@ import com.larsreimann.safeds.safeDS.SdsProtocolTokenClass
import com.larsreimann.safeds.safeDS.SdsReference
import com.larsreimann.safeds.safeDS.SdsResult
import com.larsreimann.safeds.safeDS.SdsResultList
import com.larsreimann.safeds.safeDS.SdsSchema
import com.larsreimann.safeds.safeDS.SdsStarProjection
import com.larsreimann.safeds.safeDS.SdsStep
import com.larsreimann.safeds.safeDS.SdsString
Expand Down Expand Up @@ -548,6 +550,19 @@ fun createSdsConstraint(goals: List<SdsAbstractConstraintGoal>): SdsConstraint {
}
}

/**
* Returns a new object of class [SdsColumn].
*/
fun createSdsColumn(
columnName: SdsString,
columnType: SdsAbstractType
): SdsColumn {
return factory.createSdsColumn().apply {
this.columnName = columnName
this.columnType = columnType
}
}

/**
* Returns a new object of class [SdsEnum].
*/
Expand Down Expand Up @@ -1295,6 +1310,48 @@ fun createSdsStarProjection(): SdsStarProjection {
return factory.createSdsStarProjection()
}

/**
* Returns a new object of class [SdsSchema].
*/
fun createSdsSchema(
name: String,
annotationCalls: List<SdsAnnotationCall> = emptyList(),
columns: List<SdsColumn> = emptyList()
): SdsSchema {
return factory.createSdsSchema().apply {
this.name = name
this.annotationCallList = createSdsAnnotationCallList(annotationCalls)
columns.forEach { addColumn(it) }
}
}

/**
* Adds a new object of class [SdsSchema] to the receiver.
*/
fun SdsCompilationUnit.sdsSchema(
name: String,
annotationCalls: List<SdsAnnotationCall> = emptyList(),
columns: List<SdsColumn> = emptyList()
) {
this.addMember(
createSdsSchema(
name,
annotationCalls,
columns
)
)
}

/**
* Adds a new column to the receiver.
*/
private fun SdsSchema.addColumn(column: SdsColumn) {
if (this.columnList == null) {
this.columnList = factory.createSdsColumnList()
}
this.columnList.columns += column
}

/**
* Returns a new object of class [SdsStep].
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import com.larsreimann.safeds.safeDS.SdsCall
import com.larsreimann.safeds.safeDS.SdsCallableType
import com.larsreimann.safeds.safeDS.SdsClass
import com.larsreimann.safeds.safeDS.SdsClassBody
import com.larsreimann.safeds.safeDS.SdsColumn
import com.larsreimann.safeds.safeDS.SdsColumnList
import com.larsreimann.safeds.safeDS.SdsCompilationUnit
import com.larsreimann.safeds.safeDS.SdsConstraint
import com.larsreimann.safeds.safeDS.SdsEnum
Expand Down Expand Up @@ -80,6 +82,7 @@ import com.larsreimann.safeds.safeDS.SdsProtocolSubterm
import com.larsreimann.safeds.safeDS.SdsProtocolSubtermList
import com.larsreimann.safeds.safeDS.SdsResult
import com.larsreimann.safeds.safeDS.SdsResultList
import com.larsreimann.safeds.safeDS.SdsSchema
import com.larsreimann.safeds.safeDS.SdsStep
import com.larsreimann.safeds.safeDS.SdsTemplateString
import com.larsreimann.safeds.safeDS.SdsTypeArgument
Expand Down Expand Up @@ -901,6 +904,67 @@ class SafeDSFormatter : AbstractFormatter2() {
}
}

/**********************************************************************************************************
* Schema
**********************************************************************************************************/

is SdsSchema -> {

// Features "annotations"
doc.formatAnnotations(obj)

// Keyword "schema"
if (obj.annotationCallsOrEmpty().isEmpty()) {
doc.formatKeyword(obj, "schema", noSpace, oneSpace)
} else {
doc.formatKeyword(obj, "schema", oneSpace, oneSpace)
}

// Feature "name"
doc.formatFeature(obj, SDS_ABSTRACT_DECLARATION__NAME, null, oneSpace)

// EObject "columnList"
doc.formatObject(obj.columnList, oneSpace, null)
}
is SdsColumnList -> {

// Keyword "{"
val openingBrace = obj.regionForKeyword("{")
if (obj.columns.isEmpty()) {
doc.append(openingBrace, noSpace)
} else {
doc.append(openingBrace, newLine)
}

// Feature "columns"
obj.columns.forEach {
doc.formatObject(it, newLine, noSpace)
}

// Keywords ","
doc.formatKeyword(obj, ",", noSpace, newLine)

// Keyword "}"
val closingBrace = obj.regionForKeyword("}")
if (obj.columns.isEmpty()) {
doc.prepend(closingBrace, noSpace)
} else {
doc.prepend(closingBrace, newLine)
}
doc.interior(openingBrace, closingBrace, indent)
}
is SdsColumn -> {

// EObject "columnName"
doc.formatObject(obj.columnName, null, oneSpace)

// Keyword ":"
doc.formatKeyword(obj, ":", oneSpace, oneSpace)

// EObject "columnType"
doc.formatObject(obj.columnType)
}

/**********************************************************************************************************
* Statements
**********************************************************************************************************/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ enum class ErrorCode {
REDECLARATION,

FileMustDeclarePackage,
StubFileMustNotDeclareWorkflowsOrSteps,
StubFileMustNotDeclareWorkflowsSchemasOrSteps,
WorkflowFileMustOnlyDeclareWorkflowsAndSteps,
SchemaFileMustOnlyDeclareSchemas,

ANNOTATION_IS_SINGLE_USE,
DEPRECATED_REQUIRED_PARAMETER,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.larsreimann.safeds.validation.declarations

import com.larsreimann.safeds.constant.isInFlowFile
import com.larsreimann.safeds.constant.isInSchemaFile
import com.larsreimann.safeds.constant.isInStubFile
import com.larsreimann.safeds.constant.isInTestFile
import com.larsreimann.safeds.emf.compilationUnitMembersOrEmpty
Expand All @@ -10,6 +12,7 @@ import com.larsreimann.safeds.safeDS.SafeDSPackage.Literals
import com.larsreimann.safeds.safeDS.SdsAbstractDeclaration
import com.larsreimann.safeds.safeDS.SdsCompilationUnit
import com.larsreimann.safeds.safeDS.SdsImport
import com.larsreimann.safeds.safeDS.SdsSchema
import com.larsreimann.safeds.safeDS.SdsStep
import com.larsreimann.safeds.safeDS.SdsWorkflow
import com.larsreimann.safeds.scoping.externalGlobalDeclarations
Expand All @@ -25,16 +28,16 @@ class CompilationUnitChecker : AbstractSafeDSChecker() {
fun members(sdsCompilationUnit: SdsCompilationUnit) {
if (sdsCompilationUnit.isInStubFile()) {
sdsCompilationUnit.compilationUnitMembersOrEmpty()
.filter { it is SdsWorkflow || it is SdsStep }
.filter { it is SdsWorkflow || it is SdsStep || it is SdsSchema }
.forEach {
error(
"A stub file must not declare workflows or steps.",
"A stub file must not declare workflows, schemas or steps.",
it,
Literals.SDS_ABSTRACT_DECLARATION__NAME,
ErrorCode.StubFileMustNotDeclareWorkflowsOrSteps
ErrorCode.StubFileMustNotDeclareWorkflowsSchemasOrSteps
)
}
} else if (!sdsCompilationUnit.isInTestFile()) {
} else if (sdsCompilationUnit.isInFlowFile()) {
sdsCompilationUnit.compilationUnitMembersOrEmpty()
.filter { it !is SdsWorkflow && it !is SdsStep }
.forEach {
Expand All @@ -45,6 +48,17 @@ class CompilationUnitChecker : AbstractSafeDSChecker() {
ErrorCode.WorkflowFileMustOnlyDeclareWorkflowsAndSteps
)
}
} else if (sdsCompilationUnit.isInSchemaFile()) {
sdsCompilationUnit.compilationUnitMembersOrEmpty()
.filter { it !is SdsSchema }
.forEach {
error(
"A schema file must only declare schemas.",
it,
Literals.SDS_ABSTRACT_DECLARATION__NAME,
ErrorCode.SchemaFileMustOnlyDeclareSchemas
)
}
}
}

Expand Down
Loading