Skip to content

Commit

Permalink
feat: Describe schemas in the DSL (#13) and Tool to infer initial sch…
Browse files Browse the repository at this point in the history
…ema of dataset (#12)
  • Loading branch information
MShahzaib committed Jun 22, 2022
1 parent 6c255b0 commit fdc0c10
Show file tree
Hide file tree
Showing 36 changed files with 576 additions and 52 deletions.
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
2 changes: 2 additions & 0 deletions DSL/com.larsreimann.safeds/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ dependencies {
api(platform("org.eclipse.xtext:xtext-dev-bom:$xtextVersion"))
implementation("org.eclipse.xtext:org.eclipse.xtext:$xtextVersion")

implementation("tech.tablesaw:tablesaw-core:0.43.1")

testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.2")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.8.2")
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 @@ -29,3 +29,5 @@ fun SdsTypeParameter.kind(): SdsKind {
return SdsKind.values().firstOrNull { it.kind == this.kind }
?: throw IllegalArgumentException("Unknown kind '$kind'.")
}

fun SdsTypeParameter.hasSchemaKind() = this.kind() == SdsKind.SchemaKind
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 @@ -7,6 +7,7 @@

package com.larsreimann.safeds.emf

import com.larsreimann.safeds.constant.hasSchemaKind
import com.larsreimann.safeds.safeDS.SdsAbstractAssignee
import com.larsreimann.safeds.safeDS.SdsAbstractCallable
import com.larsreimann.safeds.safeDS.SdsAbstractClassMember
Expand Down Expand Up @@ -39,6 +40,8 @@ import com.larsreimann.safeds.safeDS.SdsEnumVariant
import com.larsreimann.safeds.safeDS.SdsExpressionLambda
import com.larsreimann.safeds.safeDS.SdsFunction
import com.larsreimann.safeds.safeDS.SdsFunctionBody
import com.larsreimann.safeds.safeDS.SdsGoalArgument
import com.larsreimann.safeds.safeDS.SdsGoalCall
import com.larsreimann.safeds.safeDS.SdsImport
import com.larsreimann.safeds.safeDS.SdsNamedType
import com.larsreimann.safeds.safeDS.SdsParameter
Expand Down Expand Up @@ -177,6 +180,10 @@ fun SdsClass?.typeParametersOrEmpty(): List<SdsTypeParameter> {
return this?.typeParameterList?.typeParameters.orEmpty()
}

fun SdsClass?.hasSchema(): Boolean {
return this?.typeParametersOrEmpty()?.any { it.hasSchemaKind() } ?: false
}

fun SdsClass?.parentTypesOrEmpty(): List<SdsAbstractType> {
return this?.parentTypeList?.parentTypes.orEmpty()
}
Expand Down Expand Up @@ -247,6 +254,12 @@ fun SdsFunction?.constraintsOrEmpty(): List<SdsAbstractConstraintGoal> {
.orEmpty()
}

// SdsGoalCall -------------------------------------------------------------------------------------

fun SdsGoalCall?.argumentsOrEmpty(): List<SdsGoalArgument> {
return this?.argumentList?.arguments.orEmpty()
}

// SdsImport ---------------------------------------------------------------------------------------

fun SdsImport.aliasNameOrNull(): String? {
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
Loading

0 comments on commit fdc0c10

Please sign in to comment.