diff --git a/bundles/org.eclipse.mita.base/META-INF/MANIFEST.MF b/bundles/org.eclipse.mita.base/META-INF/MANIFEST.MF index f38b1021..a112c4b2 100644 --- a/bundles/org.eclipse.mita.base/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.mita.base/META-INF/MANIFEST.MF @@ -31,7 +31,8 @@ Require-Bundle: org.eclipse.xtext;visibility:=reexport, com.google.guava, org.eclipse.mita.library.extension, org.eclipse.core.resources;bundle-version="3.12.0", - com.google.gson;bundle-version="2.2.4" + com.google.gson;bundle-version="2.2.4", + org.eclipse.xtext.ui Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Export-Package: io.protostuff, io.protostuff.runtime, diff --git a/bundles/org.eclipse.mita.base/model/types.xcore b/bundles/org.eclipse.mita.base/model/types.xcore index c53a758c..1228b857 100644 --- a/bundles/org.eclipse.mita.base/model/types.xcore +++ b/bundles/org.eclipse.mita.base/model/types.xcore @@ -51,7 +51,7 @@ class TypeReferenceSpecifier extends PresentTypeSpecifier { val args = if(typeArguments.empty) { "" } else { - "<" + typeArguments.map[if(it === null) {"null"} else {it.toString}].reduce[p1, p2| p1 + ", " + p2] + ">" + "<" + typeArguments.map[if(it === null) {"null"} else {it.toString}].reduce[p1, p2| p1 + ", " + p2] + ">" + (if(optional) {"?"} else {""}) } val ref = eGet(TypesPackage.eINSTANCE.typeReferenceSpecifier_Type, false) @@ -60,7 +60,14 @@ class TypeReferenceSpecifier extends PresentTypeSpecifier { refText = refText ?: "" refText = refText.trim - return refText + args; + val optionalModifier = if(optional) { + "?"; + } + else { + "" + } + + return referenceModifiers.join + refText + optionalModifier + args; } } class TypeReferenceLiteral extends Literal { @@ -337,6 +344,12 @@ class Parameter extends TypedElement, NamedElement { } } +abstract class ExportableOperation extends Operation, Exportable { + op String toString() { + return super.toString(); + } +} + abstract class Expression { } class ParameterWithDefaultValue extends Parameter { @@ -415,6 +428,15 @@ class StructureType extends StructuralType, HasAccessors, Exportable { } } +class GeneratedFunctionDefinition extends ExportableOperation, GeneratedElement { + op String getId(){ + return null; + } + op String toString() { + return super.toString(); + } +} + class GeneratedType extends ComplexType, GeneratedElement, Exportable { op String toString() { super.toString @@ -422,7 +444,7 @@ class GeneratedType extends ComplexType, GeneratedElement, Exportable { contains Operation constructor } -class GeneratedTypeConstructor extends Operation, GeneratedObject { +class GeneratedTypeConstructor extends GeneratedFunctionDefinition, GeneratedObject { contains transient TypeReferenceSpecifier generatedTypeSpecifier op String getName() { @@ -435,6 +457,16 @@ class GeneratedTypeConstructor extends Operation, GeneratedObject { return "con_" + generatedType?.name } + op boolean isExported() { + val generatedType = if(eContainer instanceof GeneratedType) { + eContainer as GeneratedType; + } + else { + return false; + } + return generatedType.isExported; + } + op TypeParameter[] getTypeParameters() { return (eContainer as GeneratedType).typeParameters; } @@ -583,3 +615,8 @@ class CoercionExpression extends Expression { } } +class SystemResourceEvent extends Event { + String sizeInferrer +} + + diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/TypeDsl.xtext b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/TypeDsl.xtext index 866742e3..9e5deb4a 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/TypeDsl.xtext +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/TypeDsl.xtext @@ -78,13 +78,16 @@ GeneratedType returns GeneratedType: 'generator' generator=STRING 'size-inferrer' sizeInferrer=STRING ('validator' validator=STRING)? - constructor = GeneratedTypeConstructor + (constructor = GeneratedTypeConstructor)? ';' ; GeneratedTypeConstructor returns GeneratedTypeConstructor: {GeneratedTypeConstructor} 'constructor' name='con' '(' (parameters+=GeneratedTypeParameter (',' parameters+=GeneratedTypeParameter)*)? ')' + ('generator' generator=STRING)? + ('size-inferrer' sizeInferrer=STRING)? + ('validator' validator=STRING)? ; GeneratedTypeParameter returns GeneratedTypeParameter: @@ -156,6 +159,13 @@ ProductMember returns ProductMember: name=ID ':' typeSpecifier=TypeSpecifier ; +SystemResourceEvent returns SystemResourceEvent: + 'event' name=ID ((':' typeSpecifier=TypeSpecifier) | (typeSpecifier=NullTypeSpecifier)) ('{' + ("size-inferrer" sizeInferrer=STRING)? + '}')? +; + + /** * BELOW THIS LINE @@ -417,6 +427,7 @@ ReservedKeywords: 'catch' | 'checked' | 'constructor' | + 'con' | 'do' | 'else' | 'enum' | diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/expressions/util/ExpressionUtils.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/expressions/util/ExpressionUtils.xtend index 3512eb9d..e69a75bc 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/expressions/util/ExpressionUtils.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/expressions/util/ExpressionUtils.xtend @@ -110,7 +110,6 @@ class ExpressionUtils { if(name == "self") { return expr.arguments.head.value; } - argIndex--; } } if(argIndex === null || argIndex >= sortedArgs.length) return null; diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/BaseConstraintFactory.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/BaseConstraintFactory.xtend index 0682445d..2a25171d 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/BaseConstraintFactory.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/BaseConstraintFactory.xtend @@ -48,6 +48,7 @@ import org.eclipse.mita.base.expressions.StringLiteral import org.eclipse.mita.base.expressions.TypeCastExpression import org.eclipse.mita.base.expressions.UnaryOperator import org.eclipse.mita.base.expressions.ValueRange +import org.eclipse.mita.base.types.Event import org.eclipse.mita.base.types.ComplexType import org.eclipse.mita.base.types.ExceptionTypeDeclaration import org.eclipse.mita.base.types.Expression @@ -128,6 +129,7 @@ class BaseConstraintFactory implements IConstraintFactory { protected IScopeProvider scopeProvider; public static final String GENERATOR_KEY = "generator"; + public static final String VALIDATOR_KEY = "validator"; public static final String SIZE_INFERRER_KEY = "sizeInferrer"; public static final String PARENT_NAME_KEY = "parentName"; public static final String ECLASS_KEY = "eClass"; @@ -220,7 +222,9 @@ class BaseConstraintFactory implements IConstraintFactory { } protected def void computeConstraintsForChildren(ConstraintSystem system, EObject context) { - context.eContents.forEach[ system.computeConstraints(it) ] + for(EObject child: context.eContents) { + system.computeConstraints(child) + } } protected def computeParameterType(ConstraintSystem system, Operation function, Iterable parms) { @@ -386,6 +390,10 @@ class BaseConstraintFactory implements IConstraintFactory { return system.associate(refType, varOrFun); } + protected dispatch def TypeVariable computeConstraints(ConstraintSystem system, Event event) { + return system.associate(system.computeConstraints(event.typeSpecifier), event); + } + protected def TypeVariable computeConstraintsForFunctionCall(ConstraintSystem system, EObject functionCall, EReference functionReference, String functionName, Iterable argExprs, List candidates) { return computeConstraintsForFunctionCall(system, functionCall, functionReference, functionName, system.computeArgumentConstraints(functionCall, functionName, argExprs), candidates); } @@ -818,6 +826,9 @@ class BaseConstraintFactory implements IConstraintFactory { if(genType.sizeInferrer !== null) { system.putUserData(result, SIZE_INFERRER_KEY, genType.sizeInferrer) } + if(genType.validator !== null) { + system.putUserData(result, VALIDATOR_KEY, genType.validator); + } system._defineUserData(genType as ComplexType, result); } protected dispatch def AbstractType doTranslateTypeDeclaration(ConstraintSystem system, GeneratedType genType) { @@ -905,7 +916,7 @@ class BaseConstraintFactory implements IConstraintFactory { // compute val ref = typeSpecifier.eGet(eRef, false) val reftext = if(ref instanceof EObject && !(ref as EObject).eIsProxy) ref.toString() else null; - val typeName = reftext ?: NodeModelUtils.findNodesForFeature(typeSpecifier, TypesPackage.eINSTANCE.typeReferenceSpecifier_Type)?.head?.text?.trim; + val typeName = reftext ?: NodeModelUtils.findNodesForFeature(BaseUtils.computeOrigin(typeSpecifier), TypesPackage.eINSTANCE.typeReferenceSpecifier_Type)?.head?.text?.trim; val typeArgTypes = typeArguments.map[system.computeConstraints(it) as AbstractType]; // since type specifiers reference something we don't always know the variance here val typeArgs = typeArgTypes.map[it -> Variance.UNKNOWN].force; diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/StdlibTypeRegistry.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/StdlibTypeRegistry.xtend index b148fe5b..a21c6575 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/StdlibTypeRegistry.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/StdlibTypeRegistry.xtend @@ -52,6 +52,7 @@ class StdlibTypeRegistry { public static val sigInstTypeQID = QualifiedName.create(#[/*"stdlib",*/ "siginst"]); public static val modalityTypeQID = QualifiedName.create(#[/*"stdlib",*/ "modality"]); public static val arrayTypeQID = QualifiedName.create(#[/*"stdlib",*/ "array"]); + public static val ringbufferTypeQID = QualifiedName.create(#[/*"stdlib",*/ "ringbuffer"]); public static val plusFunctionQID = QualifiedName.create(#["stdlib", "__PLUS__"]); public static val minusFunctionQID = QualifiedName.create(#["stdlib", "__MINUS__"]); public static val timesFunctionQID = QualifiedName.create(#["stdlib", "__TIMES__"]); diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/MitaBaseResource.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/MitaBaseResource.xtend index 2baec32d..9c60c0d8 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/MitaBaseResource.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/MitaBaseResource.xtend @@ -54,6 +54,7 @@ import org.eclipse.xtext.resource.IFragmentProvider import org.eclipse.xtext.resource.impl.ListBasedDiagnosticConsumer import org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider import org.eclipse.xtext.scoping.IScopeProvider +import org.eclipse.xtext.ui.resource.LiveScopeResourceSetInitializer import org.eclipse.xtext.util.CancelIndicator import org.eclipse.xtext.util.Triple import org.eclipse.xtext.xtext.XtextFragmentProvider @@ -105,6 +106,9 @@ class MitaBaseResource extends LazyLinkingResource { public final static String PROGRAM_EXT = ".mita" public final static String PLATFORM_EXT = ".platform" + @Inject + protected LiveScopeResourceSetInitializer liveScopeResourceSetInitializer + override toString() { val str = URI.toString; val len = str.length(); @@ -187,10 +191,12 @@ class MitaBaseResource extends LazyLinkingResource { public def generateLinkAndType(EObject model) { val diagnosticsConsumer = new ListBasedDiagnosticConsumer(); - model.eAllContents.filter(GeneratedObject).forEach [ - it.generateMembers() - ] - typeLinker.doActuallyClearReferences(model); + BaseUtils.ignoreChange(model, [ + typeLinker.doActuallyClearReferences(model); + model.eAllContents.filter(GeneratedObject).forEach [ + it.generateMembers() + ] + ]) typeLinker.linkModel(model, diagnosticsConsumer); typeDependentLinker.linkModel(model, diagnosticsConsumer); // size inference expects fully linked types, @@ -215,7 +221,8 @@ class MitaBaseResource extends LazyLinkingResource { timer.start("resourceDescriptions"); if (!resourceSet.loadOptions.containsKey(ResourceDescriptionsProvider.NAMED_BUILDER_SCOPE)) { - resourceSet.loadOptions.put(ResourceDescriptionsProvider.LIVE_SCOPE, true); +// resourceSet.loadOptions.put(ResourceDescriptionsProvider.LIVE_SCOPE, true); + liveScopeResourceSetInitializer.initialize(resourceSet); } val resourceDescriptions = resourceDescriptionsProvider.getResourceDescriptions(resourceSet); val thisResourceDescription = resourceDescriptions.getResourceDescription(resource.URI); diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/NicerTypeVariableNamesForErrorMessages.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/NicerTypeVariableNamesForErrorMessages.xtend index ff7e9d09..87db1338 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/NicerTypeVariableNamesForErrorMessages.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/infra/NicerTypeVariableNamesForErrorMessages.xtend @@ -18,7 +18,7 @@ import java.util.Random import java.util.stream.Collectors import java.util.stream.IntStream import org.eclipse.core.runtime.Assert -import org.eclipse.mita.base.typesystem.types.AbstractType.Either +import org.eclipse.mita.base.util.Either import org.eclipse.mita.base.typesystem.types.AbstractType.NameModifier class NicerTypeVariableNamesForErrorMessages extends NameModifier { diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/CoerciveSubtypeSolver.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/CoerciveSubtypeSolver.xtend index e19e9063..6cae8b97 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/CoerciveSubtypeSolver.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/CoerciveSubtypeSolver.xtend @@ -480,7 +480,7 @@ class CoerciveSubtypeSolver implements IConstraintSolver { return null; ].filterNull.force; } - }) ?: #[]; + })?.filterNull ?: #[]; return new TypeClassConstraintResolutionResult(Substitution.EMPTY, equalities + subtypeCheckResult.constraints, #[], coercions, typ, fun, distance + subtypeCheckResult.constraints.size); } @@ -875,6 +875,9 @@ class CoerciveSubtypeSolver implements IConstraintSolver { if(object === null) { return; } + if(object.eIsProxy) { + return; + } val uri = EcoreUtil.getURI(object); system.coercions.put(uri, type); diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/ConstraintSystem.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/ConstraintSystem.xtend index 065c4e0c..f3474311 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/ConstraintSystem.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/ConstraintSystem.xtend @@ -38,7 +38,6 @@ import org.eclipse.mita.base.typesystem.infra.TypeClass import org.eclipse.mita.base.typesystem.infra.TypeClassProxy import org.eclipse.mita.base.typesystem.serialization.SerializationAdapter import org.eclipse.mita.base.typesystem.types.AbstractType -import org.eclipse.mita.base.typesystem.types.AbstractType.Either import org.eclipse.mita.base.typesystem.types.AbstractType.NameModifier import org.eclipse.mita.base.typesystem.types.BottomType import org.eclipse.mita.base.typesystem.types.DependentTypeVariable @@ -47,6 +46,7 @@ import org.eclipse.mita.base.typesystem.types.TypeHole import org.eclipse.mita.base.typesystem.types.TypeVariable import org.eclipse.mita.base.typesystem.types.TypeVariableProxy import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.base.util.Either import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtext.diagnostics.Severity import org.eclipse.xtext.naming.QualifiedName @@ -375,7 +375,7 @@ class ConstraintSystem { val typeVar = getTypeVariable(typeVarOrigin); if(typeVar != t && t !== null) { - addConstraint(new EqualityConstraint(typeVar, t, new ValidationIssue(Severity.ERROR, '''«typeVarOrigin» must be of type "%2$s"''', typeVarOrigin, null, "")), toHead); + addConstraint(new EqualityConstraint(typeVar, t, new ValidationIssue(Severity.ERROR, '''«typeVarOrigin» (:: %1$s) must be of type "%2$s"''', typeVarOrigin, null, "")), toHead); } return typeVar; } @@ -502,8 +502,8 @@ class ConstraintSystem { println('''introducing «uri»!'''); } // explicitly set the origin to the resolved object, since the symbol table only contains proxies! - val tvIdx = this.getTypeVariable(it).idx; - return new TypeVariable(it, tvIdx) as AbstractType; + val tv = this.getTypeVariable(it); + return tv.replaceOrigin(it) as AbstractType; ].force; } diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/Substitution.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/Substitution.xtend index 0b4349ad..6523d258 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/Substitution.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/solver/Substitution.xtend @@ -182,6 +182,9 @@ class Substitution { } def void addToContent(TypeVariable tv, AbstractType typ) { + if(tv.idx == 2679 && typ.toString == "uint32") { + print("") + } content.put(tv.idx, typ); idxToTypeVariable.put(tv.idx, tv); val freeVars = typ.freeVars; diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/AbstractType.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/AbstractType.xtend index 490707a9..bf35c71a 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/AbstractType.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/AbstractType.xtend @@ -18,8 +18,8 @@ import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.typesystem.infra.Tree import org.eclipse.mita.base.typesystem.solver.ConstraintSystem import org.eclipse.mita.base.typesystem.solver.Substitution +import org.eclipse.mita.base.util.Either import org.eclipse.xtend.lib.annotations.Accessors -import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor @Accessors abstract class AbstractType { @@ -92,38 +92,7 @@ abstract class AbstractType { def AbstractType modifyNames(NameModifier converter) { map[it.modifyNames(converter)]; } - - /* Either is the opposite of a Pair. Let's compare them: - * val Pair pair = new Pair<>(1, true); - * val Either intLeft = new Left<>(1); - * val Either boolRight = new Right<>(true); - * - * now pair holds both 1 and true, where values of type Either<> hold only one of them. - * therefore one can look at pair as a much safer version of "Object", - * since there are only two possible values that it may be instead of all classes on the classpath. - * - * If this class is used more extensively we should add more functions like - * - isLeft/isRight, - * - map(Either, A=>C, B=>D), - * - match(onLeft: A=>C, onRight: B=>C), and so on. - * For now instanceof is enough, since we use this only in TypeVariable.modifyNames. - */ - public static abstract class Either { - public static def Either left(LEFT l) { - return new Left(l); - } - public static def Either right(RIGHT r) { - return new Right(r); - } - } - @FinalFieldsConstructor - public static class Left extends Either { - public val T value; - } - @FinalFieldsConstructor - public static class Right extends Either { - public val R value; - } + // basically a typedef of (A ~ typeof(TypeVariable.uniqueId)) => A -> A public static abstract class NameModifier implements IntFunction> { } diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/DependentTypeVariable.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/DependentTypeVariable.xtend index b0a4fb50..6ff68534 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/DependentTypeVariable.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/DependentTypeVariable.xtend @@ -4,6 +4,8 @@ import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.types.InstanceTypeParameter import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.mita.base.typesystem.solver.ConstraintSystem +import org.eclipse.mita.base.util.Left +import org.eclipse.mita.base.util.Right @Accessors class DependentTypeVariable extends TypeVariable { @@ -23,6 +25,10 @@ class DependentTypeVariable extends TypeVariable { this.dependsOn = dependsOn; } + override replaceOrigin(EObject origin) { + return new DependentTypeVariable(origin, idx, name, dependsOn); + } + override modifyNames(NameModifier converter) { val newName = converter.apply(idx); if(newName instanceof Left) { diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeHole.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeHole.xtend index b0ae60d2..830b49b1 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeHole.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeHole.xtend @@ -14,6 +14,8 @@ package org.eclipse.mita.base.typesystem.types import org.eclipse.emf.ecore.EObject +import org.eclipse.mita.base.util.Left +import org.eclipse.mita.base.util.Right import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtend.lib.annotations.EqualsHashCode @@ -29,6 +31,13 @@ class TypeHole extends TypeVariable { super(origin, idx, name); } + override getFreeVars() { + return #[]; + } + override replaceOrigin(EObject origin) { + return new TypeHole(origin, idx, name); + } + override modifyNames(NameModifier converter) { val newName = converter.apply(idx); if(newName instanceof Left) { diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeVariable.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeVariable.xtend index fa2c03ce..3315c424 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeVariable.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeVariable.xtend @@ -17,8 +17,9 @@ import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.typesystem.infra.Tree import org.eclipse.mita.base.typesystem.solver.ConstraintSystem import org.eclipse.mita.base.typesystem.solver.Substitution +import org.eclipse.mita.base.util.Left +import org.eclipse.mita.base.util.Right import org.eclipse.xtend.lib.annotations.Accessors -import org.eclipse.xtend.lib.annotations.EqualsHashCode /* * Info: TypeVariable.name is null unless an explicit display name is set. @@ -33,7 +34,6 @@ class TypeVariable extends AbstractType { return system.newTypeVariable(null); } - new(EObject origin, int idx) { this(origin, idx, null); } @@ -43,6 +43,10 @@ class TypeVariable extends AbstractType { this.idx = idx; } + def TypeVariable replaceOrigin(EObject origin) { + return new TypeVariable(origin, idx, name); + } + override quote() { return new Tree(this); } diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeVariableProxy.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeVariableProxy.xtend index 7fd61026..eeda50db 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeVariableProxy.xtend +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/typesystem/types/TypeVariableProxy.xtend @@ -20,6 +20,8 @@ import org.eclipse.mita.base.types.NamedElement import org.eclipse.mita.base.types.SumAlternative import org.eclipse.mita.base.typesystem.solver.ConstraintSystem import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.base.util.Left +import org.eclipse.mita.base.util.Right import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtend.lib.annotations.EqualsHashCode import org.eclipse.xtext.naming.QualifiedName @@ -69,6 +71,10 @@ class TypeVariableProxy extends TypeVariable { new(EObject origin, int idx, EReference reference, QualifiedName qualifiedName) { this(origin, idx, reference, qualifiedName, true); } + + override replaceOrigin(EObject origin) { + return new TypeVariableProxy(origin, idx, reference, targetQID, ambiguityResolutionStrategy, isLinkingProxy, name); + } public static def getQName(EObject origin, EReference reference) { var QualifiedName maybeQname; diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/util/BaseUtils.java b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/util/BaseUtils.java index 337b25a5..c86d3876 100644 --- a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/util/BaseUtils.java +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/util/BaseUtils.java @@ -342,7 +342,7 @@ public static T ignoreChange(final Resource resource, final Supplier acti return result; } - private static List getCacheAdapters(final Resource resource) { + public static List getCacheAdapters(final Resource resource) { final ArrayList cacheAdapters = BaseUtils.force( Iterables.filter(resource.eAdapters(), OnChangeEvictingCache.CacheAdapter.class)); diff --git a/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/util/Either.xtend b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/util/Either.xtend new file mode 100644 index 00000000..41defd1e --- /dev/null +++ b/bundles/org.eclipse.mita.base/src/org/eclipse/mita/base/util/Either.xtend @@ -0,0 +1,38 @@ +package org.eclipse.mita.base.util + +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor + +/* Either is the opposite of a Pair. Let's compare them: + * val Pair pair = new Pair<>(1, true); + * val Either intLeft = new Left<>(1); + * val Either boolRight = new Right<>(true); + * + * now pair holds both 1 and true, where values of type Either<> hold only one of them. + * therefore one can look at pair as a much safer version of "Object", + * since there are only two possible values that it may be instead of all classes on the classpath. + * + * If this class is used more extensively we should add more functions like + * - isLeft/isRight, + * - map(Either, A=>C, B=>D), + * - match(onLeft: A=>C, onRight: B=>C), and so on. + * For now instanceof is enough, since we use this only in TypeVariable.modifyNames. + */ +abstract class Either { + public static def Either left(LEFT l) { + return new Left(l); + } + + public static def Either right(RIGHT r) { + return new Right(r); + } +} + +@FinalFieldsConstructor +class Left extends Either { + public val T value; +} + +@FinalFieldsConstructor +class Right extends Either { + public val R value; +} diff --git a/bundles/org.eclipse.mita.cli/src/org/eclipse/mita/cli/commands/CompileCommand.xtend b/bundles/org.eclipse.mita.cli/src/org/eclipse/mita/cli/commands/CompileCommand.xtend index d15f87a1..c77f1cfc 100644 --- a/bundles/org.eclipse.mita.cli/src/org/eclipse/mita/cli/commands/CompileCommand.xtend +++ b/bundles/org.eclipse.mita.cli/src/org/eclipse/mita/cli/commands/CompileCommand.xtend @@ -41,6 +41,7 @@ import org.eclipse.xtext.validation.CheckMode import org.eclipse.xtext.validation.IResourceValidator import org.apache.commons.cli.CommandLine import org.eclipse.mita.base.typesystem.infra.MitaBaseResource +import org.eclipse.emf.common.notify.Adapter class CompileCommand extends AbstractCommand { @Inject @@ -91,7 +92,6 @@ class CompileCommand extends AbstractCommand { println("Loading " + libraryFile); resourceSet.getResource(URI.createURI(libraryFile.replace("\\", "/")), true); } - EcoreUtil.resolveAll(resourceSet); validateResources(resourceSet.resources.filter[ it.URI.toString.endsWith('.platform') ]); // load project files @@ -102,8 +102,10 @@ class CompileCommand extends AbstractCommand { resource.eAdapters.add(new CompileToCAdapter()); ]); - // resolve all - EcoreUtil.resolveAll(resourceSet); + // resolve all user programs + resourceSet.resources.filter[it.eAdapters.exists[adapter | adapter instanceof CompileToCAdapter]].forEach[ + EcoreUtil.resolveAll(it); + ] } protected def validateResources(Iterable resources) { diff --git a/bundles/org.eclipse.mita.cli/src/org/eclipse/mita/cli/loader/StandaloneProgramDslGenerator.xtend b/bundles/org.eclipse.mita.cli/src/org/eclipse/mita/cli/loader/StandaloneProgramDslGenerator.xtend index d8419e62..019d1ca5 100644 --- a/bundles/org.eclipse.mita.cli/src/org/eclipse/mita/cli/loader/StandaloneProgramDslGenerator.xtend +++ b/bundles/org.eclipse.mita.cli/src/org/eclipse/mita/cli/loader/StandaloneProgramDslGenerator.xtend @@ -23,9 +23,9 @@ class StandaloneProgramDslGenerator extends ProgramDslGenerator { - override protected injectPlatformDependencies(Module libraryModule) { + override protected injectPlatformDependencies(Object obj, Module libraryModule) { injector = Guice.createInjector(Modules.override(injectingModule).with(new StandaloneModule()), libraryModule); - injector.injectMembers(this); + injector.injectMembers(obj); } override getUserFiles(ResourceSet set) { diff --git a/bundles/org.eclipse.mita.library.stdlib/.classpath b/bundles/org.eclipse.mita.library.stdlib/.classpath index 213e409f..f5e1002f 100644 --- a/bundles/org.eclipse.mita.library.stdlib/.classpath +++ b/bundles/org.eclipse.mita.library.stdlib/.classpath @@ -3,6 +3,10 @@ - + + + + + diff --git a/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_iterables.mita b/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_iterables.mita index 33b4e927..24aedece 100644 --- a/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_iterables.mita +++ b/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_iterables.mita @@ -40,7 +40,9 @@ export generated type array */ export generated fn length(self : array) : uint32 generator "org.eclipse.mita.library.stdlib.ArrayGenerator$LengthGenerator"; +export generated fn capacity(self : array) : uint32 generator "org.eclipse.mita.library.stdlib.ArrayGenerator$CapacityhGenerator"; export generated fn length(self : string) : uint32 generator "org.eclipse.mita.library.stdlib.ArrayGenerator$LengthGenerator"; +export generated fn capacity(self : string) : uint32 generator "org.eclipse.mita.library.stdlib.ArrayGenerator$CapacityGenerator"; export native unchecked function __PLUS__(x: array, y: array): array header "string.h"; // @@ -49,10 +51,28 @@ export native unchecked function __PLUS__(x: array, y: array< // * // * A list is an ordered collection of elements which offers random read/write access. // */ -//type ringbuffer { -// property size : uint32 -//} -// +export generated type ringbuffer + generator "org.eclipse.mita.library.stdlib.RingbufferGenerator" + size-inferrer "org.eclipse.mita.library.stdlib.ArraySizeInferrer" + + constructor con(); + +export generated fn push(self: ringbuffer, element: T): void generator "org.eclipse.mita.library.stdlib.RingbufferGenerator$PushGenerator"; +export generated fn pop(self: ringbuffer): T + generator "org.eclipse.mita.library.stdlib.RingbufferGenerator$PopGenerator" + size-inferrer "org.eclipse.mita.library.stdlib.RingbufferGenerator$PopInferrer" +; +export generated fn peek(self: ringbuffer): T + generator "org.eclipse.mita.library.stdlib.RingbufferGenerator$PeekGenerator" + size-inferrer "org.eclipse.mita.library.stdlib.RingbufferGenerator$PopInferrer"; +export generated fn count(self: ringbuffer): uint32 generator "org.eclipse.mita.library.stdlib.RingbufferGenerator$CountGenerator"; +export generated fn empty(self: ringbuffer): bool generator "org.eclipse.mita.library.stdlib.RingbufferGenerator$EmptyGenerator"; +export generated fn full(self: ringbuffer): bool generator "org.eclipse.mita.library.stdlib.RingbufferGenerator$FullGenerator"; +export generated fn capacity(self : ringbuffer): uint32 generator "org.eclipse.mita.library.stdlib.ArrayGenerator$CapacityGenerator"; + +export native unchecked function __PLUS__(x: array, y: array): array header "string.h"; + + ///* // * # Stacks // * @@ -63,25 +83,6 @@ export native unchecked function __PLUS__(x: array, y: array< // property size : uint32 //} - -/* - * Removes all elements from the list - */ -//extern fn clear(self : ringbuffer) : void - -/* - * Adds an element to the end of the list. Returns false if the list is full. - */ -//extern fn add(self : ringbuffer) : bool - -/* - * Gets an element from the list. Throws an IndexOutOfBounds exception if the index is - * is less than zero or greater-equal than the list size. - */ -//extern fn get(self : ringbuffer, index : uint32) : T - -//extern fn newInstance(self : stack, size : static uint32) : stack - /* * Pushes a new element on top of the stack. Returns false if the stack is full and the * element was not placed on the stack. diff --git a/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_references.mita b/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_references.mita index 8a598a42..11251a95 100644 --- a/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_references.mita +++ b/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_references.mita @@ -27,5 +27,5 @@ package stdlib; */ export generated type reference generator "org.eclipse.mita.library.stdlib.ReferenceGenerator" - size-inferrer "org.eclipse.mita.library.stdlib.ReferenceSizeInferrer" + size-inferrer "org.eclipse.mita.library.stdlib.OptionalAndReferenceSizeInferrer" constructor con(t: T); diff --git a/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_types.mita b/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_types.mita index bbf1d707..6e194429 100644 --- a/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_types.mita +++ b/bundles/org.eclipse.mita.library.stdlib/lib/1.0.0/stdlib_types.mita @@ -41,7 +41,6 @@ export native unchecked function __PLUS__(x: uint16, y: uint16): uint16 header " export native unchecked function __PLUS__(x: uint8 , y: uint8 ): uint8 header "math.h"; export native unchecked function __PLUS__(x: float , y: float ): float header "math.h"; export native unchecked function __PLUS__(x: double, y: double): double header "math.h"; - export native unchecked function __PLUS__(x: string, y: string): string header "string.h"; export native unchecked function __MINUS__(x: xint32, y: xint32): int32 header "math.h"; @@ -189,7 +188,7 @@ export generated fn write(self : siginst, value : T) : void */ export generated type optional generator "org.eclipse.mita.library.stdlib.OptionalGenerator" - size-inferrer "org.eclipse.mita.library.stdlib.OptionalSizeInferrer" + size-inferrer "org.eclipse.mita.library.stdlib.OptionalAndReferenceSizeInferrer" constructor con(); /* diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArrayGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArrayGenerator.xtend index 148aad95..a468df8d 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArrayGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArrayGenerator.xtend @@ -39,15 +39,19 @@ import org.eclipse.mita.program.generator.AbstractFunctionGenerator import org.eclipse.mita.program.generator.AbstractTypeGenerator import org.eclipse.mita.program.generator.CodeFragment import org.eclipse.mita.program.generator.CodeFragmentProvider +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.GeneratorUtils import org.eclipse.mita.program.generator.StatementGenerator import org.eclipse.mita.program.generator.TypeGenerator import org.eclipse.mita.program.inferrer.StaticValueInferrer import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.xtext.generator.trace.node.IGeneratorNode import static extension org.eclipse.mita.base.types.TypeUtils.ignoreCoercions import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull +import org.eclipse.xtend2.lib.StringConcatenationClient +import org.eclipse.mita.base.expressions.Literal +import org.eclipse.mita.base.types.TypeUtils +import org.eclipse.mita.program.model.ModelUtils class ArrayGenerator extends AbstractTypeGenerator { @@ -68,23 +72,30 @@ class ArrayGenerator extends AbstractTypeGenerator { } static def getInferredSize(AbstractType type) { return type?.castOrNull(TypeConstructorType)?.typeArguments?.last?.castOrNull(LiteralTypeExpression) as LiteralTypeExpression - } + } - private def long getFixedSize(EObject stmt) { - return stmt.inferredSize?.eval ?: -1L + protected def cf(StringConcatenationClient content) { + return codeFragmentProvider.create(content); } override CodeFragment generateHeader(EObject context, AbstractType type) { if(getDataType(type) instanceof TypeVariable) { return CodeFragment.EMPTY; } - codeFragmentProvider.create(''' - typedef struct { + cf('''typedef struct «typeGenerator.code(context, type)» «typeGenerator.code(context, type)»;''') + } + + override generateTypeImplementations(EObject context, AbstractType type) { + if(getDataType(type) instanceof TypeVariable) { + return CodeFragment.EMPTY; + } + cf(''' + struct «typeGenerator.code(context, type)» { «getDataTypeCCode(context, type)»* data; uint32_t length; uint32_t capacity; - } «typeGenerator.code(context, type)»; - ''').addHeader('MitaGeneratedTypes.h', false); + }; + ''').addHeader("inttypes.h", true); } protected def boolean getIsOperationCall(EObject object) { @@ -94,41 +105,62 @@ class ArrayGenerator extends AbstractTypeGenerator { return false; } - protected def CodeFragment generateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, long size, PrimitiveValueExpression init) { + protected def CodeFragment generateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, CodeFragment size, PrimitiveValueExpression init) { return codeFragmentProvider.create(''' «getDataTypeCCode(context, arrayType)» «bufferName»[«size»]«IF init !== null» = «statementGenerator.code(init)»«ENDIF»; ''') } + override generateGlobalInitialization(AbstractType type, EObject context, CodeFragment varName, Expression initialization) { + val capacity = type.inferredSize?.eval + val occurrence = getOccurrence(context); + val bufferName = cf('''data_«varName»_«occurrence»'''); + return cf(''' + «statementGenerator.generateBulkAssignment( + context, + codeFragmentProvider.create('''«varName»_array'''), + new CodeWithContext((type as TypeConstructorType).typeArguments.get(1), Optional.empty, bufferName), + cf('''«capacity»''') + )» + ''') + } + override CodeFragment generateVariableDeclaration(AbstractType type, EObject context, CodeFragment varName, Expression initialization, boolean isTopLevel) { - val init = initialization.ignoreCoercions; val capacity = type.inferredSize?.eval // if we are top-level, we must do initialization if there is any val occurrence = getOccurrence(context); - val initValue = init?.castOrNull(PrimitiveValueExpression) - val initWithValueLiteral = initValue !== null + - val bufferName = codeFragmentProvider.create('''data_«varName»_«occurrence»'''); + val bufferName = cf('''data_«varName»_«occurrence»'''); - val cf = codeFragmentProvider.create(''' + return cf(''' «IF capacity !== null» // buffer for «varName» - «generateBufferStmt(context, type, bufferName, capacity, initValue)» + «generateBufferStmt(context, type, bufferName, cf('''«capacity»'''), null)» «ELSE» ERROR: Couldn't infer size! «ENDIF» // var «varName»: «type.toString» - «typeGenerator.code(context, type)» «varName» = { - .data = data_«varName»_«occurrence», - .length = «IF initWithValueLiteral»«getFixedSize(init)»«ELSE»0«ENDIF», + «typeGenerator.code(context, type)» «varName» = «IF !isTopLevel»(«typeGenerator.code(context, type)») «ENDIF»{ + .data = «bufferName», + .length = 0, .capacity = «capacity» }; + «statementGenerator.generateBulkAllocation( + context, + codeFragmentProvider.create('''«varName»_array'''), + new CodeWithContext((type as TypeConstructorType).typeArguments.get(1), Optional.empty, bufferName), + cf('''«capacity»'''), + isTopLevel + )» + «IF !isTopLevel» + «generateGlobalInitialization(type, context, varName, initialization)» + «ENDIF» ''').addHeader('MitaGeneratedTypes.h', false); - return cf; } - def getDataType(AbstractType type) { - (type as TypeConstructorType).typeArguments.tail.head; + def AbstractType getDataType(AbstractType t) { + (t as TypeConstructorType).typeArguments.get(1); } def CodeFragment getDataTypeCCode(EObject context, AbstractType type) { @@ -136,97 +168,107 @@ class ArrayGenerator extends AbstractTypeGenerator { } override generateTypeSpecifier(AbstractType type, EObject context) { - codeFragmentProvider.create('''array_«getDataTypeCCode(context, type)»''').addHeader('MitaGeneratedTypes.h', false); + cf('''array_«getDataTypeCCode(context, type)»''').addHeader('MitaGeneratedTypes.h', false); } - - override generateNewInstance(AbstractType type, NewInstanceExpression expr) { - // if we are not in a function we are top-level and must do nothing, since we can't modify top-level anyway - if(EcoreUtil2.getContainerOfType(expr, FunctionDefinition) === null && EcoreUtil2.getContainerOfType(expr, EventHandlerDeclaration) === null) { - return CodeFragment.EMPTY; - } - val capacity = expr.getFixedSize(); - val parent = expr.eContainer; - val occurrence = getOccurrence(parent); - val varName = generatorUtils.getBaseName(parent); - - // variable declarations create the buffer already - val generateBuffer = (EcoreUtil2.getContainerOfType(expr, VariableDeclaration) === null); - codeFragmentProvider.create(''' - «IF generateBuffer» - «typeGenerator.code(expr, (type as TypeConstructorType).typeArguments.tail.head)» data_«varName»_«occurrence»[«capacity»]; - «ENDIF» - // «varName» = new array<«typeGenerator.code(expr, type)»>(size = «capacity»); - «varName» = («typeGenerator.code(expr, type)») { - .data = data_«varName»_«occurrence», - .capacity = «capacity», - .length = 0 - }; - ''').addHeader('MitaGeneratedTypes.h', false); - } - - def generateLength(EObject obj, CodeFragment temporaryBufferName, ValueRange valRange, CodeFragment objCodeExpr) { - val objLit = obj.castOrNull(PrimitiveValueExpression); - return codeFragmentProvider.create( + def generateLength(CodeFragment temporaryBufferName, ValueRange valRange, CodeWithContext obj) { + val objLit = obj.obj.orElse(null)?.castOrNull(PrimitiveValueExpression); + val inferredSize = obj.type.inferredSize?.eval; + // array literals aren't translated to a C array object, but directly used for initialization of a buffer. + // also they are always exactly as long as their member count. + return cf( ''' - «IF objLit !== null»«getFixedSize(obj)»«ELSE»«IF valRange?.upperBound !== null»«valRange.upperBound.code.noTerminator»«ELSE»«objCodeExpr».length«ENDIF»«IF valRange?.lowerBound !== null» - «valRange.lowerBound.code.noTerminator»«ENDIF»«ENDIF» + («IF objLit !== null»«inferredSize»«ELSE»«IF valRange?.upperBound !== null»«valRange.upperBound.code.noTerminator»«ELSE»«obj.code».length«ENDIF»«IF valRange?.lowerBound !== null» - «valRange.lowerBound.code.noTerminator»«ENDIF»«ENDIF») '''); } + + // returns null if it can't generate this + dispatch def CodeFragment generateExpression(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, AssignmentOperator operator, CodeWithContext right, ArrayLiteral lit) { + if(operator != AssignmentOperator.ASSIGN) { + return null; + } + val dataType = left.type.dataType; + if(!TypeUtils.isGeneratedType(context, dataType)) { + return cf(''' + «typeGenerator.code(context, dataType)» «cVariablePrefix»_temp_«context.occurrence»[«lit.values.length»] = {«FOR v: lit.values SEPARATOR(", ")»«v.code»«ENDFOR»}; + memcpy(«left.code».data, «cVariablePrefix»_temp_«context.occurrence», sizeof(«typeGenerator.code(context, dataType)»)*«lit.values.length»); + «left.code».length = «lit.values.length»; + ''').addHeader("string.h", true) + } + else { + return cf(''' + «FOR i_v: lit.values.indexed» + «statementGenerator.initializationCode( + context, + cf('''«cVariablePrefix»_«i_v.key»'''), + new CodeWithContext(dataType, Optional.empty, cf('''«left.code».data[«i_v.key»]''')), + operator, + new CodeWithContext(dataType, Optional.of(i_v.value), cf('''«i_v.value.code»''')), + true + )» + «ENDFOR» + «left.code».length = «lit.values.length»; + ''') + } + } + dispatch def CodeFragment generateExpression(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, AssignmentOperator operator, CodeWithContext right, Literal lit) { + return null; + } + dispatch def CodeFragment generateExpression(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, AssignmentOperator operator, CodeWithContext right, Void lit) { + return null; + } + + def toCComment(CodeWithContext c) { + // TODO replace */ with something else + return c.obj.map[cf('''«ModelUtils.getOriginalSourceCode(it)»''')].orElse(c.code); + } - override generateExpression(AbstractType type, EObject context, Optional left, CodeFragment leftName, CodeFragment cVariablePrefix, AssignmentOperator operator, EObject _right) { - val right = _right.ignoreCoercions; + override generateExpression(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, AssignmentOperator operator, CodeWithContext right) { if(right === null) { - return codeFragmentProvider.create(''''''); + return cf('''''') } - val rightLit = right.castOrNull(PrimitiveValueExpression); - - val rightRef = if(right instanceof ArrayAccessExpression) { - right.owner - } else { - right + val rightLit = right.obj.orElse(null)?.castOrNull(PrimitiveValueExpression)?.value; + val literalResult = generateExpression(context, cVariablePrefix, left, operator, right, rightLit); + if(literalResult !== null) { + return literalResult; } - val isNewInstance = right instanceof NewInstanceExpression; - - val codeRightExpr = codeFragmentProvider.create('''«statementGenerator.code(rightRef).noTerminator.noNewline»'''); - val rightExprIsValueLit = rightLit !== null; + val codeRightExpr = cf('''«right.code.noTerminator.noNewline»'''); - val temporaryBufferName = codeFragmentProvider.create('''«cVariablePrefix»_temp_«context.occurrence»''') + val temporaryBufferName = cf('''«cVariablePrefix»_temp_«context.occurrence»''') - val valRange = if(right instanceof ArrayAccessExpression) { - if(right.arraySelector instanceof ValueRange) { - right.arraySelector as ValueRange; + val rightObj = right.obj.orElse(null); + val valRange = if(rightObj instanceof ArrayAccessExpression) { + if(rightObj.arraySelector instanceof ValueRange) { + rightObj.arraySelector as ValueRange; } } - val lengthLeft = codeFragmentProvider.create('''«leftName».length''') - val lengthRight = generateLength(right, temporaryBufferName, valRange, codeRightExpr); - val capacityLeft = codeFragmentProvider.create('''«leftName».capacity''') - val remainingCapacityLeft = codeFragmentProvider.create('''«IF operator == AssignmentOperator.ADD_ASSIGN»(«capacityLeft» - «lengthLeft»)«ELSE»«capacityLeft»«ENDIF»''') + val lengthLeft = cf('''«left.code».length''') + val lengthRight = generateLength(temporaryBufferName, valRange, right); + val capacityLeft = cf('''«left.code».capacity''') + val remainingCapacityLeft = cf('''«IF operator == AssignmentOperator.ADD_ASSIGN»(«capacityLeft» - «lengthLeft»)«ELSE»«capacityLeft»«ENDIF»''') val dataLeft = if(operator == AssignmentOperator.ASSIGN) { - codeFragmentProvider.create('''«leftName».data'''); + cf('''«left.code».data'''); } else if(operator == AssignmentOperator.ADD_ASSIGN) { - codeFragmentProvider.create('''&«leftName».data[«leftName».length]'''); - } - val dataRight = if(!isNewInstance && !rightExprIsValueLit) { - codeFragmentProvider.create(''' - «IF valRange?.lowerBound !== null»&«ENDIF»«codeRightExpr».data«IF valRange?.lowerBound !== null»[«valRange.lowerBound.code.noTerminator»]«ENDIF» - '''); - } else if(rightExprIsValueLit) { - temporaryBufferName; + cf('''(&«left.code».data[«left.code».length])'''); } + val dataRight = cf(''' + «IF valRange?.lowerBound !== null»&«ENDIF»«codeRightExpr».data«IF valRange?.lowerBound !== null»[«valRange.lowerBound.code.noTerminator»]«ENDIF» + '''); - val sizeResLeft = left.flatMap[Optional.ofNullable(it.inferredSize)] - val sizeResRight = Optional.ofNullable(right.inferredSize); + + val sizeResLeft = Optional.ofNullable(left.type.inferredSize?.eval); + val sizeResRight = Optional.ofNullable(right.type.inferredSize?.eval); // if we can infer the sizes we don't need to check bounds // (validation prevents out of bounds compilation for known sizes) val staticSize = sizeResLeft.present && sizeResRight.present; val capacityCheck = if(!staticSize || operator == AssignmentOperator.ADD_ASSIGN) { - codeFragmentProvider.create(''' + cf(''' // do a runtime check since we either don't know the sizes statically or we're appending if(«remainingCapacityLeft» < «lengthRight») { «generateExceptionHandler(context, "EXCEPTION_INVALIDRANGEEXCEPTION")» @@ -234,7 +276,7 @@ class ArrayGenerator extends AbstractTypeGenerator { ''') } else { - codeFragmentProvider.create() + cf('''''') } val staticAccessors = new Object(){ @@ -248,22 +290,31 @@ class ArrayGenerator extends AbstractTypeGenerator { StaticValueInferrer.infer(valRange.upperBound, [x| if(x !== null) staticAccessors.field = false]) } - val lengthModifyStmt = codeFragmentProvider.create(''' + val lengthModifyStmt = cf(''' «lengthLeft» «operator.literal» «lengthRight»«IF valRange !== null»«IF valRange.lowerBound !== null» - «valRange.lowerBound.code.noTerminator»«ENDIF»«IF valRange.upperBound !== null» - («lengthRight» - «valRange.upperBound.code.noTerminator»)«ENDIF»«ENDIF»; '''); - - val typeSize = codeFragmentProvider.create('''sizeof(«getDataTypeCCode(context, type)»)''') - codeFragmentProvider.create(''' - «IF rightExprIsValueLit» - // generate buffer to hold immediate - «generateBufferStmt(context, type, temporaryBufferName, getFixedSize(rightLit), rightLit)» - «ENDIF» + + cf(''' «capacityCheck» - // «leftName» «operator.literal» «codeRightExpr» - memcpy(«dataLeft», «dataRight», «typeSize» * «lengthRight»); + /* «left.toCComment» «operator.literal» «right.toCComment» */ + «copyContents( + context, + cf('''«cVariablePrefix»_i'''), + new CodeWithContext((left.type as TypeConstructorType).typeArguments.get(1), Optional.empty, dataLeft), + new CodeWithContext((right.type as TypeConstructorType).typeArguments.get(1), Optional.empty, dataRight), + lengthRight + )» + «lengthModifyStmt» - ''').addHeader('MitaGeneratedTypes.h', false); + ''').addHeader("string.h", true) + .addHeader('MitaGeneratedTypes.h', false); + } + + def CodeFragment copyContents(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count) { + cf(''' + «statementGenerator.generateBulkCopyStatements(context, i, left, right, count)» + ''') } static class LengthGenerator extends AbstractFunctionGenerator { @@ -273,14 +324,36 @@ class ArrayGenerator extends AbstractTypeGenerator { @Inject protected extension StatementGenerator - - override generate(ElementReferenceExpression ref, IGeneratorNode resultVariableName) { - val variable = ExpressionUtils.getArgumentValue(ref.reference as Operation, ref, 'self'); + + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val variable = ExpressionUtils.getArgumentValue(functionCall.reference as Operation, functionCall, 'self'); val varref = if(variable !== null) { variable.code; } - return codeFragmentProvider.create('''«IF resultVariableName !== null»«resultVariableName» = «ENDIF»«varref».length''').addHeader('MitaGeneratedTypes.h', false); + return codeFragmentProvider.create('''«IF resultVariable !== null»«resultVariable.code» = «ENDIF»«varref».length''').addHeader('MitaGeneratedTypes.h', false); + } + + override callShouldBeUnraveled(ElementReferenceExpression expression) { + false + } + + } + + static class CapacityGenerator extends AbstractFunctionGenerator { + + @Inject + protected CodeFragmentProvider codeFragmentProvider + + protected extension StatementGenerator + + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val variable = ExpressionUtils.getArgumentValue(functionCall.reference as Operation, functionCall, 'self'); + val varref = if(variable !== null) { + variable.code; + } + + return codeFragmentProvider.create('''«IF resultVariable !== null»«resultVariable.code» = «ENDIF»«varref».capacity''').addHeader('MitaGeneratedTypes.h', false); } override callShouldBeUnraveled(ElementReferenceExpression expression) { @@ -292,9 +365,63 @@ class ArrayGenerator extends AbstractTypeGenerator { override generateCoercion(CoercionExpression expr, AbstractType from, AbstractType to) { val inner = expr.value; if(inner instanceof ArrayLiteral) { - return codeFragmentProvider.create('''«inner.code»'''); + return cf('''«inner.code»'''); } - return codeFragmentProvider.create('''CANT COERCE «inner.eClass.name»'''); + return cf('''CANT COERCE «inner.eClass.name»'''); + } + + override generateBulkAllocation(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count, boolean isTopLevel) { + val arrayType = left.type as TypeConstructorType; + val dataType = arrayType.typeArguments.get(1); + val size = cf('''«arrayType.inferredSize?.eval»'''); + return cf(''' + «generateBufferStmt(context, arrayType, cf('''«cVariablePrefix»_buf'''), cf('''«count»*«size»'''), null)» + + «statementGenerator.generateBulkAllocation( + context, + codeFragmentProvider.create('''«cVariablePrefix»_array'''), + new CodeWithContext(dataType, Optional.empty, cf('''«cVariablePrefix»_buf''')), + cf('''«count»*«size»'''), + isTopLevel + )» + ''').addHeader("stddef.h", true) + } + + override generateBulkAssignment(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count) { + val arrayType = left.type as TypeConstructorType; + val dataType = arrayType.typeArguments.get(1); + val size = cf('''«arrayType.inferredSize?.eval»'''); + val i = cf('''«cVariablePrefix»_i'''); + return cf(''' + for(size_t «i» = 0; «i» < «count»; ++«i») { + «left.code»[«i»] = («typeGenerator.code(context, arrayType)») { + .data = &«cVariablePrefix»_buf[«i»*«size»], + .length = 0, + .capacity = «size» + }; + } + «statementGenerator.generateBulkAssignment( + context, + codeFragmentProvider.create('''«cVariablePrefix»_array'''), + new CodeWithContext(dataType, Optional.empty, cf('''«cVariablePrefix»_buf''')), + cf('''«count»*«size»''') + )» + ''') + } + + override generateBulkCopyStatements(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count) { + return cf(''' + for(size_t «i» = 0; «i» < «count»; ++«i») { + «statementGenerator.generateBulkCopyStatements( + context, + cf('''ar_«i»'''), + new CodeWithContext((left.type as TypeConstructorType).typeArguments.get(1), Optional.empty, cf('''«left.code»[«i»].data''')), + new CodeWithContext((right.type as TypeConstructorType).typeArguments.get(1), Optional.empty, cf('''«right.code»[«i»].data''')), + cf('''«right.code»[«i»].length''') + )» + «left.code»[«i»].length = «right.code»[«i»].length; + } + ''') } } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArraySizeInferrer.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArraySizeInferrer.xtend index c18e6551..cabc0389 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArraySizeInferrer.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ArraySizeInferrer.xtend @@ -31,6 +31,10 @@ import static org.eclipse.mita.program.inferrer.ProgramSizeInferrer.* import static extension org.eclipse.mita.base.types.TypeUtils.ignoreCoercions import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull +import org.eclipse.mita.base.typesystem.types.AbstractType +import org.eclipse.mita.base.typesystem.constraints.ExplicitInstanceConstraint +import org.eclipse.mita.base.typesystem.constraints.EqualityConstraint +import org.eclipse.mita.base.typesystem.types.AtomicType class ArraySizeInferrer extends GenericContainerSizeInferrer { @@ -42,6 +46,20 @@ class ArraySizeInferrer extends GenericContainerSizeInferrer { return #[2]; } + static def wrapInArray(InferenceContext c, StdlibTypeRegistry typeRegistry, AbstractType t) { + val arrayTypeObject = typeRegistry.getTypeModelObject(c.obj, StdlibTypeRegistry.arrayTypeQID); + // \T S. array + val arrayType = c.system.getTypeVariable(arrayTypeObject); + // t0 ~ array + val arrayInstance = c.system.newTypeVariable(c.obj); + // t0 instanceof \T. sigInst => creates t0 := sigInst + c.system.addConstraint(new ExplicitInstanceConstraint(arrayInstance, arrayType, new ValidationIssue('''%s is not instance of %s''', c.obj))); + // bind sigInst to t0 + c.system.addConstraint(new EqualityConstraint(arrayInstance, new TypeConstructorType(c.obj, "array", #[new AtomicType(arrayTypeObject, "array") -> Variance.INVARIANT, t -> Variance.INVARIANT, c.system.newTypeVariable(null) -> Variance.COVARIANT]), new ValidationIssue('''%s is not instance of %s''', c.obj))) + // return t0 ~ sigInst + return arrayInstance; + } + dispatch def void doCreateConstraints(InferenceContext c, ArrayLiteral lit, TypeConstructorType t) { val innerDataType = c.system.newTypeVariable(lit); val oldDataType = t.typeArguments.get(1) @@ -61,15 +79,15 @@ class ArraySizeInferrer extends GenericContainerSizeInferrer { } dispatch def void doCreateConstraints(InferenceContext c, ArrayAccessExpression expr, TypeConstructorType type) { - val arraySelector = expr.arraySelector.ignoreCoercions?.castOrNull(ValueRange); - if(arraySelector !== null) { + val arraySelectorRange = expr.arraySelector.ignoreCoercions?.castOrNull(ValueRange); + if(arraySelectorRange !== null) { val u32 = typeRegistry.getTypeModelObject(expr, StdlibTypeRegistry.u32TypeQID); val u32Type = c.system.getTypeVariable(u32); val ownerSize = typeVariableToTypeConstructorType(c, c.system.getTypeVariable(expr.owner), type).typeArguments.last; - val lowerBound = new LiteralNumberType(arraySelector.lowerBound, -1 * (StaticValueInferrer.infer(arraySelector.lowerBound, [])?.castOrNull(Long) ?: 0L), u32Type); - val upperBoundInferred = StaticValueInferrer.infer(arraySelector.upperBound, [])?.castOrNull(Long); + val lowerBound = new LiteralNumberType(arraySelectorRange.lowerBound, -1 * (StaticValueInferrer.infer(arraySelectorRange.lowerBound, [])?.castOrNull(Long) ?: 0L), u32Type); + val upperBoundInferred = StaticValueInferrer.infer(arraySelectorRange.upperBound, [])?.castOrNull(Long); val upperBound = if(upperBoundInferred !== null) { - new LiteralNumberType(arraySelector.upperBound, upperBoundInferred, u32Type); + new LiteralNumberType(arraySelectorRange.upperBound, upperBoundInferred, u32Type); } else { ownerSize @@ -77,6 +95,9 @@ class ArraySizeInferrer extends GenericContainerSizeInferrer { val exprSizeType = typeVariableToTypeConstructorType(c, c.system.getTypeVariable(expr), type).typeArguments.last as TypeVariable; c.system.addConstraint(new SumConstraint(exprSizeType, #[upperBound, lowerBound], new ValidationIssue('''''', expr))); } + else { + wrapInArray(c, typeRegistry, type); + } c.system.associate(type, expr); } diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericContainerSizeInferrer.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericContainerSizeInferrer.xtend index 61e49539..6ec16ec1 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericContainerSizeInferrer.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/GenericContainerSizeInferrer.xtend @@ -55,6 +55,12 @@ import org.eclipse.mita.program.NewInstanceExpression import org.eclipse.mita.base.typesystem.types.LiteralTypeExpression import org.eclipse.mita.base.types.Parameter import org.eclipse.mita.program.ReturnParameterReference +import org.eclipse.mita.program.SystemEventSource +import org.eclipse.mita.base.expressions.ArrayAccessExpression +import org.eclipse.mita.program.EventHandlerVariableDeclaration +import org.eclipse.mita.program.DereferenceExpression +import org.eclipse.mita.base.expressions.Argument +import org.eclipse.mita.base.types.GeneratedElement /** * Automatic unbinding of size types and recursion of data types. @@ -126,6 +132,11 @@ abstract class GenericContainerSizeInferrer implements TypeSizeInferrer { return doUnbindSize(r, system, obj, type); } + dispatch def Pair> doUnbindSize(Resource r, ConstraintSystem system, SystemEventSource obj, AbstractType type) { + val basicResult = doUnbindSize(r, system, null, type); + return basicResult.key -> (basicResult.value + #[obj.source as EObject] + obj.source.eAllContents.toIterable); + } + dispatch def Pair> doUnbindSize(Resource r, ConstraintSystem system, TypeReferenceSpecifier typeSpecifier, TypeConstructorType type) { return setTypeArguments(type, [i, t| @@ -212,6 +223,10 @@ abstract class GenericContainerSizeInferrer implements TypeSizeInferrer { } } + dispatch def void doCreateConstraints(InferenceContext c, EventHandlerVariableDeclaration variable, AbstractType t) { + inferUnmodifiedFrom(c.system, variable, EcoreUtil2.getContainerOfType(variable, EventHandlerDeclaration).event); + } + dispatch def void doCreateConstraints(InferenceContext c, TypeReferenceSpecifier obj, TypeConstructorType t) { // recurse on sizes val newType = setTypeArguments(t, [i, t1| @@ -486,13 +501,17 @@ abstract class GenericContainerSizeInferrer implements TypeSizeInferrer { } // can be overriden to explicitly enable/disable validation for certain eobjects - def alwaysValid(EObject origin) { + def boolean alwaysValid(EObject origin) { // function parameters normally don't need their size inferred, // since they are allocated from outside. // copying them will create issues at the place where they are copied. if(EcoreUtil2.getContainerOfType(origin, Parameter) !== null) { return true; } + // TODO is this bad? I think for generated elements all bets are off anyway. + if(EcoreUtil2.getContainerOfType(origin, GeneratedElement) !== null) { + return true; + } // references don't need to validate, since their reference already validates --> less errors for user // except for function calls and return statements if(origin instanceof ElementReferenceExpression) { @@ -503,6 +522,17 @@ abstract class GenericContainerSizeInferrer implements TypeSizeInferrer { return true; } } + // same goes for array access expression + if(origin instanceof ArrayAccessExpression) { + return true; + } + // and for dereference + if(origin instanceof DereferenceExpression) { + return true; + } + if(origin instanceof Argument) { + return origin.value.alwaysValid; + } return false; } @@ -533,7 +563,7 @@ abstract class GenericContainerSizeInferrer implements TypeSizeInferrer { else { return #[]; } - ] + ].force } else { return #[]; diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/OptionalAndReferenceSizeInferrer.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/OptionalAndReferenceSizeInferrer.xtend new file mode 100644 index 00000000..eb0cfc02 --- /dev/null +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/OptionalAndReferenceSizeInferrer.xtend @@ -0,0 +1,142 @@ +/******************************************************************************** + * Copyright (c) 2017, 2018 Bosch Connected Devices and Solutions GmbH. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * Contributors: + * Bosch Connected Devices and Solutions GmbH - initial contribution + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +package org.eclipse.mita.library.stdlib + +import org.eclipse.emf.common.notify.impl.AdapterImpl +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.mita.base.types.Operation +import org.eclipse.mita.base.types.TypeReferenceSpecifier +import org.eclipse.mita.base.typesystem.infra.InferenceContext +import org.eclipse.mita.base.typesystem.solver.ConstraintSystem +import org.eclipse.mita.base.typesystem.types.AbstractType +import org.eclipse.mita.base.typesystem.types.TypeConstructorType +import org.eclipse.mita.program.ReturnParameterDeclaration +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor +import org.eclipse.mita.base.types.PresentTypeSpecifier +import org.eclipse.mita.program.DereferenceExpression + +class OptionalAndReferenceSizeInferrer extends GenericContainerSizeInferrer { + + override getDataTypeIndexes() { + return #[1]; + } + + override getSizeTypeIndexes() { + return #[]; + } + + def getInnerSpecifier(TypeReferenceSpecifier specifier, TypeConstructorType type) { + if(type.name == "optional" && specifier.optional) { + return specifier; + } + else if(type.name == "reference" && specifier.hasReferenceModifierLeft) { + specifier.useReferenceModifier; + return specifier; + } + + return specifier.typeArguments.get(0); + } + + def void undoSideEffects(TypeReferenceSpecifier specifier, PresentTypeSpecifier innerSpecifier, TypeConstructorType type) { + if(specifier === innerSpecifier && type.name == "reference") { + specifier.clearUsageOfReferenceModifier; + } + } + + dispatch override Pair> doUnbindSize(Resource r, ConstraintSystem system, TypeReferenceSpecifier typeSpecifier, TypeConstructorType type) { + val innerSpecifier = typeSpecifier.getInnerSpecifier(type); + return setTypeArguments(type, + [i, t| + delegate.unbindSize(r, system, innerSpecifier, t) + ], + [i, t| system.newTypeVariable(t.origin) as AbstractType -> #[innerSpecifier] + innerSpecifier.eAllContents.toIterable], + [t_objs | t_objs.key], + [t, objs| t -> objs.flatMap[it.value]] + ) => [ + typeSpecifier.undoSideEffects(innerSpecifier, type); + ]; + } + + dispatch override void doCreateConstraints(InferenceContext c, TypeReferenceSpecifier obj, TypeConstructorType t) { + if(t.name == "optional" && obj.optional) { + val innerSpecifier = obj.getInnerSpecifier(t); + val modelType = innerSpecifier; + val innerContext = new InferenceContext(c, modelType, c.system.getTypeVariable(modelType), t.typeArguments.get(1)); + delegate.createConstraints(innerContext); + obj.undoSideEffects(innerSpecifier, t); + } + else if(t.name == "reference" && obj.hasReferenceModifierLeft) { + val innerSpecifier = obj.getInnerSpecifier(t); + val modelType = innerSpecifier; + val innerContext = new InferenceContext(c, modelType, c.system.getTypeVariable(modelType), t.typeArguments.get(1)); + delegate.createConstraints(innerContext); + obj.undoSideEffects(innerSpecifier, t); + } + else { + val innerSpecifier = obj.getInnerSpecifier(t); + val newType = setTypeArguments(t, [i, t1| + val modelType = innerSpecifier; + val innerContext = new InferenceContext(c, modelType, c.system.getTypeVariable(modelType), t1); + delegate.createConstraints(innerContext); + val result = c.system.newTypeVariable(t1.origin) as AbstractType + c.system.associate(result, modelType) + result; + ], [i, t1| + // no size arguments in optionals + t1; + ], [it], [t1, xs | t1]) + c.system.associate(newType, obj); + obj.undoSideEffects(innerSpecifier, t); + } + + } + + dispatch def Pair> doUnbindSize(Resource r, ConstraintSystem system, ReturnParameterDeclaration variable, TypeConstructorType type) { + val superResult = _doUnbindSize(r, system, variable as EObject, type); + + return superResult.key -> #[ + EcoreUtil2.getContainerOfType(variable, Operation) as EObject + ] + } + + static def getReferenceModifiersUsedAdapter(TypeReferenceSpecifier ts) { + return ts.eAdapters.filter(ReferenceModifiersUsedAdapter).head ?: { + val adapter = new ReferenceModifiersUsedAdapter(ts.referenceModifiers.map[it.length].fold(0, [a, b | a+b])); + ts.eAdapters.add(adapter); + adapter; + } + } + static def boolean hasReferenceModifierLeft(TypeReferenceSpecifier ts) { + val a = ts.referenceModifiersUsedAdapter; + return a.used < a.count; + } + static def void useReferenceModifier(TypeReferenceSpecifier ts) { + val a = ts.referenceModifiersUsedAdapter; + a.used++; + } + static def void clearUsageOfReferenceModifier(TypeReferenceSpecifier ts) { + val a = ts.referenceModifiersUsedAdapter; + a.used--; + } + + @Accessors + @FinalFieldsConstructor + static class ReferenceModifiersUsedAdapter extends AdapterImpl { + protected var int used = 0; + protected val int count; + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/OptionalGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/OptionalGenerator.xtend index 959664f2..618a5970 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/OptionalGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/OptionalGenerator.xtend @@ -17,22 +17,21 @@ import com.google.inject.Inject import java.util.Optional import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.expressions.AssignmentOperator -import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.base.types.CoercionExpression import org.eclipse.mita.base.types.Expression import org.eclipse.mita.base.types.GeneratedType -import org.eclipse.mita.base.types.Operation import org.eclipse.mita.base.typesystem.types.AbstractType import org.eclipse.mita.base.typesystem.types.TypeConstructorType -import org.eclipse.mita.program.GeneratedFunctionDefinition -import org.eclipse.mita.program.NewInstanceExpression +import org.eclipse.mita.base.typesystem.types.TypeVariable import org.eclipse.mita.program.ProgramBlock import org.eclipse.mita.program.generator.AbstractTypeGenerator import org.eclipse.mita.program.generator.CodeFragment +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.GeneratorUtils import org.eclipse.mita.program.generator.StatementGenerator import org.eclipse.mita.program.generator.internal.GeneratorRegistry import org.eclipse.xtext.EcoreUtil2 +import java.util.Optional import org.eclipse.mita.base.typesystem.types.TypeVariable class OptionalGenerator extends AbstractTypeGenerator { @@ -48,15 +47,11 @@ class OptionalGenerator extends AbstractTypeGenerator { public static final String ENUM_NAME = "enumOptional"; static enum enumOptional { - Some, None + None, Some } public static final String OPTIONAL_FLAG_MEMBER = "flag"; public static final String OPTIONAL_DATA_MEMBER = "data"; - - override generateNewInstance(AbstractType type, NewInstanceExpression expr) { - CodeFragment.EMPTY; - } - + override generateTypeSpecifier(AbstractType type, EObject context) { codeFragmentProvider.create('''optional_«typeGenerator.code(context, (type as TypeConstructorType).typeArguments.tail.head)»''').addHeader('MitaGeneratedTypes.h', false); } @@ -65,28 +60,13 @@ class OptionalGenerator extends AbstractTypeGenerator { codeFragmentProvider.create('''«typeGenerator.code(context, type)» «varName»;''') } - override generateExpression(AbstractType type, EObject context, Optional left, CodeFragment leftName, CodeFragment cVariablePrefix, AssignmentOperator operator, EObject right) { + override generateExpression(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, AssignmentOperator operator, CodeWithContext right) { if(operator != AssignmentOperator.ASSIGN) { return codeFragmentProvider.create('''ERROR: Unsuported operator: «operator.literal»''') } val haveInit = right !== null; - - val initIsEref = haveInit && right instanceof ElementReferenceExpression; - val initAsEref = if(initIsEref) { - right as ElementReferenceExpression; - } - val initIsOperation = initIsEref && initAsEref.reference instanceof Operation - val initAsOperation = if(initIsOperation) { - initAsEref.reference as Operation; - } - - val initIsGeneratedFunction = initAsOperation instanceof GeneratedFunctionDefinition; - val initAsGeneratedFunction = if(initIsGeneratedFunction) { - initAsOperation as GeneratedFunctionDefinition; - } - - val valueExpressionTypeAnnotation = codeFragmentProvider.create('''(«generateTypeSpecifier(type, context)») '''); + val valueExpressionTypeAnnotation = codeFragmentProvider.create('''(«generateTypeSpecifier(left.type, context)») '''); val validInit = if(right !== null) { codeFragmentProvider.create('''«right.code»'''); @@ -98,16 +78,15 @@ class OptionalGenerator extends AbstractTypeGenerator { }''') } - val initValueIsNone = right === null || (initIsGeneratedFunction && initAsGeneratedFunction.name == "none"); + val initValueIsNone = right === null// || (initIsGeneratedFunction && initAsGeneratedFunction.name == "none"); - val firstTypeArgType = (type as TypeConstructorType).typeArguments.tail.head; + val firstTypeArgType = (left.type as TypeConstructorType).typeArguments.tail.head; val firstTypeArgOrigin = firstTypeArgType.origin; - // if we assigned for example a: int32? = 1, right has integer, left has optional. so we check if left.args.head ~ right. Also we short-circuit none and some and supply a default value. - val initWithImmediate = initIsGeneratedFunction - || right === null - || (!(firstTypeArgOrigin instanceof GeneratedType)); + // Supply a default value and upcast immediates. + val initWithImmediate = right === null + || (!(firstTypeArgOrigin instanceof GeneratedType)); val init = if(initWithImmediate) { @@ -136,7 +115,7 @@ class OptionalGenerator extends AbstractTypeGenerator { } } - codeFragmentProvider.create('''«leftName» = «init.noNewline»''') + return codeFragmentProvider.create('''«left.code» = «init.noNewline»''') } override CodeFragment generateHeader() { @@ -173,5 +152,16 @@ class OptionalGenerator extends AbstractTypeGenerator { '''); } + override generateBulkCopyStatements(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override generateBulkAllocation(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count, boolean isTopLevel) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override generateBulkAssignment(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/OptionalSizeInferrer.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/OptionalSizeInferrer.xtend deleted file mode 100644 index 42558576..00000000 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/OptionalSizeInferrer.xtend +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2017, 2018 Bosch Connected Devices and Solutions GmbH. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * Contributors: - * Bosch Connected Devices and Solutions GmbH - initial contribution - * - * SPDX-License-Identifier: EPL-2.0 - ********************************************************************************/ - -package org.eclipse.mita.library.stdlib - -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.mita.base.types.TypeReferenceSpecifier -import org.eclipse.mita.base.typesystem.solver.ConstraintSystem -import org.eclipse.mita.base.typesystem.types.AbstractType -import org.eclipse.mita.base.typesystem.types.TypeConstructorType - -class OptionalSizeInferrer extends GenericContainerSizeInferrer { - - override getDataTypeIndexes() { - return #[1]; - } - - override getSizeTypeIndexes() { - return #[]; - } - - dispatch override Pair> doUnbindSize(Resource r, ConstraintSystem system, TypeReferenceSpecifier typeSpecifier, TypeConstructorType type) { - return setTypeArguments(type, - [i, t| - delegate.unbindSize(r, system, if(typeSpecifier.typeArguments.size > i) {typeSpecifier.typeArguments.get(i - 1)}, t) - ], - [i, t| system.newTypeVariable(t.origin) as AbstractType -> #[typeSpecifier.typeArguments.get(i - 1)] + typeSpecifier.typeArguments.get(i - 1).eAllContents.toIterable], - [t_objs | t_objs.key], - [t, objs| t -> objs.flatMap[it.value]] - ); - } -} \ No newline at end of file diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ReferenceGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ReferenceGenerator.xtend index ecd58d4c..4d2b46eb 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ReferenceGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ReferenceGenerator.xtend @@ -23,6 +23,7 @@ import org.eclipse.mita.base.typesystem.types.TypeConstructorType import org.eclipse.mita.program.NewInstanceExpression import org.eclipse.mita.program.generator.AbstractTypeGenerator import org.eclipse.mita.program.generator.CodeFragment +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.GeneratorUtils import org.eclipse.mita.program.generator.StatementGenerator @@ -33,11 +34,7 @@ class ReferenceGenerator extends AbstractTypeGenerator { @Inject protected extension GeneratorUtils - - override generateNewInstance(AbstractType type, NewInstanceExpression expr) { - CodeFragment.EMPTY; - } - + override generateTypeSpecifier(AbstractType type, EObject context) { if(type instanceof TypeConstructorType) { val realType = type.typeArguments.tail.head; @@ -54,9 +51,21 @@ class ReferenceGenerator extends AbstractTypeGenerator { override generateVariableDeclaration(AbstractType type, EObject context, CodeFragment varName, Expression initialization, boolean isTopLevel) { codeFragmentProvider.create('''«typeGenerator.code(context, type)» «varName»«IF initialization !== null» = «initialization.code»«ENDIF»;''') } - override generateExpression(AbstractType type, EObject context, Optional left, CodeFragment leftName, CodeFragment cVariablePrefix, AssignmentOperator operator, EObject right) { - codeFragmentProvider.create('''«leftName» «operator.literal» «right.code»;''') + override generateExpression(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, AssignmentOperator operator, CodeWithContext right) { + codeFragmentProvider.create('''«left.code» «operator.literal» «right.code»;''') } + override generateBulkCopyStatements(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override generateBulkAllocation(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count, boolean isTopLevel) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override generateBulkAssignment(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ReferenceSizeInferrer.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ReferenceSizeInferrer.xtend deleted file mode 100644 index 86c56c38..00000000 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/ReferenceSizeInferrer.xtend +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2017, 2018 Bosch Connected Devices and Solutions GmbH. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0. - * - * Contributors: - * Bosch Connected Devices and Solutions GmbH - initial contribution - * - * SPDX-License-Identifier: EPL-2.0 - ********************************************************************************/ - -package org.eclipse.mita.library.stdlib - -import org.eclipse.emf.ecore.EObject -import org.eclipse.emf.ecore.resource.Resource -import org.eclipse.mita.base.types.TypeReferenceSpecifier -import org.eclipse.mita.base.typesystem.infra.InferenceContext -import org.eclipse.mita.base.typesystem.solver.ConstraintSystem -import org.eclipse.mita.base.typesystem.types.AbstractType -import org.eclipse.mita.base.typesystem.types.TypeConstructorType -import org.eclipse.mita.program.DereferenceExpression -import org.eclipse.mita.program.ReferenceExpression -import org.eclipse.mita.program.ReturnParameterDeclaration -import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.mita.base.types.Operation - -class ReferenceSizeInferrer extends GenericContainerSizeInferrer { - - override getDataTypeIndexes() { - return #[1]; - } - - override getSizeTypeIndexes() { - return #[]; - } - - dispatch override Pair> doUnbindSize(Resource r, ConstraintSystem system, TypeReferenceSpecifier typeSpecifier, TypeConstructorType type) { - return setTypeArguments(type, - [i, t| - delegate.unbindSize(r, system, if(typeSpecifier.typeArguments.size > i) {typeSpecifier.typeArguments.get(i - 1)}, t) - ], - [i, t| system.newTypeVariable(t.origin) as AbstractType -> #[typeSpecifier.typeArguments.get(i - 1)] + typeSpecifier.typeArguments.get(i - 1).eAllContents.toIterable], - [t_objs | t_objs.key], - [t, objs| t -> objs.flatMap[it.value]] - ); - } - - dispatch def Pair> doUnbindSize(Resource r, ConstraintSystem system, ReturnParameterDeclaration variable, TypeConstructorType type) { - val superResult = _doUnbindSize(r, system, variable as EObject, type); - - return superResult.key -> #[ - EcoreUtil2.getContainerOfType(variable, Operation) as EObject - ] - } -} \ No newline at end of file diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/RingbufferGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/RingbufferGenerator.xtend new file mode 100644 index 00000000..3b0166ff --- /dev/null +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/RingbufferGenerator.xtend @@ -0,0 +1,363 @@ +package org.eclipse.mita.library.stdlib + +import com.google.inject.Inject +import java.util.Optional +import org.eclipse.emf.ecore.EObject +import org.eclipse.mita.base.expressions.AssignmentOperator +import org.eclipse.mita.base.expressions.ElementReferenceExpression +import org.eclipse.mita.base.expressions.util.ExpressionUtils +import org.eclipse.mita.base.types.Expression +import org.eclipse.mita.base.types.Operation +import org.eclipse.mita.base.types.Variance +import org.eclipse.mita.base.types.validation.IValidationIssueAcceptor.ValidationIssue +import org.eclipse.mita.base.typesystem.StdlibTypeRegistry +import org.eclipse.mita.base.typesystem.constraints.EqualityConstraint +import org.eclipse.mita.base.typesystem.constraints.ExplicitInstanceConstraint +import org.eclipse.mita.base.typesystem.infra.FunctionSizeInferrer +import org.eclipse.mita.base.typesystem.infra.InferenceContext +import org.eclipse.mita.base.typesystem.infra.TypeSizeInferrer +import org.eclipse.mita.base.typesystem.types.AbstractType +import org.eclipse.mita.base.typesystem.types.AtomicType +import org.eclipse.mita.base.typesystem.types.TypeConstructorType +import org.eclipse.mita.program.EventHandlerDeclaration +import org.eclipse.mita.program.FunctionDefinition +import org.eclipse.mita.program.NewInstanceExpression +import org.eclipse.mita.program.generator.AbstractFunctionGenerator +import org.eclipse.mita.program.generator.AbstractTypeGenerator +import org.eclipse.mita.program.generator.CodeFragment +import org.eclipse.mita.program.generator.CodeWithContext +import org.eclipse.mita.program.generator.GeneratorUtils +import org.eclipse.mita.program.generator.StatementGenerator +import org.eclipse.mita.program.generator.internal.GeneratorRegistry +import org.eclipse.xtend.lib.annotations.Accessors +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.generator.trace.node.IGeneratorNode + +import static extension org.eclipse.mita.library.stdlib.ArrayGenerator.getInferredSize +import org.eclipse.mita.base.types.TypeConstructor +import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.base.typesystem.types.TypeVariable + +// https://www.snellman.net/blog/archive/2016-12-13-ring-buffers/ +class RingbufferGenerator extends AbstractTypeGenerator { + @Inject + extension GeneratorUtils + + @Inject + protected StatementGenerator statementGenerator; + + static def TypeConstructorType wrapInRingbuffer(StdlibTypeRegistry typeRegistry, EObject context, AbstractType innerType) { + val ringbufferObj = typeRegistry.getTypeModelObject(context, StdlibTypeRegistry.ringbufferTypeQID); + val ringbufferTypeInstance = new TypeConstructorType(context, "ringbuffer", #[new AtomicType(ringbufferObj, "ringbuffer") -> Variance.INVARIANT, innerType -> Variance.INVARIANT, new TypeVariable(null, 0) -> Variance.COVARIANT]) + return ringbufferTypeInstance; + } + + + override CodeFragment generateHeader(EObject context, AbstractType type) { + codeFragmentProvider.create('''typedef struct «typeGenerator.code(context, type)» «typeGenerator.code(context, type)»;''') + } + + override generateTypeImplementations(EObject context, AbstractType type) { + if(type instanceof TypeConstructorType) { + codeFragmentProvider.create(''' + struct «typeGenerator.code(context, type)» { + «typeGenerator.code(context, type.typeArguments.tail.head)»* data; + uint32_t read; + uint32_t length; + uint32_t capacity; + }; + ''').addHeader('inttypes.h', true); + } + } + + override generateHeader() { + return codeFragmentProvider.create(''' + uint32_t ringbuffer_mask(uint32_t i, uint32_t len); + uint32_t ringbuffer_increment(uint32_t i, uint32_t len); + ''') + } + + override generateImplementation() { + return codeFragmentProvider.create(''' + //assumes that you won't be overflowing by more than len + uint32_t ringbuffer_mask(uint32_t i, uint32_t len) { + if(i >= len) { + return i - len; + } + return i; + } + + uint32_t ringbuffer_increment(uint32_t i, uint32_t len) { + return ringbuffer_mask(i + 1, len); + } + ''') + } + + override generateTypeSpecifier(AbstractType type, EObject context) { + if(type instanceof TypeConstructorType) { + codeFragmentProvider.create('''ringbuffer_«typeGenerator.code(context, type.typeArguments.tail.head)»''').addHeader('MitaGeneratedTypes.h', false); + } + } + + override generateGlobalInitialization(AbstractType type, EObject context, CodeFragment varName, Expression initialization) { + if(type instanceof TypeConstructorType) { + val occurrence = getOccurrence(context); + val bufferName = codeFragmentProvider.create('''data_«varName»_«occurrence»''') + val size = codeFragmentProvider.create('''«type.inferredSize?.eval»'''); + val dataType = type.typeArguments.get(1); + + return codeFragmentProvider.create(''' + «statementGenerator.generateBulkAssignment( + context, + codeFragmentProvider.create('''«varName»_rb'''), + new CodeWithContext(dataType, Optional.empty, bufferName), + size + )» + ''') + } + } + + override generateVariableDeclaration(AbstractType type, EObject context, CodeFragment varName, Expression initialization, boolean isTopLevel) { + if(type instanceof TypeConstructorType) { + val occurrence = getOccurrence(context); + val bufferName = codeFragmentProvider.create('''data_«varName»_«occurrence»''') + val size = codeFragmentProvider.create('''«type.inferredSize?.eval»'''); + val dataType = type.typeArguments.get(1); + + return codeFragmentProvider.create(''' + «typeGenerator.code(context, type.typeArguments.tail.head)» «bufferName»[«size»]; + «typeGenerator.code(context, type)» «varName» = «IF !isTopLevel»(«typeGenerator.code(context, type)») «ENDIF»{ + .data = «bufferName», + .read = 0, + .length = 0, + .capacity = «size» + }; + «statementGenerator.generateBulkAllocation( + context, + codeFragmentProvider.create('''«varName»_rb'''), + new CodeWithContext(dataType, Optional.empty, bufferName), + size, + isTopLevel + )» + «IF !isTopLevel» + «generateGlobalInitialization(type, context, varName, initialization)» + «ENDIF» + ''') + } + } + + override generateBulkAllocation(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count, boolean isTopLevel) { + val type = left.type as TypeConstructorType; + val dataType = type.typeArguments.get(1); + val size = codeFragmentProvider.create('''«type.inferredSize?.eval»'''); + return codeFragmentProvider.create(''' + «typeGenerator.code(context, type.typeArguments.tail.head)» «cVariablePrefix»_buf[«count»*«size»]; + «statementGenerator.generateBulkAllocation( + context, + codeFragmentProvider.create('''«cVariablePrefix»_array'''), + new CodeWithContext(dataType, Optional.empty, codeFragmentProvider.create('''«cVariablePrefix»_buf''')), + codeFragmentProvider.create('''«count»*«size»'''), + isTopLevel + )»''').addHeader("stddef.h", true) + } + + override generateBulkAssignment(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count) { + val type = left.type as TypeConstructorType; + val dataType = type.typeArguments.get(1); + val i = codeFragmentProvider.create('''«cVariablePrefix»_i'''); + val size = codeFragmentProvider.create('''«type.inferredSize?.eval»'''); + return codeFragmentProvider.create(''' + for(size_t «i» = 0; «i» < «count»; ++«i») { + «left.code»[«i»] = («typeGenerator.code(context, type)») { + .data = &«cVariablePrefix»_buf[«i»*«size»], + .length = 0, + .capacity = «size» + }; + } + «statementGenerator.generateBulkAssignment( + context, + codeFragmentProvider.create('''«cVariablePrefix»_array'''), + new CodeWithContext(dataType, Optional.empty, codeFragmentProvider.create('''«cVariablePrefix»_buf''')), + codeFragmentProvider.create('''«count»*«size»''') + )»''').addHeader("stddef.h", true) + } + + override generateBulkCopyStatements(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + static class PushGenerator extends AbstractFunctionGenerator { + @Inject + protected extension StatementGenerator; + @Inject + extension GeneratorUtils + + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val rbRef = ExpressionUtils.getArgumentValue(functionCall.reference as Operation, functionCall, "self"); + val value = ExpressionUtils.getArgumentValue(functionCall.reference as Operation, functionCall, "element").code; + return generate(functionCall, new CodeWithContext(BaseUtils.getType(rbRef), Optional.empty, codeFragmentProvider.create('''«rbRef.code»''')), value); + } + + def generate(EObject context, CodeWithContext rbRef, IGeneratorNode value) { + val innerType = (rbRef.type as TypeConstructorType).typeArguments.get(1) + return codeFragmentProvider.create(''' + if(«rbRef.code».length >= «rbRef.code».capacity) { + «generateExceptionHandler(context, "EXCEPTION_INDEXOUTOFBOUNDSEXCEPTION")» + } + «statementGenerator.initializationCode( + context, + codeFragmentProvider.create(''''''), + new CodeWithContext( + innerType, + Optional.empty, + codeFragmentProvider.create('''«rbRef.code».data[ringbuffer_mask(«rbRef.code».read + «rbRef.code».length, «rbRef.code».capacity)]''')), + AssignmentOperator.ASSIGN, + new CodeWithContext( + innerType, + Optional.empty, + codeFragmentProvider.create('''«value»''') + ), + true + )» + «rbRef.code».length++; + ''').addHeader("MitaGeneratedTypes.h", false); + } + } + static class PopGenerator extends AbstractFunctionGenerator { + @Inject + protected extension StatementGenerator statementGenerator; + @Inject + extension GeneratorUtils + + @Inject + protected GeneratorRegistry registry + + + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val rbRef = functionCall.arguments.head.value; + val rbRefCode = rbRef.code; + val innerType = resultVariable?.type; + + return codeFragmentProvider.create(''' + if(«rbRefCode».length == 0) { + «generateExceptionHandler(functionCall, "EXCEPTION_INDEXOUTOFBOUNDSEXCEPTION")» + } + --«rbRefCode».length; + «IF resultVariable !== null» +««« copy data + «statementGenerator.initializationCode( + functionCall, + resultVariable.code, + resultVariable, + AssignmentOperator.ASSIGN, + new CodeWithContext(innerType, Optional.empty, codeFragmentProvider.create('''«rbRefCode».data[«rbRefCode».read]''')), + true + )» + «ENDIF» + «rbRefCode».read = ringbuffer_increment(«rbRefCode».read, «rbRefCode».capacity); + ''').addHeader("MitaGeneratedTypes.h", false); + } + } + static class PopInferrer implements FunctionSizeInferrer { + + static def wrapInRingbuffer(InferenceContext c, StdlibTypeRegistry typeRegistry, AbstractType t) { + val ringbufferTypeObject = typeRegistry.getTypeModelObject(c.obj, StdlibTypeRegistry.ringbufferTypeQID); + // \T S. ringbuffer + val ringbufferType = c.system.getTypeVariable(ringbufferTypeObject); + // t0 ~ ringbuffer + val ringbufferInstance = c.system.newTypeVariable(c.obj); + // t0 instanceof \T S. ringbuffer => creates t0 := ringbuffer + c.system.addConstraint(new ExplicitInstanceConstraint(ringbufferInstance, ringbufferType, new ValidationIssue('''%s is not instance of %s''', c.obj))); + // bind sigInst to t0 + c.system.addConstraint(new EqualityConstraint(ringbufferInstance, new TypeConstructorType(c.obj, "ringbuffer", #[new AtomicType(ringbufferTypeObject, "ringbuffer") -> Variance.INVARIANT, t -> Variance.INVARIANT, c.system.newTypeVariable(null) -> Variance.COVARIANT]), new ValidationIssue('''%s is not instance of %s''', c.obj))) + // return t0 ~ sigInst + return ringbufferInstance; + } + + @Accessors + TypeSizeInferrer delegate; + + @Inject + StdlibTypeRegistry typeRegistry; + + override createConstraints(InferenceContext c) { + val funCall = c.obj; + if(funCall instanceof ElementReferenceExpression) { + if(funCall.arguments.size > 0) { + val innerType = c.type; + c.system.associate(innerType, c.obj); + val rbType = wrapInRingbuffer(c, typeRegistry, innerType); + val argument = funCall.arguments.head.value; + c.system.associate(rbType, argument); + } + } + } + + } + static class PeekGenerator extends AbstractFunctionGenerator { + @Inject + protected extension StatementGenerator statementGenerator; + @Inject + extension GeneratorUtils + + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val rbRef = functionCall.arguments.head.code; + val innerType = resultVariable?.type; + return codeFragmentProvider.create(''' + if(«rbRef».length == 0) { + «generateExceptionHandler(functionCall, "EXCEPTION_INDEXOUTOFBOUNDSEXCEPTION")» + } + «IF resultVariable !== null» + «statementGenerator.initializationCode( + functionCall, + resultVariable?.code, + resultVariable, + AssignmentOperator.ASSIGN, + new CodeWithContext(innerType, Optional.empty, codeFragmentProvider.create('''«rbRef».data[«rbRef».read]''')), + true + )» + «ENDIF» + ''').addHeader("MitaGeneratedTypes.h", false); + } + } + static class CountGenerator extends AbstractFunctionGenerator { + @Inject + protected extension StatementGenerator statementGenerator; + + // no need to recurse, empty has type uint32 + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val rbRef = functionCall.arguments.head.code; + return codeFragmentProvider.create(''' + «IF resultVariable !== null»«resultVariable.code» = «ENDIF»«rbRef».length; + ''').addHeader("MitaGeneratedTypes.h", false); + } + } + static class EmptyGenerator extends AbstractFunctionGenerator { + @Inject + protected extension StatementGenerator statementGenerator; + + // no need to recurse, empty has type bool + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val rbRef = functionCall.arguments.head.code; + return codeFragmentProvider.create(''' + «IF resultVariable !== null»«resultVariable.code» = «ENDIF»«rbRef».length == 0; + ''').addHeader("MitaGeneratedTypes.h", false); + } + } + static class FullGenerator extends AbstractFunctionGenerator { + @Inject + protected extension StatementGenerator statementGenerator; + + // no need to recurse, empty has type bool + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val rbRef = functionCall.arguments.head.code; + return codeFragmentProvider.create(''' + «IF resultVariable !== null»«resultVariable.code» = «ENDIF»«rbRef».length == «rbRef».capacity; + ''').addHeader("MitaGeneratedTypes.h", false); + } + } +} + + + + diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/StringGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/StringGenerator.xtend index f89c7910..031e8895 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/StringGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/StringGenerator.xtend @@ -16,6 +16,7 @@ package org.eclipse.mita.library.stdlib import com.google.inject.Inject import java.util.LinkedList import org.eclipse.emf.ecore.EObject +import org.eclipse.mita.base.expressions.AssignmentOperator import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.base.expressions.Literal import org.eclipse.mita.base.expressions.PrimitiveValueExpression @@ -25,12 +26,14 @@ import org.eclipse.mita.base.expressions.util.ExpressionUtils import org.eclipse.mita.base.types.Expression import org.eclipse.mita.base.types.InterpolatedStringLiteral import org.eclipse.mita.base.types.Operation +import org.eclipse.mita.base.typesystem.infra.TypeSizeInferrer import org.eclipse.mita.base.typesystem.types.AbstractType import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.program.VariableDeclaration import org.eclipse.mita.program.generator.AbstractFunctionGenerator import org.eclipse.mita.program.generator.CodeFragment import org.eclipse.mita.program.generator.CodeFragmentProvider +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.ProgramDslTraceExtensions import org.eclipse.mita.program.generator.transformation.EscapeWhitespaceInStringStage import org.eclipse.mita.program.model.ModelUtils @@ -39,48 +42,97 @@ import org.eclipse.xtext.generator.trace.node.IGeneratorNode import org.eclipse.xtext.generator.trace.node.NewLineNode import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull +import org.eclipse.mita.base.typesystem.types.TypeConstructorType import org.eclipse.mita.base.typesystem.infra.TypeSizeInferrer - +import java.util.Optional class StringGenerator extends ArrayGenerator { @Inject protected extension ProgramDslTraceExtensions - override CodeFragment generateLength(EObject obj, CodeFragment temporaryBufferName, ValueRange valRange, CodeFragment objCodeExpr) { - return codeFragmentProvider.create('''«doGenerateLength(obj, temporaryBufferName, valRange, objCodeExpr).noNewline»'''); + override generateBulkCopyStatements(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count) { + return cf(''' + for(size_t «i» = 0; «i» < «count»; ++«i») { + memcpy(«left.code»[«i»].data, «right.code»[«i»].data, sizeof(char) * «right.code»[«i»].length); + «left.code»[«i»].length = «right.code»[«i»].length; + } + ''') } - dispatch def CodeFragment doGenerateLength(PrimitiveValueExpression expr, CodeFragment temporaryBufferName, ValueRange valRange, CodeFragment objCodeExpr) { - return doGenerateLength(expr, temporaryBufferName, valRange, objCodeExpr, expr.value); + override CodeFragment copyContents(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count) { + return cf(''' + memcpy(«left.code», «right.code», sizeof(char) * «count»); + ''') } - dispatch def CodeFragment doGenerateLength(PrimitiveValueExpression expr, CodeFragment temporaryBufferName, ValueRange valRange, CodeFragment objCodeExpr, InterpolatedStringLiteral l) { + + dispatch def CodeFragment generateExpression(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, AssignmentOperator operator, CodeWithContext right, StringLiteral lit) { + if(operator != AssignmentOperator.ASSIGN) { + return null; + } + val charBuffer = cf('''«cVariablePrefix»_temp_«context.occurrence»'''); + return cf(''' + char «charBuffer»[«lit.value.length»] = "«lit.value»"; + memcpy(«left.code».data, «charBuffer», sizeof(char)*«lit.value.length»); + «left.code».length = «lit.value.length»; + ''').addHeader("string.h", true) + } + + dispatch def CodeFragment generateExpression(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, AssignmentOperator operator, CodeWithContext right, InterpolatedStringLiteral lit) { + if(operator != AssignmentOperator.ASSIGN) { + return null; + } + val bufferName = cf('''«cVariablePrefix»_temp_«context.occurrence»'''); + val size = left.type.inferredSize?.eval + // need to allocate size+1 since snprintf always writes a zero byte at the end. + return cf(''' + «getDataTypeCCode(context, left.type)» «bufferName»[«size + 1»] = {0}; + int «bufferName»_written = snprintf(«bufferName», sizeof(«bufferName»), "«lit.pattern»"«FOR x : lit.content BEFORE ', ' SEPARATOR ', '»«x.getDataHandleForPrintf»«ENDFOR»); + if(«bufferName»_written > «size») { + «generateExceptionHandler(context, "EXCEPTION_STRINGFORMATEXCEPTION")» + } + memcpy(«left.code».data, «bufferName», sizeof(char)*«bufferName»_written); + «left.code».length = «bufferName»_written; + ''').addHeader("string.h", true) + } + + override CodeFragment generateLength(CodeFragment temporaryBufferName, ValueRange valRange, CodeWithContext obj) { + return codeFragmentProvider.create('''«doGenerateLength(temporaryBufferName, valRange, obj, obj.obj.orElse(null)).noNewline»'''); + } + + dispatch def CodeFragment doGenerateLength(CodeFragment temporaryBufferName, ValueRange valRange, CodeWithContext obj, PrimitiveValueExpression expr) { + return doGenerateLength(temporaryBufferName, valRange, obj, expr, expr.value); + } + dispatch def CodeFragment doGenerateLength(CodeFragment temporaryBufferName, ValueRange valRange, CodeWithContext obj, PrimitiveValueExpression expr, InterpolatedStringLiteral l) { return codeFragmentProvider.create(''' «temporaryBufferName»_written '''); } - dispatch def CodeFragment doGenerateLength(PrimitiveValueExpression expr, CodeFragment temporaryBufferName, ValueRange valRange, CodeFragment objCodeExpr, Literal l) { - return super.generateLength(expr, temporaryBufferName, valRange, objCodeExpr); + dispatch def CodeFragment doGenerateLength(CodeFragment temporaryBufferName, ValueRange valRange, CodeWithContext obj, PrimitiveValueExpression expr, Literal l) { + return super.generateLength(temporaryBufferName, valRange, obj); } - dispatch def CodeFragment doGenerateLength(PrimitiveValueExpression expr, CodeFragment temporaryBufferName, ValueRange valRange, CodeFragment objCodeExpr, Object l) { - return super.generateLength(expr, temporaryBufferName, valRange, objCodeExpr); + dispatch def CodeFragment doGenerateLength(CodeFragment temporaryBufferName, ValueRange valRange, CodeWithContext obj, PrimitiveValueExpression expr, Object l) { + return super.generateLength(temporaryBufferName, valRange, obj); } - dispatch def CodeFragment doGenerateLength(PrimitiveValueExpression expr, CodeFragment temporaryBufferName, ValueRange valRange, CodeFragment objCodeExpr, Void l) { - return super.generateLength(expr, temporaryBufferName, valRange, objCodeExpr); + dispatch def CodeFragment doGenerateLength(CodeFragment temporaryBufferName, ValueRange valRange, CodeWithContext obj, PrimitiveValueExpression expr, Void l) { + return super.generateLength(temporaryBufferName, valRange, obj); } - dispatch def CodeFragment doGenerateLength(EObject expr, CodeFragment temporaryBufferName, ValueRange valRange, CodeFragment objCodeExpr) { - return super.generateLength(expr, temporaryBufferName, valRange, objCodeExpr); + dispatch def CodeFragment doGenerateLength(CodeFragment temporaryBufferName, ValueRange valRange, CodeWithContext obj, EObject expr) { + return super.generateLength(temporaryBufferName, valRange, obj); + } + dispatch def CodeFragment doGenerateLength(CodeFragment temporaryBufferName, ValueRange valRange, CodeWithContext obj, Void expr) { + return super.generateLength(temporaryBufferName, valRange, obj); } - override CodeFragment generateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, long size, PrimitiveValueExpression init) { + override CodeFragment generateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, CodeFragment size, PrimitiveValueExpression init) { val value = init?.value; return doGenerateBufferStmt(context, arrayType, bufferName, size, init, value); } - dispatch def CodeFragment doGenerateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, long size, PrimitiveValueExpression init, InterpolatedStringLiteral l) { - // need to allocate size+1 since snprintf always writes a zero byte at the end. + dispatch def CodeFragment doGenerateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, CodeFragment size, PrimitiveValueExpression init, InterpolatedStringLiteral l) { codeFragmentProvider.create(''' - «getDataTypeCCode(context, arrayType)» «bufferName»[«size + 1»] = {0}; + // need to allocate size+1 since snprintf always writes a zero byte at the end. + «getDataTypeCCode(context, arrayType)» «bufferName»[«size» + 1] = {0}; int «bufferName»_written = snprintf(«bufferName», sizeof(«bufferName»), "«l.pattern»"«FOR x : l.content BEFORE ', ' SEPARATOR ', '»«x.getDataHandleForPrintf»«ENDFOR»); if(«bufferName»_written > «size») { «generateExceptionHandler(context, "EXCEPTION_STRINGFORMATEXCEPTION")» @@ -90,17 +142,17 @@ class StringGenerator extends ArrayGenerator { .addHeader('inttypes.h', true) } - dispatch def CodeFragment doGenerateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, long size, PrimitiveValueExpression init, StringLiteral l) { + dispatch def CodeFragment doGenerateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, CodeFragment size, PrimitiveValueExpression init, StringLiteral l) { return super.generateBufferStmt(context, arrayType, bufferName, size, init); } - dispatch def CodeFragment doGenerateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, long size, PrimitiveValueExpression init, Object l) { + dispatch def CodeFragment doGenerateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, CodeFragment size, PrimitiveValueExpression init, Object l) { return super.generateBufferStmt(context, arrayType, bufferName, size, init); } - dispatch def CodeFragment doGenerateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, long size, PrimitiveValueExpression init, Void l) { + dispatch def CodeFragment doGenerateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, CodeFragment size, PrimitiveValueExpression init, Void l) { return super.generateBufferStmt(context, arrayType, bufferName, size, init); } - dispatch def CodeFragment doGenerateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, long size, PrimitiveValueExpression init, Literal l) { + dispatch def CodeFragment doGenerateBufferStmt(EObject context, AbstractType arrayType, CodeFragment bufferName, CodeFragment size, PrimitiveValueExpression init, Literal l) { return codeFragmentProvider.create('''UNKNOWN LITERAL: «l.eClass»''') } @@ -219,8 +271,8 @@ class StringGenerator extends ArrayGenerator { @Inject protected TypeSizeInferrer sizeInferrer - override generate(ElementReferenceExpression ref, IGeneratorNode resultVariableName) { - val variable = ExpressionUtils.getArgumentValue(ref.reference as Operation, ref, 'self'); + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val variable = ExpressionUtils.getArgumentValue(functionCall.reference as Operation, functionCall, 'self'); val varref = if(variable instanceof ElementReferenceExpression) { val varref = variable.reference; if(varref instanceof VariableDeclaration) { @@ -228,7 +280,7 @@ class StringGenerator extends ArrayGenerator { } } - return codeFragmentProvider.create('''«IF resultVariableName !== null»«resultVariableName» = «ENDIF»«varref».length'''); + return codeFragmentProvider.create('''«IF resultVariable !== null»«resultVariable.code» = «ENDIF»«varref».length'''); } } diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/VirtualTypeGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/VirtualTypeGenerator.xtend index 47162b74..877baabe 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/VirtualTypeGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/VirtualTypeGenerator.xtend @@ -13,11 +13,17 @@ package org.eclipse.mita.library.stdlib +import org.eclipse.mita.program.NewInstanceExpression import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.expressions.AssignmentOperator +import org.eclipse.mita.base.types.TypeSpecifier +import org.eclipse.mita.program.NewInstanceExpression +import org.eclipse.mita.program.generator.AbstractTypeGenerator +import org.eclipse.mita.program.generator.CodeFragment import org.eclipse.mita.base.typesystem.types.AbstractType import org.eclipse.mita.program.NewInstanceExpression import org.eclipse.mita.program.generator.AbstractTypeGenerator +import org.eclipse.mita.program.generator.CodeWithContext class VirtualTypeGenerator extends AbstractTypeGenerator { @@ -25,8 +31,16 @@ class VirtualTypeGenerator extends AbstractTypeGenerator { return codeFragmentProvider.create('''VIRTUAL_TYPE_BREAKS_CODE'''); } - override generateNewInstance(AbstractType type, NewInstanceExpression expr) { - return codeFragmentProvider.create(''''''); + override generateBulkCopyStatements(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count) { + return codeFragmentProvider.create('''VIRTUAL_TYPE_BREAKS_CODE'''); + } + + override generateBulkAllocation(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count, boolean isTopLevel) { + return codeFragmentProvider.create('''VIRTUAL_TYPE_BREAKS_CODE'''); + } + + override generateBulkAssignment(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count) { + return codeFragmentProvider.create('''VIRTUAL_TYPE_BREAKS_CODE'''); } } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/VirtualTypeSizeInferrer.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/VirtualTypeSizeInferrer.xtend index a3b17af6..5be1916b 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/VirtualTypeSizeInferrer.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/VirtualTypeSizeInferrer.xtend @@ -25,6 +25,8 @@ import org.eclipse.mita.base.expressions.ElementReferenceExpression import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull; import org.eclipse.mita.program.SignalInstance import org.eclipse.mita.base.typesystem.infra.InferenceContext +import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.platform.Signal class VirtualTypeSizeInferrer extends GenericContainerSizeInferrer { // implements inference for modality and siginst @@ -40,8 +42,8 @@ class VirtualTypeSizeInferrer extends GenericContainerSizeInferrer { val superResult = super._doUnbindSize(r, system, obj, type); if(type.name == "siginst") { val sigInst = obj.reference?.castOrNull(SignalInstance); - - return superResult.key -> (superResult.value + #[sigInst]); + val obsAndTypes = (#[sigInst] + sigInst.eAllContents.toIterable).map[it -> system.getTypeVariable(it)] + return superResult.key -> (superResult.value + #[sigInst] + sigInst.eAllContents.toIterable); } return superResult; diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/LogGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/LogGenerator.xtend index 1fd7eb5d..c71b50f7 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/LogGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/LogGenerator.xtend @@ -15,17 +15,17 @@ package org.eclipse.mita.library.stdlib.functions import com.google.inject.Inject import org.eclipse.mita.base.expressions.ElementReferenceExpression +import org.eclipse.mita.base.expressions.PrimitiveValueExpression import org.eclipse.mita.base.types.InterpolatedStringLiteral import org.eclipse.mita.base.types.NamedElement import org.eclipse.mita.library.stdlib.StringGenerator import org.eclipse.mita.program.generator.AbstractFunctionGenerator +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.IPlatformLoggingGenerator import org.eclipse.mita.program.generator.IPlatformLoggingGenerator.LogLevel import org.eclipse.mita.program.inferrer.StaticValueInferrer -import org.eclipse.xtext.generator.trace.node.IGeneratorNode -import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull; -import org.eclipse.mita.base.expressions.PrimitiveValueExpression +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull class LogGenerator extends AbstractFunctionGenerator { @@ -36,8 +36,8 @@ class LogGenerator extends AbstractFunctionGenerator { protected IPlatformLoggingGenerator loggingGenerator - override generate(ElementReferenceExpression function, IGeneratorNode resultVariableName) { - val functionName = (function.reference as NamedElement).name; + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val functionName = (functionCall.reference as NamedElement).name; val level = switch(functionName) { case "logDebug": LogLevel.Debug case "logInfo": LogLevel.Info @@ -45,11 +45,17 @@ class LogGenerator extends AbstractFunctionGenerator { case "logError": LogLevel.Error } - val firstArg = function.arguments.head?.value; +// val firstArg = functionCall.arguments.head?.value; +// val result = if(firstArg instanceof InterpolatedStringExpression) { +// val pattern = stringGenerator.getPattern(firstArg); +// val args = firstArg.content.map[ codeFragmentProvider.create('''«generate(it)»''') ] + + val firstArg = functionCall.arguments.head?.value; val interpolatedStringLiteral = firstArg.castOrNull(PrimitiveValueExpression)?.value?.castOrNull(InterpolatedStringLiteral) val result = if(interpolatedStringLiteral !== null) { val pattern = stringGenerator.getPattern(interpolatedStringLiteral); val args = interpolatedStringLiteral.content.map[ codeFragmentProvider.create('''«generate(it)»''') ] + loggingGenerator.generateLogStatement(level, pattern, args); } else { val pattern = StaticValueInferrer.infer(firstArg, []); diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/ModalityReadGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/ModalityReadGenerator.xtend index 57d2b273..290a7ef2 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/ModalityReadGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/ModalityReadGenerator.xtend @@ -17,8 +17,8 @@ import com.google.inject.Inject import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.program.generator.AbstractFunctionGenerator import org.eclipse.mita.program.generator.CodeFragment +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.StatementGenerator -import org.eclipse.xtext.generator.trace.node.IGeneratorNode class ModalityReadGenerator extends AbstractFunctionGenerator { @@ -29,11 +29,11 @@ class ModalityReadGenerator extends AbstractFunctionGenerator { return false; } - override generate(ElementReferenceExpression functionCall, IGeneratorNode resultVariableName) { - if(resultVariableName === null) { + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + if(resultVariable === null) { CodeFragment.EMPTY } else { - codeFragmentProvider.create('''«resultVariableName» = «statementGenerator.code(functionCall.arguments.get(0).value)»;'''); + codeFragmentProvider.create('''«resultVariable.code» = «statementGenerator.code(functionCall.arguments.get(0).value)»;'''); } } diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsHasValueGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsHasValueGenerator.xtend index 9b667efc..2d57a7b4 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsHasValueGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsHasValueGenerator.xtend @@ -17,8 +17,8 @@ import com.google.inject.Inject import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.library.stdlib.OptionalGenerator.enumOptional import org.eclipse.mita.program.generator.AbstractFunctionGenerator +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.StatementGenerator -import org.eclipse.xtext.generator.trace.node.IGeneratorNode class OptionalsHasValueGenerator extends AbstractFunctionGenerator { @@ -26,11 +26,11 @@ class OptionalsHasValueGenerator extends AbstractFunctionGenerator { @Inject protected extension StatementGenerator statementGenerator - override generate(ElementReferenceExpression functionCall, IGeneratorNode resultVariableName) { + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { val args = functionCall.arguments; val optVarOrExpr = args.head.value; - codeFragmentProvider.create('''«IF resultVariableName !== null»«resultVariableName» = «ENDIF»«optVarOrExpr.code».flag == «enumOptional.Some.name»;''').addHeader('MitaGeneratedTypes.h', false); + codeFragmentProvider.create('''«IF resultVariable !== null»«resultVariable.code» = «ENDIF»«optVarOrExpr.code».flag == «enumOptional.Some.name»;''').addHeader('MitaGeneratedTypes.h', false); } diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsNoneGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsNoneGenerator.xtend index 3e87f9e1..b80f65b7 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsNoneGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsNoneGenerator.xtend @@ -15,17 +15,16 @@ package org.eclipse.mita.library.stdlib.functions import com.google.inject.Inject import org.eclipse.mita.base.expressions.ElementReferenceExpression -import org.eclipse.mita.base.types.GeneratedType import org.eclipse.mita.base.typesystem.types.TypeConstructorType import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.library.stdlib.OptionalGenerator import org.eclipse.mita.library.stdlib.OptionalGenerator.enumOptional import org.eclipse.mita.program.generator.AbstractFunctionGenerator +import org.eclipse.mita.program.generator.AbstractTypeGenerator import org.eclipse.mita.program.generator.CodeFragment +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.StatementGenerator import org.eclipse.mita.program.generator.internal.GeneratorRegistry -import org.eclipse.xtext.generator.trace.node.IGeneratorNode -import org.eclipse.mita.program.generator.AbstractTypeGenerator class OptionalsNoneGenerator extends AbstractFunctionGenerator { @@ -35,22 +34,21 @@ class OptionalsNoneGenerator extends AbstractFunctionGenerator { @Inject protected GeneratorRegistry registry - override generate(ElementReferenceExpression functionCall, IGeneratorNode resultVariableName) { + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { // need the optionalGenerator val funType = BaseUtils.getType(functionCall); - val funTypeOrigin = funType.origin; if(!(funType instanceof TypeConstructorType)) { return CodeFragment.EMPTY; } val optGen = registry.getGenerator(functionCall.eResource, funType) as AbstractTypeGenerator; codeFragmentProvider.create(''' - «IF resultVariableName === null» + «IF resultVariable === null» («optGen?.generateTypeSpecifier(funType, functionCall)») { .«OptionalGenerator.OPTIONAL_FLAG_MEMBER» = «enumOptional.None.name» } «ELSE» - «resultVariableName».«OptionalGenerator.OPTIONAL_FLAG_MEMBER» = «enumOptional.None.name»; + «resultVariable.code».«OptionalGenerator.OPTIONAL_FLAG_MEMBER» = «enumOptional.None.name»; «ENDIF» ''').addHeader('MitaGeneratedTypes.h', false); } diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsSomeGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsSomeGenerator.xtend index 74a4c846..bc98a162 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsSomeGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsSomeGenerator.xtend @@ -15,18 +15,18 @@ package org.eclipse.mita.library.stdlib.functions import com.google.inject.Inject import org.eclipse.mita.base.expressions.ElementReferenceExpression -import org.eclipse.mita.base.types.GeneratedType import org.eclipse.mita.base.typesystem.types.TypeConstructorType import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.library.stdlib.OptionalGenerator import org.eclipse.mita.library.stdlib.OptionalGenerator.enumOptional import org.eclipse.mita.program.generator.AbstractFunctionGenerator +import org.eclipse.mita.program.generator.AbstractTypeGenerator import org.eclipse.mita.program.generator.CodeFragment +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.StatementGenerator import org.eclipse.mita.program.generator.internal.GeneratorRegistry -import org.eclipse.xtext.generator.trace.node.IGeneratorNode + import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull -import org.eclipse.mita.program.generator.AbstractTypeGenerator class OptionalsSomeGenerator extends AbstractFunctionGenerator { @@ -36,26 +36,27 @@ class OptionalsSomeGenerator extends AbstractFunctionGenerator { @Inject protected GeneratorRegistry registry - override generate(ElementReferenceExpression functionCall, IGeneratorNode resultVariableName) { + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { val args = functionCall.arguments; val valueVarOrExpr = args.head.value; // need the optionalGenerator val funType = BaseUtils.getType(functionCall); if(!(funType instanceof TypeConstructorType)) { + return CodeFragment.EMPTY; } val optGen = registry.getGenerator(functionCall.eResource, funType).castOrNull(AbstractTypeGenerator); codeFragmentProvider.create(''' - «IF resultVariableName === null» + «IF resultVariable === null» («optGen?.generateTypeSpecifier(funType, functionCall)») { .«OptionalGenerator.OPTIONAL_FLAG_MEMBER» = «enumOptional.Some.name», .«OptionalGenerator.OPTIONAL_DATA_MEMBER» = «valueVarOrExpr.code» } «ELSE» - «resultVariableName».«OptionalGenerator.OPTIONAL_FLAG_MEMBER» = «enumOptional.Some.name»; - «resultVariableName».«OptionalGenerator.OPTIONAL_DATA_MEMBER» = «valueVarOrExpr.code»; + «resultVariable.code».«OptionalGenerator.OPTIONAL_FLAG_MEMBER» = «enumOptional.Some.name»; + «resultVariable.code».«OptionalGenerator.OPTIONAL_DATA_MEMBER» = «valueVarOrExpr.code»; «ENDIF» ''').addHeader('MitaGeneratedTypes.h', false); } diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsValueGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsValueGenerator.xtend index aa5f85cf..31d877a2 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsValueGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/OptionalsValueGenerator.xtend @@ -17,16 +17,16 @@ import com.google.inject.Inject import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.library.stdlib.OptionalGenerator import org.eclipse.mita.program.generator.AbstractFunctionGenerator +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.StatementGenerator import org.eclipse.mita.program.model.ModelUtils -import org.eclipse.xtext.generator.trace.node.IGeneratorNode class OptionalsValueGenerator extends AbstractFunctionGenerator { @Inject protected extension StatementGenerator statementGenerator - override generate(ElementReferenceExpression functionCall, IGeneratorNode resultVariableName) { + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { val args = functionCall.arguments; val optVarOrExpr = args.head.value; @@ -39,7 +39,7 @@ class OptionalsValueGenerator extends AbstractFunctionGenerator { return EXCEPTION_NOVALUEEXCEPTION; «ENDIF» } - «IF resultVariableName !== null»«resultVariableName» = «ENDIF»«optVarOrExpr.code».«OptionalGenerator.OPTIONAL_DATA_MEMBER»; + «IF resultVariable !== null»«resultVariable.code» = «ENDIF»«optVarOrExpr.code».«OptionalGenerator.OPTIONAL_DATA_MEMBER»; ''').addHeader('MitaGeneratedTypes.h', false); } diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/PrintGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/PrintGenerator.xtend index 4955bd66..8650d0f3 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/PrintGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/PrintGenerator.xtend @@ -20,26 +20,33 @@ import org.eclipse.mita.base.types.InterpolatedStringLiteral import org.eclipse.mita.base.types.NamedElement import org.eclipse.mita.library.stdlib.StringGenerator import org.eclipse.mita.program.generator.AbstractFunctionGenerator -import org.eclipse.xtext.generator.trace.node.IGeneratorNode +import org.eclipse.mita.program.generator.CodeWithContext -import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull; +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull class PrintGenerator extends AbstractFunctionGenerator { @Inject protected StringGenerator stringGenerator - override generate(ElementReferenceExpression function, IGeneratorNode resultVariableName) { - val functionName = (function.reference as NamedElement).name; + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val functionName = (functionCall.reference as NamedElement).name; val addBreaklinePostfix = functionName == 'println'; - val firstArg = function.arguments.head?.value; +// val firstArg = ref.arguments.head?.value; +// val result = if(firstArg instanceof InterpolatedStringExpression) { +// codeFragmentProvider.create('''printf("«stringGenerator.getPattern(firstArg)»«IF addBreaklinePostfix»\n«ENDIF»"«IF !firstArg.content.empty», «FOR arg : firstArg.content SEPARATOR ', '»«generate(arg)»«ENDFOR»«ENDIF»);''') +// .addHeader('inttypes.h', true); +// } else { +// codeFragmentProvider.create('''printf("%s«IF addBreaklinePostfix»\n«ENDIF»", «ref.arguments.head.generate»); + + val firstArg = functionCall.arguments.head?.value; val interpolatedStringLiteral = firstArg.castOrNull(PrimitiveValueExpression)?.value?.castOrNull(InterpolatedStringLiteral) val result = if(interpolatedStringLiteral !== null) { codeFragmentProvider.create('''printf("«stringGenerator.getPattern(interpolatedStringLiteral)»«IF addBreaklinePostfix»\n«ENDIF»"«IF !interpolatedStringLiteral.content.empty», «FOR arg : interpolatedStringLiteral.content SEPARATOR ', '»«stringGenerator.getDataHandleForPrintf(arg)»«ENDFOR»«ENDIF»);''') .addHeader('inttypes.h', true); } else { - val expr = function.arguments.head.value; + val expr = functionCall.arguments.head.value; codeFragmentProvider.create('''printf("«stringGenerator.getPattern(expr)»«IF addBreaklinePostfix»\n«ENDIF»", «stringGenerator.getDataHandleForPrintf(expr)»); '''); } diff --git a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/SignalInstanceReadWriteGenerator.xtend b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/SignalInstanceReadWriteGenerator.xtend index 5bc0b81c..d55d3937 100644 --- a/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/SignalInstanceReadWriteGenerator.xtend +++ b/bundles/org.eclipse.mita.library.stdlib/src/org/eclipse/mita/library/stdlib/functions/SignalInstanceReadWriteGenerator.xtend @@ -22,9 +22,10 @@ import org.eclipse.mita.base.typesystem.types.TypeConstructorType import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.program.SignalInstance import org.eclipse.mita.program.generator.AbstractFunctionGenerator +import org.eclipse.mita.program.generator.CodeWithContext import org.eclipse.mita.program.generator.GeneratorUtils import org.eclipse.mita.program.generator.TypeGenerator -import org.eclipse.xtext.generator.trace.node.IGeneratorNode +import java.util.Optional import java.util.Optional class SignalInstanceReadWriteGenerator extends AbstractFunctionGenerator { @@ -35,7 +36,10 @@ class SignalInstanceReadWriteGenerator extends AbstractFunctionGenerator { @Inject protected TypeGenerator typeGenerator - override generate(ElementReferenceExpression functionCall, IGeneratorNode resultVariableName) { + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val resultVariableCode = resultVariable?.code ?: codeFragmentProvider.create(''' + «functionCall.uniqueIdentifier» + ''') val firstArg = functionCall.arguments.get(0)?.value; val siginst = if(firstArg instanceof ElementReferenceExpression && (firstArg as ElementReferenceExpression).reference instanceof SignalInstance) { (firstArg as ElementReferenceExpression).reference as SignalInstance; @@ -48,7 +52,10 @@ class SignalInstanceReadWriteGenerator extends AbstractFunctionGenerator { return codeFragmentProvider.create('''#error No signal instance found in this siginst write call. This should not happen!''') } else if(functionName == 'read') { return codeFragmentProvider.create(''' - exception = «siginst.readAccessName»(&«resultVariableName»); + «IF resultVariable === null»««« generate a temporary variable + «typeGenerator.code(functionCall, BaseUtils.getType(functionCall))» «resultVariableCode»; + «ENDIF» + exception = «siginst.readAccessName»(&«resultVariableCode»); «generateExceptionHandler(functionCall, 'exception')» ''') .addHeader(siginst.eContainer.fileBasename + '.h', false) @@ -56,7 +63,6 @@ class SignalInstanceReadWriteGenerator extends AbstractFunctionGenerator { val value = functionCall.arguments.get(1).value; val variableName = codeFragmentProvider.create('''_new«firstArg.uniqueIdentifier.toFirstUpper»'''); - val siginstType = BaseUtils.getType(siginst).sigInstTypeArg; val valueType = BaseUtils.getType(value); return codeFragmentProvider.create(''' diff --git a/bundles/org.eclipse.mita.platform.ui/src/org/eclipse/mita/platform/ui/labeling/PlatformDSLLabelProvider.xtend b/bundles/org.eclipse.mita.platform.ui/src/org/eclipse/mita/platform/ui/labeling/PlatformDSLLabelProvider.xtend index 30d1b076..335b6219 100644 --- a/bundles/org.eclipse.mita.platform.ui/src/org/eclipse/mita/platform/ui/labeling/PlatformDSLLabelProvider.xtend +++ b/bundles/org.eclipse.mita.platform.ui/src/org/eclipse/mita/platform/ui/labeling/PlatformDSLLabelProvider.xtend @@ -26,6 +26,7 @@ import org.eclipse.mita.base.types.EnumerationType import org.eclipse.mita.base.types.Enumerator import org.eclipse.mita.base.types.Event import org.eclipse.mita.base.types.ExceptionTypeDeclaration +import org.eclipse.mita.base.types.SystemResourceEvent import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.platform.Bus import org.eclipse.mita.platform.ConfigurationItem @@ -33,9 +34,7 @@ import org.eclipse.mita.platform.Connectivity import org.eclipse.mita.platform.Modality import org.eclipse.mita.platform.Sensor import org.eclipse.mita.platform.Signal -import org.eclipse.mita.platform.SignalEvent import org.eclipse.mita.platform.SystemResourceAlias -import org.eclipse.mita.platform.SystemResourceEvent import org.eclipse.xtext.ui.label.DefaultEObjectLabelProvider /** @@ -107,10 +106,6 @@ class PlatformDSLLabelProvider extends DefaultEObjectLabelProvider { '''event «ele.name»''' } - def text(SignalEvent ele) { - '''signal event «ele.name»''' - } - def text(Modality ele) { val type = BaseUtils.getType(ele); '''modality «ele.name» : «type»''' diff --git a/bundles/org.eclipse.mita.platform/META-INF/MANIFEST.MF b/bundles/org.eclipse.mita.platform/META-INF/MANIFEST.MF index 2815b0db..7ea02e42 100644 --- a/bundles/org.eclipse.mita.platform/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.mita.platform/META-INF/MANIFEST.MF @@ -23,7 +23,8 @@ Require-Bundle: org.eclipse.xtext, org.eclipse.xtend.lib, org.eclipse.emf.ecore.xcore, org.eclipse.emf.mwe2.launch;resolution:=optional, - org.eclipse.jdt.core + org.eclipse.jdt.core, + org.eclipse.xtext.ui Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Export-Package: org.eclipse.mita.platform, org.eclipse.mita.platform.generator, diff --git a/bundles/org.eclipse.mita.platform/model/platforms.xcore b/bundles/org.eclipse.mita.platform/model/platforms.xcore index e7432a62..b7693189 100644 --- a/bundles/org.eclipse.mita.platform/model/platforms.xcore +++ b/bundles/org.eclipse.mita.platform/model/platforms.xcore @@ -17,11 +17,12 @@ package org.eclipse.mita.platform import org.eclipse.mita.base.types.GeneratedElement import org.eclipse.mita.base.types.PackageAssociation import org.eclipse.mita.base.types.Expression -import org.eclipse.mita.base.types.Event +import org.eclipse.mita.base.types.SystemResourceEvent import org.eclipse.mita.base.types.Operation import org.eclipse.mita.base.types.Property import org.eclipse.mita.base.types.ParameterWithDefaultValue import org.eclipse.mita.base.types.Type +import org.eclipse.mita.base.types.PackageMember enum Instantiability { /** @@ -45,13 +46,17 @@ enum Instantiability { Many } +interface HasEvents extends PackageMember { + op SystemResourceEvent[] getEvents() +} + class SystemSpecification extends PackageAssociation { contains AbstractSystemResource[] resources } class SignalParameter extends ParameterWithDefaultValue { } // DO NOT SWAP the order of inheritance here as a bug in Xcore will cause the DSL generation to fail with an NPE -abstract class AbstractSystemResource extends Type, GeneratedElement { +abstract class AbstractSystemResource extends Type, GeneratedElement, HasEvents { Instantiability instantiable contains ConfigurationItem[] configurationItems @@ -74,16 +79,7 @@ class ConfigurationItem extends Property { } class Signal extends Operation { - contains SignalEvent[] events opposite signal } - - -class SystemResourceEvent extends Event { -} -class SignalEvent extends Event { - container Signal signal opposite events -} - class Modality extends Property { } diff --git a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/GeneratePlatformDSL.mwe2 b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/GeneratePlatformDSL.mwe2 index 8ab79365..2c4547cc 100644 --- a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/GeneratePlatformDSL.mwe2 +++ b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/GeneratePlatformDSL.mwe2 @@ -29,6 +29,9 @@ Workflow { name = "org.eclipse.mita.platform.PlatformDSL" fileExtensions = "platform" + parserGenerator = { + debugGrammar = true + } serializer = { generateStub = false } diff --git a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSL.xtext b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSL.xtext index b3da0999..aa886236 100644 --- a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSL.xtext +++ b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSL.xtext @@ -42,10 +42,6 @@ PlatformSpecification returns platform::Platform: )* '}' ; -SystemResourceEvent returns platform::SystemResourceEvent: - 'event' name=ID typeSpecifier=NullTypeSpecifier -; - SystemResourceAlias returns platform::SystemResourceAlias: 'alias' name=ID typeKind=TypeKind 'for' delegate=[platform::AbstractSystemResource] ; diff --git a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSLRuntimeModule.xtend b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSLRuntimeModule.xtend index 6e019935..08b9862b 100644 --- a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSLRuntimeModule.xtend +++ b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/PlatformDSLRuntimeModule.xtend @@ -39,6 +39,8 @@ import org.eclipse.xtext.resource.IDefaultResourceDescriptionStrategy import org.eclipse.xtext.scoping.IScopeProvider import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider import org.eclipse.xtext.service.DefaultRuntimeModule +import org.eclipse.xtext.ui.editor.DirtyStateManager +import org.eclipse.xtext.ui.editor.IDirtyStateManager import org.eclipse.xtext.validation.IResourceValidator import org.eclipse.mita.base.typesystem.infra.AbstractSizeInferrer import org.eclipse.mita.base.typesystem.infra.NullSizeInferrer @@ -59,6 +61,7 @@ class PlatformDSLRuntimeModule extends AbstractPlatformDSLRuntimeModule { binder.bind(IConstraintSolver).annotatedWith(Names.named("sizeSolver")).to(NullSolver); binder.bind(MitaTypeLinker).annotatedWith(Names.named("typeLinker")).to(MitaTypeLinker); binder.bind(MitaTypeLinker).annotatedWith(Names.named("typeDependentLinker")).to(PlatformLinker); + binder.bind(IDirtyStateManager).to(DirtyStateManager); binder.bind(AbstractSizeInferrer).to(NullSizeInferrer); } diff --git a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/infra/PlatformLinker.xtend b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/infra/PlatformLinker.xtend index 7dab9840..4ade19be 100644 --- a/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/infra/PlatformLinker.xtend +++ b/bundles/org.eclipse.mita.platform/src/org/eclipse/mita/platform/infra/PlatformLinker.xtend @@ -26,7 +26,7 @@ import org.eclipse.xtext.nodemodel.INode class PlatformLinker extends MitaTypeLinker { override shouldLink(EClass classifier) { - super.shouldLink(classifier) || PlatformPackage.eINSTANCE.abstractSystemResource.isSuperTypeOf(classifier); + false;//super.shouldLink(classifier) || PlatformPackage.eINSTANCE.abstractSystemResource.isSuperTypeOf(classifier); } override ensureIsLinked(EObject obj, INode node, CrossReference ref, Set handledReferences, IDiagnosticProducer producer) { diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/BasicControlStructuresTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/BasicControlStructuresTest.xtend index 1dc85f03..4494ef75 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/BasicControlStructuresTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/BasicControlStructuresTest.xtend @@ -40,7 +40,7 @@ class BasicControlStructuresTest extends AbstractGeneratorTest { ''') ast.assertNoCompileErrors(); - val generatedFunction = ast.value.findFunction("HandleEvery100Millisecond1"); + val generatedFunction = ast.value.findFunction("HandleEvery100Millisecond1_worker"); assertNotNull("No event handler was generated", generatedFunction); val body = generatedFunction.body as IASTCompoundStatement; diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/SensorAccessTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/SensorAccessTest.xtend index c7aa73f9..d26925fb 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/SensorAccessTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/SensorAccessTest.xtend @@ -34,7 +34,7 @@ class SensorAccessTest extends AbstractGeneratorTest { '''); ast.assertNoCompileErrors(); - val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1") + val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1_worker") assertNotNull("No event handler was generated", eventHandler); val body = eventHandler.body as IASTCompoundStatement; /* diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/TryCatchGeneratorTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/TryCatchGeneratorTest.xtend index 9e4a6b65..48d73d13 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/TryCatchGeneratorTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/generator/tests/TryCatchGeneratorTest.xtend @@ -53,7 +53,7 @@ class TryCatchGeneratorTest extends AbstractGeneratorTest { '''); ast.assertNoCompileErrors(); - val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1") + val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1_worker") assertNotNull("No event handler was generated", eventHandler); val body = eventHandler.body as IASTCompoundStatement; @@ -110,7 +110,7 @@ class TryCatchGeneratorTest extends AbstractGeneratorTest { '''); ast.assertNoCompileErrors(); - val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1") + val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1_worker") assertNotNull("No event handler was generated", eventHandler); val body = eventHandler.body as IASTCompoundStatement; @@ -225,7 +225,7 @@ class TryCatchGeneratorTest extends AbstractGeneratorTest { '''); ast.assertNoCompileErrors(); - val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1") + val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1_worker") assertNotNull("No event handler was generated", eventHandler); val body = eventHandler.body as IASTCompoundStatement; diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/EpochTimeTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/EpochTimeTest.xtend new file mode 100644 index 00000000..f23de916 --- /dev/null +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/EpochTimeTest.xtend @@ -0,0 +1,50 @@ +/******************************************************************************** + * Copyright (c) 2018 Bosch Connected Devices and Solutions GmbH. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * Contributors: + * Bosch Connected Devices and Solutions GmbH - initial contribution + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +package org.eclipse.mita.program.runtime.tests + +import org.junit.Test +import java.nio.file.Paths +import org.junit.Assert +import java.time.Instant + +class EpochTimeTest extends AbstractRuntimeTest { + @Test + def testMe() { + val projectPath = setup("epochTimeTest", ''' + package my.pkg; + + import platforms.x86; + + var x = 0; + + every x86.startup(time) { + println(`${time}`); + } + + every 1 seconds { + exit(0); + } + + native unchecked fn exit(status: int16): void header "stdlib.h"; + ''').key; + compileMita(projectPath); + compileC(projectPath, "all"); + val executable = projectPath.resolve(Paths.get("src-gen", "build", "app")); + val lines = runAtMost(executable, 60); + val lastLine = lines.iterator.last; + val timeFromApp = Integer.parseInt(lastLine); + val timeFromJava = Instant.now().toEpochMilli(); + Assert.assertTrue(Math.abs(timeFromJava as int - timeFromApp) < 10); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/RingbufferTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/RingbufferTest.xtend new file mode 100644 index 00000000..2936f3b2 --- /dev/null +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/RingbufferTest.xtend @@ -0,0 +1,298 @@ +/******************************************************************************** + * Copyright (c) 2018 Bosch Connected Devices and Solutions GmbH. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * Contributors: + * Bosch Connected Devices and Solutions GmbH - initial contribution + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +package org.eclipse.mita.program.runtime.tests + +import com.google.common.collect.Streams +import java.nio.file.Paths +import org.junit.Assert +import org.junit.Test + +class RingbufferTest extends AbstractRuntimeTest { + @Test + def testMe() { + val projectPath = setup("ringbufferTest", ''' + package my.pkg; + + import platforms.x86; + + native unchecked fn exit(status: int16): void header "stdlib.h"; + + let a1: ringbuffer; + let a2: ringbuffer; + let a3: ringbuffer, 3>; + let a4: ringbuffer, 5>; + let a5: ringbuffer, 5>, 3>; + + fn report(r: &ringbuffer) { + println(`${(*r).count()} ${(*r).empty()} ${(*r).full()}`); + } + fn report(r: &ringbuffer) { + println(`${(*r).count()} ${(*r).empty()} ${(*r).full()}`); + } + + every x86.startup { + try { + // 0 1 0 + (&a1).report(); + a1.push(1); + // 1 0 0 + (&a1).report(); + a1.push(2); + // 2 0 1 + (&a1).report(); + // add to full RB + a1.push(3); + } + catch(IndexOutOfBoundsException) { + // we get here + println("IOOB"); + } + try { + // 0 1 0 + (&a2).report(); + // no such element --> IOOB + println(`${a2.peek()}`); + } + catch(IndexOutOfBoundsException) { + // we get here + println("IOOB"); + } + try { + // no such element --> IOOB + println(`${a2.pop()}`); + } + catch(IndexOutOfBoundsException) { + // we get here + println("IOOB"); + } + let a2els = a2.capacity() - a2.count(); + for(var i = 0; i < a2els; i++) { + a2.push(i); + } + let a3els = a3.capacity() - a3.count(); + for(var i = 0; i < a3els; i++) { + a3.push(`${i}`); + } + let a4els = a4.capacity() - a4.count(); + for(var i = 0; i < a4els; i++) { + a4.push([i]); + } + let a5els = a5.capacity() - a5.count(); + for(var i = 0; i < a5els; i++) { + a5.push([`${i}`]); + } + } + + /* + * Initially: + * a1 = [1,2] + * a2 = [0,1, ..., 19] + * a3 = ["0", "1", "2"] + * a4 = [[0], [1], ..., [5]] + * a5 = [["0"], ["1"], ["2"]] + */ + every 1 second { + //1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10 + println(`1: ${a1.peek()}`); + a1.push(a1.pop() + 1); + + //0,1,2,3,4,5,6,7,8,...,18 + println(`2: ${a2.peek()}`); + a2.push(a2.pop() + 1); + + //"0", "1", "2", "01", "11", "21", "011", "111", "211", ..., "211111", "0111111" + var a3s: string<100> = a3.pop(); + print("3: "); + println(a3s); + if(a3s.length() < 100) { + a3s += "1"; + } + else { + println("a3s full"); + } + a3.push(a3s); + + // [0], [1], [2], [3], [0, 1], [1, 1], [2, 1], [3, 1], ..., [3, 1, 1, 1] + var a4s: array = a4.pop(); + print("4: "); + printarray(a4s); + if(a4s.length() < 10) { + a4s += [1 as uint8]; + } + else { + println("a4s full"); + } + a4.push(a4s); + + // ["0"], ["1"], ["2"], ["0", "1"], ..., ["0", "1", "1", "1", "1"], 7*"a5s full" + var a5s: array, 5> = a5.pop(); + print("5: "); + printarray(a5s); + if(a5s.length() < 5) { + a5s += ["1"]; + } + else { + println("a5s full"); + } + a5.push(a5s); + + if(a1.peek() > 10) { + exit(0); + } + } + + fn printarray(a: array) { + print("["); + for(var i = 0; i < a.length(); i++) { + print(`${a[i]}`); + if(i < a.length() - 1) { + print(", "); + } + } + println("]"); + } + + fn printarray(a: array, _>) { + print("["); + for(var i = 0; i < a.length(); i++) { + print(`${a[i]}`); + if(i < a.length() - 1) { + print(", "); + } + } + println("]"); + } + ''').key; + compileMita(projectPath); + compileC(projectPath, "all"); + val executable = projectPath.resolve(Paths.get("src-gen", "build", "app")); + val lines = runAtMost(executable, 60); + val expectations = #[ + "0 1 0", + "1 0 0", + "2 0 1", + "IOOB", + "0 1 0", + "IOOB", + "IOOB", + "1: 1", + "2: 0", + "3: 0", + "4: [0]", + "5: [0]", + "1: 2", + "2: 1", + "3: 1", + "4: [1]", + "5: [1]", + "1: 2", + "2: 2", + "3: 2", + "4: [2]", + "5: [2]", + "1: 3", + "2: 3", + "3: 01", + "4: [3]", + "5: [0, 1]", + "1: 3", + "2: 4", + "3: 11", + "4: [4]", + "5: [1, 1]", + "1: 4", + "2: 5", + "3: 21", + "4: [0, 1]", + "5: [2, 1]", + "1: 4", + "2: 6", + "3: 011", + "4: [1, 1]", + "5: [0, 1, 1]", + "1: 5", + "2: 7", + "3: 111", + "4: [2, 1]", + "5: [1, 1, 1]", + "1: 5", + "2: 8", + "3: 211", + "4: [3, 1]", + "5: [2, 1, 1]", + "1: 6", + "2: 9", + "3: 0111", + "4: [4, 1]", + "5: [0, 1, 1, 1]", + "1: 6", + "2: 10", + "3: 1111", + "4: [0, 1, 1]", + "5: [1, 1, 1, 1]", + "1: 7", + "2: 11", + "3: 2111", + "4: [1, 1, 1]", + "5: [2, 1, 1, 1]", + "1: 7", + "2: 12", + "3: 01111", + "4: [2, 1, 1]", + "5: [0, 1, 1, 1, 1]", + "a5s full", + "1: 8", + "2: 13", + "3: 11111", + "4: [3, 1, 1]", + "5: [1, 1, 1, 1, 1]", + "a5s full", + "1: 8", + "2: 14", + "3: 21111", + "4: [4, 1, 1]", + "5: [2, 1, 1, 1, 1]", + "a5s full", + "1: 9", + "2: 15", + "3: 011111", + "4: [0, 1, 1, 1]", + "5: [0, 1, 1, 1, 1]", + "a5s full", + "1: 9", + "2: 16", + "3: 111111", + "4: [1, 1, 1, 1]", + "5: [1, 1, 1, 1, 1]", + "a5s full", + "1: 10", + "2: 17", + "3: 211111", + "4: [2, 1, 1, 1]", + "5: [2, 1, 1, 1, 1]", + "a5s full", + "1: 10", + "2: 18", + "3: 0111111", + "4: [3, 1, 1, 1]", + "5: [0, 1, 1, 1, 1]", + "a5s full" + ]; + Streams.zip(lines, expectations.stream, [s1, s2| + Assert.assertEquals(s1.trim, s2.trim); + return null; + ]) + return; + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/StringTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/StringTest.xtend index 4cae7c36..25c57894 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/StringTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/StringTest.xtend @@ -41,7 +41,7 @@ class StringTest extends AbstractRuntimeTest { var c = "5"; c += "6"; println(c); - var d = new string<100>; + var d = new string<100>(); d += "7"; println(d); for(var i = 8; i < 12; i++) { @@ -63,7 +63,9 @@ class StringTest extends AbstractRuntimeTest { val lines = runAtMost(executable, 60); val expectedLines = #["1", "2", "34", "3", "56", "7", "7891011"]; for(l1_l2: lines.collect(Collectors.toList).zip(expectedLines)) { - Assert.assertEquals(l1_l2.key.trim, l1_l2.value.trim); + println(l1_l2); + println(l1_l2.key.trim + ", " + l1_l2.value.trim); + Assert.assertEquals(l1_l2.key, l1_l2.value); } } } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/SumTypesTest.xtend b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/SumTypesTest.xtend index 5b5bc4a4..04a5e4bd 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/SumTypesTest.xtend +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/runtime/tests/SumTypesTest.xtend @@ -132,7 +132,7 @@ class SumTypesTest extends AbstractRuntimeTest { "v4d(18, 19, 20, 21)" ] for(l1_l2: lines.collect(Collectors.toList).zip(expectedLines)) { - Assert.assertEquals(l1_l2.key.trim, l1_l2.value); + Assert.assertEquals(l1_l2.key, l1_l2.value); } } } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/arrays/ArraysTest.mita.xt b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/arrays/ArraysTest.mita.xt index 9ead8a38..8997b796 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/arrays/ArraysTest.mita.xt +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/arrays/ArraysTest.mita.xt @@ -155,12 +155,10 @@ fn errors() { var a = new array(); /* XPECT errors --- "Array range is invalid: Lower bound must be smaller than upper bound" at "2:1" - "Couldn't infer size" at "a[2:1]" --- */ var b = a[2:1]; /* XPECT errors --- "Array range is invalid: Lower bound must be smaller than upper bound" at "6:" - "Couldn't infer size" at "a[6:]" --- */ b = a[6:]; // XPECT errors --> "Array range is invalid: Upper bound must be less than or equal to array size (5)" at ":7" diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/events/EventHandlingTest.mita.xt b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/events/EventHandlingTest.mita.xt index 2bd05582..fd6a83df 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/events/EventHandlingTest.mita.xt +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/events/EventHandlingTest.mita.xt @@ -33,3 +33,21 @@ every vci01.event02 { } // This should be fine, we should generate two different handlers every my_sensor00.event00 { } + +// XPECT noCompileErrors +every my_sensor00.event03(u32) { + //XPECT inferredType --> uint32 + let a = u32; +} +// XPECT noCompileErrors +every my_sensor00.event04(s100) { + //XPECT inferredType --> string<'100> + let a = s100; +} +// XPECT noCompileErrors +every my_sensor00.event05(ar_s100_5) { + //XPECT inferredType --> array, '5> + let a = ar_s100_5; +} + + diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/optionals/OptionalsTest.mita.xt b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/optionals/OptionalsTest.mita.xt index f4e33708..01f7280d 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/optionals/OptionalsTest.mita.xt +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/optionals/OptionalsTest.mita.xt @@ -43,10 +43,6 @@ function testOptionalsSuccess() { } function testOptionalOfOptionalError() { - /*XPECT errors --- - "Nested generated types are not supported yet." at "optional" - "Nested generated types are not supported yet." at "var optionalOfOptional : optional = 10;" - --- */ var optionalOfOptional : optional = 10; optionalOfOptional = 10; } @@ -66,10 +62,6 @@ function testOptionalsFail(){ var optional : uint32?; functionWithOptionals(42, 10); - /*XPECT errors --- - "Nested generated types are not supported yet." at "optional" - "Nested generated types are not supported yet." at "var optionalOfOptional : optional = 10;" - --- */ var optionalOfOptional : optional = 10; // XPECT errors --> "Assignment operator '=' may only be applied on compatible types, not on uint32 and optional." at "notOptional = optional" notOptional = optional; diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/strings/StringsTest.mita.xt b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/strings/StringsTest.mita.xt index 88b8192b..8e43592e 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/strings/StringsTest.mita.xt +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/strings/StringsTest.mita.xt @@ -80,7 +80,7 @@ function stringTestSuccess() : void { let x17 = `${x14} ${x15}`; let x18 = `\n\t\r 0123456789{}()[],.;:`; let x19 = `{ } , ; : . ( ) [ ] + - * / % \\ && || & | = == < > <= >= !=`; - let x20 = `alias-of alt alternative as catch checked constructor do else enum every exception export extends finally fn for function generated generator header hour hours if in import is isother let millisecond milliseconds minute minutes native native-type new package return second seconds setup size-inferrer static struct subtype-of throw try type unchecked validator var where while`; + let x20 = `alias-of alt alternative as catch checked constructor con do else enum every exception export extends finally fn for function generated generator header hour hours if in import is isother let millisecond milliseconds minute minutes native native-type new package return second seconds setup size-inferrer static struct subtype-of throw try type unchecked validator var where while`; let x21 = `this ${"is"} a test`; let x22 = `${bla + bla * 2}`; } diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/sumtypes/SumTypesTest.mita.xt b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/sumtypes/SumTypesTest.mita.xt index f9599b24..afba300b 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/sumtypes/SumTypesTest.mita.xt +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/sumtypes/SumTypesTest.mita.xt @@ -62,7 +62,7 @@ fn incVecs(a: anyVec) { is(x: anyVec.vec1d) { /*XPECT errors --- "Function __PLUS__ cannot be used here" at "x + 1" - "__args(vec1d(int32), xint8) not instance of __PLUS__. Valid instances are:\r\n __PLUS__([x: double, y: double]): __args(f64, f64) → f64\r\n __PLUS__([x: float, y: float]): __args(f32, f32) → f32\r\n __PLUS__([x: int16, y: int16]): __args(int16, int16) → int16\r\n __PLUS__([x: int32, y: int32]): __args(int32, int32) → int32\r\n __PLUS__([x: int8, y: int8]): __args(int8, int8) → int8\r\n __PLUS__([x: uint16, y: uint16]): __args(uint16, uint16) → uint16\r\n __PLUS__([x: uint32, y: uint32]): __args(uint32, uint32) → uint32\r\n __PLUS__([x: uint8, y: uint8]): __args(uint8, uint8) → uint8\r\n __PLUS__([x: xint16, y: xint16]): __args(xint16, xint16) → xint16\r\n __PLUS__([x: xint32, y: xint32]): __args(xint32, xint32) → xint32\r\n __PLUS__([x: xint8, y: xint8]): __args(xint8, xint8) → xint8\r\n __PLUS__([x: string, y: string]): ∀[A, B].__args(string, string) → string\r\n __PLUS__([x: array, y: array]): ∀[C, D, E].__args(array, array) → array\r\n" at "x + 1" + "__args(vec1d(int32), xint8) not instance of __PLUS__. Valid instances are:\n __PLUS__([x: double, y: double]): __args(f64, f64) → f64\n __PLUS__([x: float, y: float]): __args(f32, f32) → f32\n __PLUS__([x: int16, y: int16]): __args(int16, int16) → int16\n __PLUS__([x: int32, y: int32]): __args(int32, int32) → int32\n __PLUS__([x: int8, y: int8]): __args(int8, int8) → int8\n __PLUS__([x: uint16, y: uint16]): __args(uint16, uint16) → uint16\n __PLUS__([x: uint32, y: uint32]): __args(uint32, uint32) → uint32\n __PLUS__([x: uint8, y: uint8]): __args(uint8, uint8) → uint8\n __PLUS__([x: xint16, y: xint16]): __args(xint16, xint16) → xint16\n __PLUS__([x: xint32, y: xint32]): __args(xint32, xint32) → xint32\n __PLUS__([x: xint8, y: xint8]): __args(xint8, xint8) → xint8\n __PLUS__([x: string, y: string]): ∀[A, B].__args(string, string) → string\n __PLUS__([x: array, y: array]): ∀[C, D, E].__args(array, array) → array\n __PLUS__([x: array, y: array]): ∀[F, G, H].__args(array, array) → array\n" at "x + 1" --- */ b = vec1d(x + 1); } diff --git a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/types/VariableTypeInferrenceErrors.mita.xt b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/types/VariableTypeInferrenceErrors.mita.xt index e40398e1..983e9e05 100644 --- a/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/types/VariableTypeInferrenceErrors.mita.xt +++ b/bundles/org.eclipse.mita.program.tests/src/org/eclipse/mita/program/tests/types/VariableTypeInferrenceErrors.mita.xt @@ -120,7 +120,7 @@ function noCommonType() { var y : uint32 = 10; /* XPECT errors --- "Function __PLUS__ cannot be used here" at "x + y" - "__args(int32, uint32) not instance of __PLUS__. Valid instances are:\r\n __PLUS__([x: double, y: double]): __args(f64, f64) → f64\r\n __PLUS__([x: float, y: float]): __args(f32, f32) → f32\r\n __PLUS__([x: int16, y: int16]): __args(int16, int16) → int16\r\n __PLUS__([x: int32, y: int32]): __args(int32, int32) → int32\r\n __PLUS__([x: int8, y: int8]): __args(int8, int8) → int8\r\n __PLUS__([x: uint16, y: uint16]): __args(uint16, uint16) → uint16\r\n __PLUS__([x: uint32, y: uint32]): __args(uint32, uint32) → uint32\r\n __PLUS__([x: uint8, y: uint8]): __args(uint8, uint8) → uint8\r\n __PLUS__([x: xint16, y: xint16]): __args(xint16, xint16) → xint16\r\n __PLUS__([x: xint32, y: xint32]): __args(xint32, xint32) → xint32\r\n __PLUS__([x: xint8, y: xint8]): __args(xint8, xint8) → xint8\r\n __PLUS__([x: string, y: string]): ∀[A, B].__args(string, string) → string\r\n __PLUS__([x: array, y: array]): ∀[C, D, E].__args(array, array) → array\r\n" at "x + y" + "__args(int32, uint32) not instance of __PLUS__. Valid instances are:\n __PLUS__([x: double, y: double]): __args(f64, f64) → f64\n __PLUS__([x: float, y: float]): __args(f32, f32) → f32\n __PLUS__([x: int16, y: int16]): __args(int16, int16) → int16\n __PLUS__([x: int32, y: int32]): __args(int32, int32) → int32\n __PLUS__([x: int8, y: int8]): __args(int8, int8) → int8\n __PLUS__([x: uint16, y: uint16]): __args(uint16, uint16) → uint16\n __PLUS__([x: uint32, y: uint32]): __args(uint32, uint32) → uint32\n __PLUS__([x: uint8, y: uint8]): __args(uint8, uint8) → uint8\n __PLUS__([x: xint16, y: xint16]): __args(xint16, xint16) → xint16\n __PLUS__([x: xint32, y: xint32]): __args(xint32, xint32) → xint32\n __PLUS__([x: xint8, y: xint8]): __args(xint8, xint8) → xint8\n __PLUS__([x: string, y: string]): ∀[A, B].__args(string, string) → string\n __PLUS__([x: array, y: array]): ∀[C, D, E].__args(array, array) → array\n __PLUS__([x: array, y: array]): ∀[F, G, H].__args(array, array) → array\n" at "x + y" --- */ var z = x + y; } diff --git a/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/builder/ProgramDslBuilderParticipant.xtend b/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/builder/ProgramDslBuilderParticipant.xtend index ceab104e..e33535eb 100644 --- a/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/builder/ProgramDslBuilderParticipant.xtend +++ b/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/builder/ProgramDslBuilderParticipant.xtend @@ -103,9 +103,9 @@ class ProgramDslBuilderParticipant extends BuilderParticipant { override protected handleChangedContents(Delta delta, IBuildContext context, EclipseResourceFileSystemAccess2 fileSystemAccess) throws CoreException { super.handleChangedContents(delta, context, fileSystemAccess) - if (!buildSemaphore.get() && generator !== null) { - invokeGenerator(delta, context, fileSystemAccess); - } +// if (!buildSemaphore.get() && generator !== null) { +// invokeGenerator(delta, context, fileSystemAccess); +// } } protected def void invokeGenerator(Delta delta, IBuildContext context, IFileSystemAccess2 fileSystemAccess) { diff --git a/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/highlighting/ProgramDslSemanticHighlightingCalculator.xtend b/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/highlighting/ProgramDslSemanticHighlightingCalculator.xtend index e32c183e..17cda844 100644 --- a/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/highlighting/ProgramDslSemanticHighlightingCalculator.xtend +++ b/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/highlighting/ProgramDslSemanticHighlightingCalculator.xtend @@ -16,9 +16,9 @@ package org.eclipse.mita.program.ui.highlighting import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.base.expressions.FeatureCall +import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.InterpolatedStringLiteral import org.eclipse.mita.platform.Modality -import org.eclipse.mita.program.GeneratedFunctionDefinition import org.eclipse.xtext.ide.editor.syntaxcoloring.DefaultSemanticHighlightingCalculator import org.eclipse.xtext.ide.editor.syntaxcoloring.IHighlightedPositionAcceptor import org.eclipse.xtext.nodemodel.INode diff --git a/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/labeling/ProgramDslLabelProvider.xtend b/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/labeling/ProgramDslLabelProvider.xtend index cb84f7a1..d796c9bd 100644 --- a/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/labeling/ProgramDslLabelProvider.xtend +++ b/bundles/org.eclipse.mita.program.ui/src/org/eclipse/mita/program/ui/labeling/ProgramDslLabelProvider.xtend @@ -37,12 +37,12 @@ import org.eclipse.mita.base.types.Singleton import org.eclipse.mita.base.types.StructureType import org.eclipse.mita.base.types.SumType import org.eclipse.mita.base.types.TypedElement +import org.eclipse.mita.base.types.SystemResourceEvent import org.eclipse.mita.base.typesystem.types.AbstractType import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.platform.Connectivity import org.eclipse.mita.platform.Sensor import org.eclipse.mita.platform.SystemResourceAlias -import org.eclipse.mita.platform.SystemResourceEvent import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.FunctionDefinition import org.eclipse.mita.program.SignalInstance diff --git a/bundles/org.eclipse.mita.program/.classpath b/bundles/org.eclipse.mita.program/.classpath index a242d435..07ba5392 100644 --- a/bundles/org.eclipse.mita.program/.classpath +++ b/bundles/org.eclipse.mita.program/.classpath @@ -5,6 +5,10 @@ - + + + + + diff --git a/bundles/org.eclipse.mita.program/META-INF/MANIFEST.MF b/bundles/org.eclipse.mita.program/META-INF/MANIFEST.MF index 0345e874..3bd592ce 100644 --- a/bundles/org.eclipse.mita.program/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.mita.program/META-INF/MANIFEST.MF @@ -25,7 +25,8 @@ Require-Bundle: org.eclipse.xtext, org.eclipse.mita.base;visibility:=reexport, org.eclipse.mita.library.extension, org.eclipse.core.resources, - com.google.gson;bundle-version="2.2.4" + com.google.gson;bundle-version="2.2.4", + org.eclipse.xtext.ui Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Export-Package: org.eclipse.mita.program, org.eclipse.mita.program.generator, diff --git a/bundles/org.eclipse.mita.program/model/program.xcore b/bundles/org.eclipse.mita.program/model/program.xcore index 58123e0e..71085190 100644 --- a/bundles/org.eclipse.mita.program/model/program.xcore +++ b/bundles/org.eclipse.mita.program/model/program.xcore @@ -23,7 +23,7 @@ import org.eclipse.mita.base.expressions.AssignmentOperator import org.eclipse.mita.base.expressions.AssignmentExpression import org.eclipse.mita.base.expressions.IntLiteral import org.eclipse.mita.base.expressions.Literal -import org.eclipse.mita.base.types.Event +import org.eclipse.mita.base.types.SystemResourceEvent import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.base.types.Operation import org.eclipse.mita.base.types.Parameter @@ -32,6 +32,7 @@ import org.eclipse.mita.platform.AbstractSystemResource import org.eclipse.mita.platform.ConfigurationItem import org.eclipse.mita.platform.Modality import org.eclipse.mita.platform.Signal +import org.eclipse.mita.platform.HasEvents import org.eclipse.mita.base.types.PackageAssociation import org.eclipse.mita.base.types.ImportStatement import org.eclipse.mita.base.types.Exportable @@ -39,11 +40,11 @@ import org.eclipse.mita.base.types.GeneratedElement import org.eclipse.mita.base.types.ExceptionTypeDeclaration import org.eclipse.mita.base.types.PresentTypeSpecifier import org.eclipse.mita.base.types.TypeReferenceSpecifier +import org.eclipse.mita.base.types.ExportableOperation import org.eclipse.mita.base.types.GeneratedType import org.eclipse.mita.base.types.SumAlternative import org.eclipse.xtext.nodemodel.util.NodeModelUtils import org.eclipse.xtext.EcoreUtil2 -import org.eclipse.mita.base.types.InterpolatedStringLiteral class Program extends PackageAssociation { contains ImportStatement[] imports @@ -56,8 +57,7 @@ class Program extends PackageAssociation { } } -class SystemResourceSetup { - id String name +class SystemResourceSetup extends HasEvents { refers AbstractSystemResource ^type contains ConfigurationItemValue[] configurationItemValues contains SignalInstance[] signalInstances @@ -73,6 +73,10 @@ class SystemResourceSetup { val typeName = BaseUtils.getText(this, ProgramPackage.eINSTANCE.systemResourceSetup_Type); return 'setup ' + name + ': ' + typeName + ' {...}'; } + + op SystemResourceEvent[] getEvents() { + return ^type?.events + } } class ConfigurationItemValue { @@ -102,8 +106,15 @@ class SignalInstance extends VariableDeclaration { } +class EventHandlerVariableDeclaration extends VariableDeclaration { + op EventHandlerDeclaration getEventHandler() { + return EcoreUtil2.getContainerOfType(this, EventHandlerDeclaration) + } +} + class EventHandlerDeclaration { contains EventSource event + contains EventHandlerVariableDeclaration payload contains ProgramBlock block op String toString() { @@ -120,8 +131,8 @@ class TimeIntervalEvent extends EventSource { } } class SystemEventSource extends EventSource { - refers AbstractSystemResource origin - refers Event source + refers HasEvents origin + refers SystemResourceEvent source op String toString() { val ref = eGet(ProgramPackage.eINSTANCE.systemEventSource_Source, false); @@ -139,12 +150,6 @@ enum TimeUnit { Hour } -abstract class ExportableOperation extends Operation, Exportable { - op String toString() { - return super.toString(); - } -} - class FunctionDefinition extends ExportableOperation { contains ProgramBlock body @@ -156,15 +161,6 @@ class FunctionDefinition extends ExportableOperation { } } -class GeneratedFunctionDefinition extends ExportableOperation, GeneratedElement { - op String getId(){ - return null; - } - op String toString() { - return super.toString(); - } -} - class NativeFunctionDefinition extends ExportableOperation, GeneratedElement { String header boolean checked @@ -206,6 +202,9 @@ class VariableDeclaration extends Property, AbstractStatement { class ArrayLiteral extends Literal { contains Expression[] values + op String toString() { + return "[" + values.join(", ") + "]"; + } } abstract class AbstractLoopStatement extends AbstractStatement { @@ -340,12 +339,20 @@ class CatchStatement extends AbstractStatement { class NewInstanceExpression extends ElementReferenceExpression { contains TypeReferenceSpecifier ^type + op void setReference(EObject reference) { + + } + op Operation getReference() { val refType = ^type.^type; if(refType instanceof GeneratedType) { return refType.constructor; } } + + op String getRefText() { + return ^type.toString; + } } class DereferenceExpression extends Expression { diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDsl.xtext b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDsl.xtext index 34483ae9..97e17a1a 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDsl.xtext +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDsl.xtext @@ -53,7 +53,7 @@ SignalInstance returns program::SignalInstance: (writeable ?= 'var') name=ID typeSpecifier=NullTypeSpecifier '=' initialization=ElementReferenceExpression ';' ; -GeneratedFunctionDefinition returns program::GeneratedFunctionDefinition: +GeneratedFunctionDefinition returns types::GeneratedFunctionDefinition: (exported?='export')? 'generated' ('fn' | 'function') ('<' typeParameters+=TypeParameter (',' typeParameters+=TypeParameter)* '>')? @@ -97,8 +97,12 @@ VariableDeclaration returns program::VariableDeclaration: (writeable ?= 'var' | 'let') name=ID typeSpecifier=OptionalTypeSpecifier ('=' initialization=Expression)? ';' ; +EventHandlerVariableDeclaration returns program::EventHandlerVariableDeclaration: + name=ID typeSpecifier=NullTypeSpecifier +; + EventHandlerDeclaration returns program::EventHandlerDeclaration: - 'every' event=(TimeIntervalEvent | SystemEventSource) + 'every' event=(TimeIntervalEvent | SystemEventSource) ('(' payload=EventHandlerVariableDeclaration ')')? block=ProgramBlock ; @@ -113,8 +117,8 @@ enum TimeUnit returns program::TimeUnit: Hour = 'hour' | Hour = 'hours' ; -SystemEventSource returns program::SystemEventSource: - origin=[platform::AbstractSystemResource] '.' source=[types::Event] +SystemEventSource returns program::SystemEventSource: + origin=[platform::HasEvents] '.' source=[types::SystemResourceEvent] ; ReturnParameterDeclaration returns program::ReturnParameterDeclaration: @@ -181,7 +185,7 @@ ReferenceExpression returns program::ReferenceExpression hidden(): ; NewInstanceExpression returns program::NewInstanceExpression: - 'new' type=UnqualifiedPresentTypeSpecifier '(' (arguments+=Argument (',' arguments+=Argument)*)? ')' + 'new' type=UnqualifiedPresentTypeSpecifier operationCall?='(' (arguments+=Argument (',' arguments+=Argument)*)? ')' ; UnqualifiedPresentTypeSpecifier returns types::TypeReferenceSpecifier: diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDslRuntimeModule.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDslRuntimeModule.xtend index 009058af..3c6e4ce6 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDslRuntimeModule.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/ProgramDslRuntimeModule.xtend @@ -39,6 +39,7 @@ import org.eclipse.mita.program.formatting.ProgramDslFormatter import org.eclipse.mita.program.generator.ProgramDslGenerator import org.eclipse.mita.program.generator.internal.IGeneratorOnResourceSet import org.eclipse.mita.program.inferrer.ProgramSizeInferrer +import org.eclipse.mita.program.inferrer.SizeConstraintSolver import org.eclipse.mita.program.scoping.ProgramDslImportScopeProvider import org.eclipse.mita.program.scoping.ProgramDslResourceDescriptionStrategy import org.eclipse.mita.program.typesystem.ProgramConstraintFactory @@ -51,6 +52,8 @@ import org.eclipse.xtext.scoping.IGlobalScopeProvider import org.eclipse.xtext.scoping.IScopeProvider import org.eclipse.xtext.scoping.impl.AbstractDeclarativeScopeProvider import org.eclipse.xtext.service.DefaultRuntimeModule +import org.eclipse.xtext.ui.editor.DirtyStateManager +import org.eclipse.xtext.ui.editor.IDirtyStateManager import org.eclipse.xtext.validation.CompositeEValidator import org.eclipse.xtext.validation.IResourceValidator import org.eclipse.mita.program.inferrer.SizeConstraintSolver @@ -71,6 +74,7 @@ class ProgramDslRuntimeModule extends AbstractProgramDslRuntimeModule { binder.bind(IConstraintSolver).annotatedWith(Names.named("sizeSolver")).to(SizeConstraintSolver); binder.bind(MitaTypeLinker).annotatedWith(Names.named("typeLinker")).to(MitaTypeLinker); binder.bind(MitaTypeLinker).annotatedWith(Names.named("typeDependentLinker")).to(ProgramLinker); + binder.bind(IDirtyStateManager).to(DirtyStateManager); binder.bind(AbstractSizeInferrer).to(ProgramSizeInferrer); } override configureIScopeProviderDelegate(Binder binder) { diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/formatting/ProgramDslFormatter.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/formatting/ProgramDslFormatter.xtend index b2b2ab99..cae8cc32 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/formatting/ProgramDslFormatter.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/formatting/ProgramDslFormatter.xtend @@ -144,6 +144,7 @@ class ProgramDslFormatter extends AbstractDeclarativeFormatter { config.setIndentationIncrement.before(grammar.generatedFunctionDefinitionAccess.generatorKeyword_9_0_0) config.setLinewrap(1, 1, 2).before(grammar.generatedFunctionDefinitionAccess.generatorKeyword_9_0_0) config.setLinewrap(1, 1, 2).before(grammar.generatedFunctionDefinitionAccess.validatorKeyword_9_1_0) + config.setLinewrap(1, 1, 2).before(grammar.generatedFunctionDefinitionAccess.sizeInferrerKeyword_9_2_0) config.setIndentationDecrement.after(grammar.generatedFunctionDefinitionAccess.semicolonKeyword_10); } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/AbstractFunctionGenerator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/AbstractFunctionGenerator.xtend index 77b20140..7d9f2c69 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/AbstractFunctionGenerator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/AbstractFunctionGenerator.xtend @@ -13,13 +13,14 @@ package org.eclipse.mita.program.generator +import com.google.common.base.Optional import com.google.inject.Inject import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.base.util.BaseUtils -import org.eclipse.xtext.generator.trace.node.IGeneratorNode -import static extension org.eclipse.mita.base.util.BaseUtils.computeOrigin; +import static extension org.eclipse.mita.base.util.BaseUtils.computeOrigin + /** * Generates code implementing a function call. */ @@ -36,7 +37,7 @@ abstract class AbstractFunctionGenerator implements IGenerator { * If resultVariableName is null the generator is expected to produce a valid C expression. If the generator * cannot produce such an expression it should mark an error. */ - abstract def CodeFragment generate(ElementReferenceExpression functionCall, IGeneratorNode resultVariableName) + abstract def CodeFragment generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) /** * This function allows generators to opt out of the regular function unraveling. This enables function generators diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/AbstractTypeGenerator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/AbstractTypeGenerator.xtend index ada4240a..e7d02f3f 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/AbstractTypeGenerator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/AbstractTypeGenerator.xtend @@ -19,17 +19,13 @@ import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.expressions.AssignmentOperator import org.eclipse.mita.base.types.CoercionExpression import org.eclipse.mita.base.types.Expression -import org.eclipse.mita.base.typesystem.infra.SubtypeChecker import org.eclipse.mita.base.typesystem.types.AbstractType import org.eclipse.mita.program.NewInstanceExpression /** * Interface for type generators. */ -abstract class AbstractTypeGenerator implements IGenerator { - - @Inject SubtypeChecker subtypeChecker; - +abstract class AbstractTypeGenerator implements IGenerator { @Inject protected TypeGenerator typeGenerator @@ -51,20 +47,41 @@ abstract class AbstractTypeGenerator implements IGenerator { } /** - * Produces a new instance of the type + * Produces initialization code that cannot be put globally. */ - def CodeFragment generateNewInstance(AbstractType type, NewInstanceExpression expr); - + def CodeFragment generateGlobalInitialization(AbstractType type, EObject context, CodeFragment varName, Expression initialization) { + CodeFragment.EMPTY; + } + /** * Produces code which implements an assignment operation. * Every generator should be able to at least handle AssignmentOperator.ASSIGN. * left can be used for size inference, but might not exist, for example when copying inner structures. * leftName might be a C expression (for example `(*_result)`), to generate temporary variable names use cVariablePrefix. */ - def CodeFragment generateExpression(AbstractType type, EObject context, Optional left, CodeFragment leftName, CodeFragment cVariablePrefix, AssignmentOperator operator, EObject right) { - return codeFragmentProvider.create('''«leftName» «operator.literal» «right»;'''); + def CodeFragment generateExpression(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, AssignmentOperator operator, CodeWithContext right) { + return codeFragmentProvider.create('''«left.code»«IF right !== null» «operator.literal» «right.code»«ENDIF»;'''); } + /** + * Produces code that reserves static memory (global/stack) for *count* instances. + * Left is a C-array of length at least *count*. + * Produced C-code might be global. + */ + def CodeFragment generateBulkAllocation(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count, boolean isTopLevel); + + /** + * Produces code that assigns *count* instances in left. + * Left is a C-array of length at least *count*. + * Produced C-code is always in a function context. + */ + def CodeFragment generateBulkAssignment(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count); + + /** + * Produces code that bulk copies data from C-array to C-array. + */ + def CodeFragment generateBulkCopyStatements(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count); + /** * Produces header definitions. Called only once. */ @@ -72,6 +89,13 @@ abstract class AbstractTypeGenerator implements IGenerator { return CodeFragment.EMPTY; } + /** + * Produces function definitions. Called only once. + */ + def CodeFragment generateImplementation() { + return CodeFragment.EMPTY; + } + def CodeFragment generateCoercion(CoercionExpression expr, AbstractType from, AbstractType to) { return codeFragmentProvider.create(''' ERROR: CANT COERCE FROM «from» to «to» (expr.eClass = «expr.eClass.name»). THIS IS MOST LIKELY A BUG IN THE COMPILER, PLEASE REPORT @@ -85,4 +109,10 @@ abstract class AbstractTypeGenerator implements IGenerator { def CodeFragment generateHeader(EObject context, AbstractType type) { return CodeFragment.EMPTY; } + /** + * Produces header type implementations, called per different instance of type arguments. + */ + def CodeFragment generateTypeImplementations(EObject context, AbstractType type) { + return CodeFragment.EMPTY; + } } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/CodeFragment.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/CodeFragment.xtend index f9e86e1d..fe9933d7 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/CodeFragment.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/CodeFragment.xtend @@ -20,12 +20,33 @@ import org.eclipse.xtend2.lib.StringConcatenationClient import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode import org.eclipse.xtext.generator.trace.node.IGeneratorNode import org.eclipse.xtext.generator.trace.node.TemplateNode +import org.eclipse.xtext.generator.trace.node.TextNode +import org.eclipse.xtext.generator.trace.node.NewLineNode /** * A code fragment is source code generated by a component generator. */ class CodeFragment extends CompositeGeneratorNode { + static dispatch def String doGetString(IGeneratorNode node) { + node.toString; + } + static dispatch def String doGetString(CompositeGeneratorNode node) { + node.children.map[doGetString].join; + } + static dispatch def String doGetString(TextNode node) { + node.text.toString + } + static dispatch def String doGetString(NewLineNode node) { + "" + } + def getString() { + return doGetString(this); + } + + override toString() { + return getString(); + } static class IncludePath { public static final int ULTRA_LOW_PRIORITY = 0; diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/CodeWithContext.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/CodeWithContext.xtend new file mode 100644 index 00000000..835ca210 --- /dev/null +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/CodeWithContext.xtend @@ -0,0 +1,26 @@ +package org.eclipse.mita.program.generator + +import java.util.Optional +import org.eclipse.emf.ecore.EObject +import org.eclipse.mita.base.typesystem.types.AbstractType +import org.eclipse.xtend.lib.annotations.Accessors + +import static extension org.eclipse.mita.base.types.TypeUtils.ignoreCoercions + +@Accessors +class CodeWithContext { + protected val AbstractType type; + protected val Optional obj; + protected val CodeFragment code; + + new(AbstractType type, Optional obj, CodeFragment code) { + this.type = type; + this.obj = obj; + this.code = code; + } + + override toString() { + return code + ": " + type + } + +} \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/DefaultMainSystemResourceGenerator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/DefaultMainSystemResourceGenerator.xtend new file mode 100644 index 00000000..7fdabf43 --- /dev/null +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/DefaultMainSystemResourceGenerator.xtend @@ -0,0 +1,22 @@ +package org.eclipse.mita.program.generator + +import org.eclipse.mita.program.EventHandlerDeclaration + +class DefaultMainSystemResourceGenerator extends MainSystemResourceGenerator { + + override generateSetup() { + return codeFragmentProvider.create('''''') + } + + override generateEnable() { + return codeFragmentProvider.create('''''') + } + + public def getQueueSizeName() { + return "queueSize"; + } + + override getEventHandlerPayloadQueueSize(EventHandlerDeclaration handler) { + return configuration.getLong(queueSizeName); + } +} diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/EmptyPlatformGeneratorModule.java b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/EmptyPlatformGeneratorModule.java index 10fcd152..2672955b 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/EmptyPlatformGeneratorModule.java +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/EmptyPlatformGeneratorModule.java @@ -41,4 +41,7 @@ public Class bindIPlatformLoggingGenerator( return IPlatformLoggingGenerator.NullImpl.class; } + public Class bindMainSystemResourceGenerator() { + return DefaultMainSystemResourceGenerator.class; + } } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/GeneratorUtils.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/GeneratorUtils.xtend index feaa322a..59a968c8 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/GeneratorUtils.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/GeneratorUtils.xtend @@ -26,7 +26,6 @@ import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.plugin.EcorePlugin import org.eclipse.emf.ecore.resource.Resource import org.eclipse.mita.base.expressions.ElementReferenceExpression -import org.eclipse.mita.base.expressions.FeatureCall import org.eclipse.mita.base.types.AnonymousProductType import org.eclipse.mita.base.types.Event import org.eclipse.mita.base.types.ExceptionTypeDeclaration @@ -36,6 +35,8 @@ import org.eclipse.mita.base.types.Operation import org.eclipse.mita.base.types.Singleton import org.eclipse.mita.base.types.StructureType import org.eclipse.mita.base.types.SumAlternative +import org.eclipse.mita.base.types.SystemResourceEvent +import org.eclipse.mita.base.types.TypeUtils import org.eclipse.mita.base.typesystem.BaseConstraintFactory import org.eclipse.mita.base.typesystem.types.AbstractType import org.eclipse.mita.base.typesystem.types.AtomicType @@ -50,7 +51,6 @@ import org.eclipse.mita.platform.Modality import org.eclipse.mita.platform.Platform import org.eclipse.mita.platform.Sensor import org.eclipse.mita.platform.SystemResourceAlias -import org.eclipse.mita.platform.SystemResourceEvent import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.FunctionDefinition import org.eclipse.mita.program.ModalityAccess @@ -75,7 +75,10 @@ import org.eclipse.xtext.generator.trace.node.TextNode import org.eclipse.xtext.scoping.IScopeProvider import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull -import org.eclipse.mita.base.types.TypeUtils +import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.base.types.TypeReferenceSpecifier +import org.eclipse.mita.base.types.TypeSpecifier +import static extension org.eclipse.mita.base.util.BaseUtils.force import org.eclipse.mita.base.typesystem.infra.MitaBaseResource import org.eclipse.core.runtime.NullProgressMonitor @@ -96,6 +99,10 @@ class GeneratorUtils { @Inject(optional = true) protected IPlatformLoggingGenerator loggingGenerator; + def isTopLevel(EObject obj) { + return (EcoreUtil2.getContainerOfType(obj, Operation) as EObject ?: EcoreUtil2.getContainerOfType(obj, EventHandlerDeclaration)) === null + } + /** * Opens the file at *fileLoc* either absolute or relative to the current project, depending on whether the path is absolute or relative. * In the case of the standalone compiler this will open *fileLoc* relative to the user's command. @@ -273,11 +280,13 @@ class GeneratorUtils { def dispatch getFileBasename(AbstractSystemResource resource) { return '''«resource.baseName?.toFirstUpper»''' - } - + } def dispatch getFileBasename(SystemResourceSetup setup) { return '''«setup.baseName»''' } + def dispatch getFileBasename(EObject obj) { + return '''INVALID''' + } def dispatch getResourceTypeName(Bus sensor) { return '''Bus'''; @@ -312,7 +321,26 @@ class GeneratorUtils { } def dispatch String getBaseName(Operation element) { - return '''«element.name»«FOR p : element.parameters BEFORE '_' SEPARATOR '_'»«p.type.name»«ENDFOR»''' + return '''«element.name»«FOR p : element.parameters BEFORE '_' SEPARATOR '_'»«val t = p.typeSpecifier»«t.toFunctionNamePart(t.separator)»«ENDFOR»''' + } + + def String getSeparator(TypeSpecifier t) { + return new String(newCharArrayOfSize(doGetSeparator(t))).replace(0 as char, "_"); + } + + def dispatch int doGetSeparator(TypeSpecifier t) { + return 0; + } + def dispatch int doGetSeparator(TypeReferenceSpecifier t) { + return (#[-1] + t.typeArguments.map[doGetSeparator]).max + 1 + } + + def dispatch String toFunctionNamePart(TypeSpecifier t, String separator) { + "" + } + def dispatch String toFunctionNamePart(TypeReferenceSpecifier t, String separator) { + val typeArgs = t.typeArguments.map[it.toFunctionNamePart(separator.substring(1))].filter[!nullOrEmpty].force; + (#[t.type.name] + typeArgs).join(separator) } def dispatch String getBaseName(AbstractSystemResource resource) { @@ -520,7 +548,7 @@ class GeneratorUtils { ''' /** * Generated by Eclipse Mita «context.mitaVersion». - * @date «new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())» + * @date «new SimpleDateFormat("yyyy-MM-dd").format(new Date())» */ ''' @@ -615,4 +643,8 @@ class GeneratorUtils { !eventHandlers.empty || !functionDefinitions.empty || !types.empty || !globalVariables.empty } + def boolean needsCast(EObject obj) { + return EcoreUtil2.getContainerOfType(obj, ProgramBlock) !== null; + } + } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/IPlatformEventLoopGenerator.java b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/IPlatformEventLoopGenerator.java index c3efcd25..9d92eccf 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/IPlatformEventLoopGenerator.java +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/IPlatformEventLoopGenerator.java @@ -84,6 +84,9 @@ public interface IPlatformEventLoopGenerator { */ public CodeFragment generateEventHeaderPreamble(CompilationContext context); + + public CodeFragment generateEventLoopHandlerEpilogue(CompilationContext context, EventHandlerDeclaration declaration); + /** * Generates code which is prepended to the Mita_initialize function. This is prepended after generateEventLoopHandlerPreamble and exception variable declaration. * @param context @@ -137,5 +140,10 @@ public CodeFragment generateEnablePreamble(CompilationContext context) { return CodeFragment.EMPTY; } + @Override + public CodeFragment generateEventLoopHandlerEpilogue(CompilationContext context, + EventHandlerDeclaration declaration) { + return CodeFragment.EMPTY; + } } } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/MainSystemResourceGenerator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/MainSystemResourceGenerator.xtend new file mode 100644 index 00000000..8d693c09 --- /dev/null +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/MainSystemResourceGenerator.xtend @@ -0,0 +1,12 @@ +package org.eclipse.mita.program.generator + +import org.eclipse.mita.program.generator.AbstractSystemResourceGenerator +import org.eclipse.mita.program.EventHandlerDeclaration + +abstract class MainSystemResourceGenerator extends AbstractSystemResourceGenerator { + /* Returns log_2(ringbufferSize) for target event handler. + * Will be used to create a ringbuffer of size 2^(returned value). + * This facilitates a really easy ringbuffer implementation. + */ + public def long getEventHandlerPayloadQueueSize(EventHandlerDeclaration handler); +} \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/ProgramDslGenerator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/ProgramDslGenerator.xtend index bfed272a..20775ed2 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/ProgramDslGenerator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/ProgramDslGenerator.xtend @@ -60,6 +60,7 @@ import org.eclipse.xtext.service.DefaultRuntimeModule import org.eclipse.xtext.xbase.lib.Functions.Function1 import static extension org.eclipse.mita.base.util.BaseUtils.force +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull /** * Generates code from your model files on save. @@ -123,6 +124,11 @@ class ProgramDslGenerator extends AbstractGenerator implements IGeneratorOnResou Provider resourceSetProvider; + protected def injectPlatformDependencies(Object obj, Module libraryModule) { + val injector = Guice.createInjector(injectingModule, libraryModule); + injector.injectMembers(obj) + } + override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { resource.resourceSet.doGenerate(fsa); } @@ -131,11 +137,6 @@ class ProgramDslGenerator extends AbstractGenerator implements IGeneratorOnResou return resource.URI.segments.last.startsWith('application.') } - protected def injectPlatformDependencies(Module libraryModule) { - injector = Guice.createInjector(injectingModule, libraryModule); - injector.injectMembers(this) - } - private def produceFile(IFileSystemAccess2 fsa, String path, EObject ctx, CompositeGeneratorNode content) { var root = CodeFragment.cleanNullChildren(content); fsa.generateTracedFile(path, root); @@ -161,6 +162,12 @@ class ProgramDslGenerator extends AbstractGenerator implements IGeneratorOnResou val stdlibUri = libs.filter[it.toString.endsWith(MitaBaseResource.PROGRAM_EXT)] val stdlib = stdlibUri.map[input.getResource(it, true)].filterNull.map[it.contents.filter(Program).head].force; + val someProgram1 = resourcesToCompile.map[it.contents.head].filter(Program).head; + val platform = modelUtils.getPlatform(input, someProgram1); + val platformModule = resourceLoader.loadFromPlugin(platform.eResource, platform.module) as Module; + injectPlatformDependencies(this, platformModule); + + /* * Steps: * 1. Copy all programs @@ -170,6 +177,7 @@ class ProgramDslGenerator extends AbstractGenerator implements IGeneratorOnResou * 5. Generate user code per input model file */ val copyResourceSet = resourceSetProvider.get(); + val untransformedCompilationContext = compilationContextProvider.get(resourcesToCompile.map[it.contents.head.castOrNull(Program)].filterNull, stdlib); val compilationUnits = (resourcesToCompile) .map[x | x.contents.filter(Program).head ] .filterNull @@ -182,7 +190,7 @@ class ProgramDslGenerator extends AbstractGenerator implements IGeneratorOnResou } val copy = x.copy(copyResourceSet); BaseUtils.ignoreChange(copy, [ - transformer.get.transform(copy) + transformer.get.transform(untransformedCompilationContext, copy) ]); return copy; ] @@ -190,14 +198,21 @@ class ProgramDslGenerator extends AbstractGenerator implements IGeneratorOnResou val someProgram = compilationUnits.head; + compilationUnits.forEach[ + // some transformation stages might force evaluation of resource descriptions. + // Here we clear them again. + clearCache(it); + ] compilationUnits.forEach[ doType(it); ] - val platform = modelUtils.getPlatform(input, someProgram); - platform.doType(); + var EObject platformRoot = modelUtils.getPlatform(input, compilationUnits.head); + while(platformRoot.eContainer !== null) { + platformRoot = platformRoot.eContainer; + } - injectPlatformDependencies(resourceLoader.loadFromPlugin(platform.eResource, platform.module) as Module); + doType(platformRoot) val context = compilationContextProvider.get(compilationUnits, stdlib); @@ -239,6 +254,7 @@ class ProgramDslGenerator extends AbstractGenerator implements IGeneratorOnResou ) files += fsa.produceFile('base/MitaGeneratedTypes.h', someProgram, generatedTypeGenerator.generateHeader(context, userTypeFiles)); + files += fsa.produceFile('base/MitaGeneratedTypes.c', someProgram, generatedTypeGenerator.generateImplementation(context, userTypeFiles)); files += getUserFiles(input); @@ -251,6 +267,14 @@ class ProgramDslGenerator extends AbstractGenerator implements IGeneratorOnResou files += systemResourceGenerator.generateAdditionalFiles(fsa, context, resourceOrSetup); } + + def clearCache(EObject obj) { + val resource = obj.eResource; + BaseUtils.getCacheAdapters(resource).forEach[ + it.clearValues(); + ]; + } + def doType(EObject program) { val resource = program.eResource; if(resource instanceof MitaBaseResource) { diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/ProgramDslTraceExtensions.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/ProgramDslTraceExtensions.xtend index 697cdfcb..4b867b29 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/ProgramDslTraceExtensions.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/ProgramDslTraceExtensions.xtend @@ -23,7 +23,11 @@ import org.eclipse.xtext.generator.trace.node.TracedAccessors class ProgramDslTraceExtensions { override location(EObject obj) { - super.location(ProgramCopier.getOrigin(obj) ?: obj); + var original = ProgramCopier.getOrigin(obj); + if(original?.eResource !== null) { + return super.location(original); + } + return super.location(obj); } } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/StatementGenerator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/StatementGenerator.xtend index c41b013d..5fc2eafc 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/StatementGenerator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/StatementGenerator.xtend @@ -48,11 +48,11 @@ import org.eclipse.mita.base.expressions.TypeCastExpression import org.eclipse.mita.base.expressions.UnaryExpression import org.eclipse.mita.base.expressions.ValueRange import org.eclipse.mita.base.expressions.util.ExpressionUtils -import org.eclipse.mita.base.scoping.MitaTypeSystem import org.eclipse.mita.base.types.AnonymousProductType import org.eclipse.mita.base.types.CoercionExpression import org.eclipse.mita.base.types.EnumerationType import org.eclipse.mita.base.types.Expression +import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.InterpolatedStringLiteral import org.eclipse.mita.base.types.NamedProductType import org.eclipse.mita.base.types.Operation @@ -65,6 +65,7 @@ import org.eclipse.mita.base.types.SumSubTypeConstructor import org.eclipse.mita.base.types.SumType import org.eclipse.mita.base.types.TypeAccessor import org.eclipse.mita.base.types.TypeConstructor +import org.eclipse.mita.base.types.TypeSpecifier import org.eclipse.mita.base.types.TypeUtils import org.eclipse.mita.base.types.VirtualFunction import org.eclipse.mita.base.typesystem.BaseConstraintFactory @@ -80,13 +81,13 @@ import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.platform.Modality import org.eclipse.mita.program.ArrayLiteral import org.eclipse.mita.program.ArrayRuntimeCheckStatement +import org.eclipse.mita.program.ConfigurationItemValue import org.eclipse.mita.program.DereferenceExpression import org.eclipse.mita.program.DoWhileStatement import org.eclipse.mita.program.ExceptionBaseVariableDeclaration import org.eclipse.mita.program.ForEachStatement import org.eclipse.mita.program.ForStatement import org.eclipse.mita.program.FunctionDefinition -import org.eclipse.mita.program.GeneratedFunctionDefinition import org.eclipse.mita.program.IfStatement import org.eclipse.mita.program.IsAssignmentCase import org.eclipse.mita.program.IsDeconstructionCase @@ -97,7 +98,6 @@ import org.eclipse.mita.program.LoopBreakerStatement import org.eclipse.mita.program.ModalityAccess import org.eclipse.mita.program.ModalityAccessPreparation import org.eclipse.mita.program.NativeFunctionDefinition -import org.eclipse.mita.program.NewInstanceExpression import org.eclipse.mita.program.NoopStatement import org.eclipse.mita.program.Program import org.eclipse.mita.program.ProgramBlock @@ -107,6 +107,7 @@ import org.eclipse.mita.program.ReturnStatement import org.eclipse.mita.program.ReturnValueExpression import org.eclipse.mita.program.SignalInstance import org.eclipse.mita.program.SourceCodeComment +import org.eclipse.mita.program.SystemResourceSetup import org.eclipse.mita.program.ThrowExceptionStatement import org.eclipse.mita.program.TryStatement import org.eclipse.mita.program.VariableDeclaration @@ -114,6 +115,7 @@ import org.eclipse.mita.program.WhereIsStatement import org.eclipse.mita.program.WhileStatement import org.eclipse.mita.program.generator.internal.GeneratorRegistry import org.eclipse.mita.program.model.ModelUtils +import org.eclipse.xtend2.lib.StringConcatenationClient import org.eclipse.xtext.EcoreUtil2 import org.eclipse.xtext.generator.trace.node.CompositeGeneratorNode import org.eclipse.xtext.generator.trace.node.IGeneratorNode @@ -126,6 +128,7 @@ import static extension org.eclipse.emf.common.util.ECollections.asEList import static extension org.eclipse.mita.base.types.TypeUtils.getConstraintSystem import static extension org.eclipse.mita.base.types.TypeUtils.ignoreCoercions import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull +import org.eclipse.mita.program.ReturnParameterReference class StatementGenerator { @@ -150,12 +153,41 @@ class StatementGenerator { return codeFragmentProvider.create('''CODE CALLED ON NULL'''); } + private def cf(StringConcatenationClient scc) { + codeFragmentProvider.create(scc); + } + private def cf(IGeneratorNode node) { + codeFragmentProvider.create('''«node»'''); + } + @Traced dispatch def IGeneratorNode code(Argument stmt) { '''«stmt.value.code»''' } @Traced dispatch def IGeneratorNode code(StringLiteral stmt) { - '''"«stmt.value»"''' + val printContext = stmt + ?.eContainer?.castOrNull(PrimitiveValueExpression) + ?.eContainer?.castOrNull(Argument) + ?.eContainer?.castOrNull(ElementReferenceExpression) + ?.reference?.castOrNull(GeneratedFunctionDefinition) + ?.name + val setupContext = EcoreUtil2.getContainerOfType(stmt, SystemResourceSetup) as EObject ?: + EcoreUtil2.getContainerOfType(stmt, ConfigurationItemValue) + // don't create complicated stuff for: + // - print (nicer code) + // - setup (easier usage in platform components) + if(printContext == "print" || printContext == "println" || setupContext !== null) { + return '''"«stmt.value»"''' + } + + return ''' + «IF !stmt.isTopLevel»(«typeGenerator.code(stmt, BaseUtils.getType(stmt))») «ENDIF»{ + .data = "«stmt.value»", + .capacity = «stmt.value.length», + .length = «stmt.value.length», + } + ''' + } @Traced dispatch def code(NullLiteral stmt) { @@ -184,9 +216,13 @@ class StatementGenerator { .addHeader('stdbool.h', true); return '''«result»'''; } - + @Traced dispatch def IGeneratorNode code(ArrayLiteral stmt) { - '''{«FOR value: stmt.values SEPARATOR(', ')»«value.code»«ENDFOR»}''' + '''«IF !stmt.isTopLevel»(«typeGenerator.code(stmt, BaseUtils.getType(stmt))») «ENDIF»{ + .data = («typeGenerator.code(stmt, (BaseUtils.getType(stmt) as TypeConstructorType).typeArguments.get(1))»[«stmt.values.length»]) {«FOR value: stmt.values SEPARATOR(', ')»«value.code»«ENDFOR»}, + .capacity = «stmt.values.length», + .length = «stmt.values.length», + }''' } @Traced dispatch def IGeneratorNode code(Literal stmt) { @@ -245,8 +281,44 @@ class StatementGenerator { generator.generateAccessPreparationFor(stmt).addHeader(stmt.systemResource.fileBasename + '.h', false); } - @Traced dispatch def IGeneratorNode code(ArrayAccessExpression stmt) { - '''«stmt.owner.code».data[«stmt.arraySelector.code.noTerminator»]''' + @Traced dispatch def IGeneratorNode code(ArrayAccessExpression stmt) { + val arraySelector = stmt.arraySelector; + if(arraySelector instanceof ValueRange) { + // value ranges should be handled by generator. Return reference to element. + return '''«stmt.owner.code»'''; + } + else { + return '''«stmt.owner.code».data[«stmt.arraySelector.code.noTerminator»]'''; + } + } + + def CodeFragment generateBulkAllocation(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count, boolean isTopLevel) { + if(isGeneratedType(context, left.type)) { + val generator = registry.getGenerator(context.eResource, left.type).castOrNull(AbstractTypeGenerator); + + return generator.generateBulkAllocation(context, cVariablePrefix, left, count, isTopLevel); + } + return cf('''''') + } + def CodeFragment generateBulkAssignment(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count) { + if(isGeneratedType(context, left.type)) { + val generator = registry.getGenerator(context.eResource, left.type).castOrNull(AbstractTypeGenerator); + + return generator.generateBulkAssignment(context, cVariablePrefix, left, count); + } + return cf('''''') + } + def CodeFragment generateBulkCopyStatements(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count) { + if(isGeneratedType(context, left.type)) { + val generator = registry.getGenerator(context.eResource, left.type).castOrNull(AbstractTypeGenerator); + + return generator.generateBulkCopyStatements(context, i, left, right, count); + } + val typeSize = cf('''sizeof(«typeGenerator.code(context, left.type)»)''') + return cf(''' + /* «left.code» = «right.code» */ + memcpy(«left.code», «right.code», «typeSize» * «count»); + ''') } @Traced dispatch def IGeneratorNode code(ArrayRuntimeCheckStatement stmt) { @@ -259,16 +331,16 @@ class StatementGenerator { val arrayLength = codeFragmentProvider.create('''«variableName».length'''); if(arraySelector instanceof ValueRange) { if(arraySelector.lowerBound !== null) { - checks += codeFragmentProvider.create('''«arraySelector.lowerBound.code.noTerminator» < 0'''); + checks += cf('''«arraySelector.lowerBound.code.noTerminator» < 0'''); } if(arraySelector.upperBound !== null) { - checks += codeFragmentProvider.create('''«arraySelector.upperBound.code.noTerminator» >= «arrayLength»'''); + checks += cf('''«arraySelector.upperBound.code.noTerminator» >= «arrayLength»'''); } if(arraySelector.lowerBound !== null && arraySelector.upperBound !== null) { - checks += codeFragmentProvider.create('''«arraySelector.lowerBound.code.noTerminator» > «arraySelector.upperBound.code.noTerminator»'''); + checks += cf('''«arraySelector.lowerBound.code.noTerminator» > «arraySelector.upperBound.code.noTerminator»'''); } } else { - checks += codeFragmentProvider.create('''«arrayLength» <= «arraySelector.code.noTerminator»'''); + checks += cf('''«arrayLength» <= «arraySelector.code.noTerminator»'''); } return ''' @@ -307,7 +379,7 @@ class StatementGenerator { } if(TypeUtils.isGeneratedType(expr, coercedType)) { val generator = registry.getGenerator(expr.eResource, coercedType) as AbstractTypeGenerator; - return '''«generator.generateCoercion(expr, expressionType, coercedType)»'''; + return '''«generator.generateCoercion(expr, expressionType, coercedType)»'''; } if(coercedType instanceof TypeConstructorType) { // can't really cast these. This should only happen for literals. @@ -401,7 +473,7 @@ class StatementGenerator { .getConstraintSystem(callSite.eResource) ?.getUserData(constructingType, BaseConstraintFactory.ECLASS_KEY) == "Singleton"; - val constructedStruct = codeFragmentProvider.create(''' + val constructedStruct = cf(''' «IF returnTypeIsSumType || needCast»(«dataType»)«ENDIF» { «FOR i_arg: arguments.tail.indexed» «IF hasAccessors»«accessor(callSite, eConstructingType, i_arg.value.parameter, ".", " = ").apply(i_arg.key)»«ENDIF»«i_arg.value.value.code.noTerminator»«IF i_arg.key < arguments.length - 1»,«ENDIF» @@ -421,6 +493,15 @@ class StatementGenerator { return #["NamedProductType", "StructureType"].findFirst[it == eClass] !== null; } + @Traced def IGeneratorNode generateGeneratedFunctionCall(ElementReferenceExpression funCall, CodeWithContext target, GeneratedFunctionDefinition function) { + val generator = registry.getGenerator(function); + if(generator === null) { + // contract: no generator means NOOP. + return '''''' + } + '''«generator.generate(target, funCall).noTerminator»'''; + } + @Traced dispatch def IGeneratorNode code(ElementReferenceExpression stmt) { val ref = stmt.reference val id = ref?.baseName @@ -432,12 +513,13 @@ class StatementGenerator { if (ref instanceof VirtualFunction) { '''«generateVirtualFunctionCall(stmt, ref, arguments)»''' } else if (ref instanceof FunctionDefinition) { - '''«ref.generateFunctionCall(codeFragmentProvider.create('''NULL''').addHeader("stdlib.h", true), stmt)»''' + '''«ref.generateFunctionCall(cf('''NULL''').addHeader("stdlib.h", true), stmt)»''' } else if (ref instanceof GeneratedFunctionDefinition) { - '''«registry.getGenerator(ref)?.generate(stmt, null)»'''; + // target is null if we aren't part of an assignment + '''«generateGeneratedFunctionCall(stmt, null, ref)»'''; } else if(ref instanceof NativeFunctionDefinition) { if(ref.checked) { - '''«ref.generateNativeFunctionCallChecked(codeFragmentProvider.create('''NULL'''), stmt)»''' + '''«ref.generateNativeFunctionCallChecked(cf('''NULL'''), stmt)»''' } else { '''«ref.generateNativeFunctionCallUnchecked(stmt)»''' } @@ -511,7 +593,7 @@ class StatementGenerator { val generator = registry.getGenerator(stmt.eResource, type).castOrNull(AbstractTypeGenerator); if (generator !== null) { val varName = codeFragmentProvider.create('''«stmt»'''); - return '''«generator.generateExpression(type, stmt, Optional.empty, varName, varName, null, null)»'''; + return '''«generator.generateExpression(stmt, varName, new CodeWithContext(type, Optional.empty, varName), AssignmentOperator.ASSIGN, null)»'''; } else { throw new CoreException( new Status(IStatus.ERROR, "org.eclipse.mita.program", @@ -525,7 +607,7 @@ class StatementGenerator { } @Traced dispatch def IGeneratorNode code(Expression stmt) { - '''/* ERROR: unsupported expression «stmt» */''' + '''ERROR: unsupported expression «stmt»''' } @Traced dispatch def IGeneratorNode code(ExpressionStatement stmt) { @@ -533,85 +615,103 @@ class StatementGenerator { } - - def IGeneratorNode generateFunCallStmt(IGeneratorNode variableName, AbstractType type, ElementReferenceExpression initialization) { + def IGeneratorNode generateFunCallStmt(CodeWithContext left, ElementReferenceExpression initialization) { val reference = initialization.reference; val arguments = ExpressionUtils.getArgumentsOfElementReferenceExpression(initialization); if (reference instanceof VirtualFunction) { - return codeFragmentProvider.create(''' - «variableName» = «generateVirtualFunctionCall(initialization, reference, arguments).noTerminator»; + return cf(''' + «left.code» = «generateVirtualFunctionCall(initialization, reference, arguments).noTerminator»; ''') } else if (reference instanceof FunctionDefinition) { - return codeFragmentProvider.create(''' - «generateFunctionCall(reference, codeFragmentProvider.create('''&«variableName»'''), initialization).noTerminator»; + return cf(''' + «generateFunctionCall(reference, cf('''&«left.code»'''), initialization).noTerminator»; ''') } else if (reference instanceof GeneratedFunctionDefinition) { - return codeFragmentProvider.create(''' - «registry.getGenerator(reference).generate(initialization, variableName).noTerminator»; + return cf(''' + «generateGeneratedFunctionCall(initialization, left, reference)»; ''') } else if(reference instanceof NativeFunctionDefinition) { if(reference.checked) { - return codeFragmentProvider.create(''' - «reference.generateNativeFunctionCallChecked(codeFragmentProvider.create('''&«variableName»'''), initialization).noTerminator»; + return cf(''' + «generateNativeFunctionCallChecked(reference, cf('''&«left.code»'''), initialization).noTerminator»; ''') } else { - return codeFragmentProvider.create(''' - «variableName» = «reference.generateNativeFunctionCallUnchecked(initialization).noTerminator»;''') + return cf(''' + «left.code» = «generateNativeFunctionCallUnchecked(reference, initialization).noTerminator»;''') } } } + // TODO: remove code duplication with generateVariableDeclaration(...) dispatch def IGeneratorNode initializationCode(VariableDeclaration stmt) { - val varName = codeFragmentProvider.create('''«stmt.name»'''); - return initializationCode(BaseUtils.getType(stmt), stmt, Optional.of(stmt), varName, varName, AssignmentOperator.ASSIGN, stmt.initialization, false); - } - dispatch def IGeneratorNode initializationCode(AssignmentExpression expr) { - val varRef = codeFragmentProvider.create('''«expr.varRef.code.noTerminator»'''); - return initializationCode(BaseUtils.getType(expr.varRef), expr.varRef, Optional.of(expr), varRef, varRef, expr.operator, expr.expression, true); + val varName = cf('''«stmt.name»'''); + val rightSide = if(stmt.initialization !== null) { + new CodeWithContext(BaseUtils.getType(stmt.initialization), Optional.of(stmt.initialization), cf(stmt.initialization.code)); + } + return initializationCode( + stmt, + varName, + new CodeWithContext(BaseUtils.getType(stmt), Optional.of(stmt), varName), + AssignmentOperator.ASSIGN, + rightSide, + false + ); } - dispatch def IGeneratorNode initializationCode(ReturnValueExpression expr) { - val varRef = codeFragmentProvider.create('''«expr.varRef.code.noTerminator»'''); - val cPrefix = codeFragmentProvider.create('''_result'''); - return initializationCode(BaseUtils.getType(expr.varRef), expr.varRef, Optional.of(expr), varRef, cPrefix, expr.operator, expr.expression, true); + + dispatch def IGeneratorNode initializationCode(ReturnValueExpression expr) { + val varName = cf('''«expr.varRef.code.noTerminator»'''); + return initializationCode( + expr.varRef, + cf('''_result'''), + new CodeWithContext(BaseUtils.getType(expr.varRef), Optional.of(expr.varRef), varName), + expr.operator, + new CodeWithContext(BaseUtils.getType(expr.expression), Optional.of(expr.expression), cf(expr.expression.code)), + true + ); } - def IGeneratorNode initializationCode(AbstractType type, EObject context, Optional target, CodeFragment varName, CodeFragment cVariablePrefix, AssignmentOperator op, Expression initialization, boolean alwaysGenerate) { - if (isGeneratedType(context, type)) { - val generator = registry.getGenerator(context.eResource, type).castOrNull(AbstractTypeGenerator); - if (initialization instanceof NewInstanceExpression) { - return generator.generateNewInstance(type, initialization); - } else if (initialization instanceof ArrayAccessExpression) { - return generator.generateExpression(type, context, target, varName, cVariablePrefix, op, initialization); - } else if (initialization instanceof ElementReferenceExpression && (initialization as ElementReferenceExpression).isOperationCall) { - return generateFunCallStmt(varName, type, initialization as ElementReferenceExpression); - } else if(initialization instanceof PrimitiveValueExpression) { - if((initialization.value instanceof ArrayLiteral || initialization.value instanceof StringLiteral) - && target.orElse(null) instanceof VariableDeclaration - ) { - return CodeFragment.EMPTY; - } - } else { - return generator.generateExpression(type, context, target, varName, cVariablePrefix, op, initialization); - } - return generator.generateExpression(type, context, target, varName, cVariablePrefix, op, initialization); +// public def IGeneratorNode initializationCode(EObject target, CodeFragment varName, AssignmentOperator op, Expression initialization, boolean alwaysGenerate) { +// return initializationCode(BaseUtils.getType(target), target, varName, op, initialization, alwaysGenerate); +// } + + dispatch def IGeneratorNode initializationCode(AssignmentExpression expr) { + val varName = cf('''«expr.varRef.code.noTerminator»'''); + return initializationCode( + expr.varRef, + varName, + new CodeWithContext(BaseUtils.getType(expr.varRef), Optional.of(expr.varRef), varName), + expr.operator, + new CodeWithContext(BaseUtils.getType(expr.expression), Optional.of(expr.expression), cf(expr.expression.code)), + true + ); + } + def IGeneratorNode initializationCode(EObject context, CodeFragment tempVarName, CodeWithContext left, AssignmentOperator op, CodeWithContext right, boolean alwaysGenerate) { + // TODO handle Optional.none + val initialization = right?.obj?.orElse(null); + if (isGeneratedType(context, left.type)) { + val generator = registry.getGenerator(context.eResource, left.type).castOrNull(AbstractTypeGenerator); + + if (initialization instanceof ElementReferenceExpression && (initialization as ElementReferenceExpression).isOperationCall) { + return generateFunCallStmt(left, initialization as ElementReferenceExpression); + } + return generator.generateExpression(context, tempVarName, left, op, right); } else if (initialization instanceof ElementReferenceExpression) { if(initialization.isOperationCall) { - return generateFunCallStmt(varName, type, initialization); + return generateFunCallStmt(left, initialization); } else { - return context.trace('''«varName» «op» «initialization.code.noTerminator»;'''); + return context.trace('''«left.code» «op» «right.code.noTerminator»;'''); } } else if(initialization instanceof ModalityAccess) { - return context.trace('''«varName» «op» «initialization.code.noTerminator»;'''); - } else if(alwaysGenerate) { - return context.trace('''«varName» «op» «initialization.code.noTerminator»;'''); + return context.trace('''«left.code» «op» «right.code.noTerminator»;'''); + } else if(alwaysGenerate && right !== null) { + return context.trace('''«left.code» «op» «right.code.noTerminator»;'''); } return CodeFragment.EMPTY; } - - + dispatch def IGeneratorNode code(ReturnParameterDeclaration stmt) { return CodeFragment.EMPTY; } @@ -621,7 +721,7 @@ class StatementGenerator { } dispatch def IGeneratorNode code(ExceptionBaseVariableDeclaration stmt) { - return codeFragmentProvider.create(''' + return cf(''' «exceptionGenerator.exceptionType» «stmt.name» = NO_EXCEPTION; «IF stmt.needsReturnFromTryCatch» bool returnFromWithinTryCatch = false; @@ -635,7 +735,7 @@ class StatementGenerator { BaseUtils.getType(stmt), stmt, Optional.of(stmt), - codeFragmentProvider.create('''«stmt.name»'''), + cf('''«stmt.name»'''), stmt.initialization, stmt.eContainer instanceof Program ); @@ -658,10 +758,6 @@ class StatementGenerator { if (TypeUtils.isGeneratedType(context, type)) { val generator = registry.getGenerator(context.eResource, type).castOrNull(AbstractTypeGenerator); result.children += generator.generateVariableDeclaration(type, context, varName, initialization, isTopLevel); - if(initialization instanceof PrimitiveValueExpression && ( - type.name == MitaTypeSystem.ARRAY_TYPE || type.name == MitaTypeSystem.STRING)) { - initializationDone = true; - } } else if (initialization instanceof ElementReferenceExpression) { val ref = initialization.reference; // Assignment from functions is done by declaring, then passing in a reference @@ -669,35 +765,35 @@ class StatementGenerator { // constructors of structural types are done directly !(ref instanceof TypeConstructor) ) { - result.children += codeFragmentProvider.create('''«type.getCtype(context)» «varName»;'''); + result.children += cf('''«type.getCtype(context)» «varName»;'''); } else { // copy assigmnent // since type != generatedType we can copy with assignment - result.children += codeFragmentProvider.create('''«type.getCtype(context)» «varName» = «initialization.code.noTerminator»;'''); + result.children += cf('''«type.getCtype(context)» «varName» = «initialization.code.noTerminator»;'''); initializationDone = true; } // constant assignments and similar get here } else if(initialization instanceof ModalityAccess) { - result.children += codeFragmentProvider.create('''«type.getCtype(context)» «varName»;'''); + result.children += cf('''«type.getCtype(context)» «varName»;'''); } else { if (initialization !== null) { - result.children += codeFragmentProvider.create('''«type.getCtype(context)» «varName» = «initialization.code.noTerminator»;'''); + result.children += cf('''«type.getCtype(context)» «varName» = «initialization.code.noTerminator»;'''); } else if (type instanceof ProdType || type instanceof org.eclipse.mita.base.typesystem.types.SumType) { - result.children += codeFragmentProvider.create('''«type.getCtype(context)» «varName» = {0};'''); + result.children += cf('''«type.getCtype(context)» «varName» = {0};'''); } else if (type instanceof NumericType) { - result.children += codeFragmentProvider.create('''«type.getCtype(context)» «varName» = 0;'''); + result.children += cf('''«type.getCtype(context)» «varName» = 0;'''); } else if(type instanceof AtomicType) { // init is zero, type is atomic, but not generated // -> type is bool if(type.name == "bool") { - result.children += codeFragmentProvider.create('''«type.getCtype(context)» «varName» = false;'''); + result.children += cf('''«type.getCtype(context)» «varName» = false;'''); } else { - result.children += codeFragmentProvider.create('''«type.getCtype(context)» «varName» = ERROR unsupported initialization;'''); + result.children += cf('''«type.getCtype(context)» «varName» = ERROR unsupported initialization;'''); } } else { - result.children += codeFragmentProvider.create('''«type.getCtype(context)» «varName» = ERROR unsupported initialization;'''); + result.children += cf('''«type.getCtype(context)» «varName» = ERROR unsupported initialization;'''); } // all of the above did initialization initializationDone = true; @@ -709,11 +805,17 @@ class StatementGenerator { // generate initialization if(!initializationDone) { - result.children += codeFragmentProvider.create('''«"\n"»'''); + result.children += cf('''«"\n"»'''); // TODO: remove code duplication with initializationCode(VariableDeclaration) - result.children += initializationCode(type, context, varDecl.map[it], varName, varName, AssignmentOperator.ASSIGN, initialization, false).noNewline.noTerminator; - result.children += codeFragmentProvider.create('''«";"»'''); - + result.children += initializationCode( + context, + varName, + new CodeWithContext(type, varDecl.map[it], varName), + AssignmentOperator.ASSIGN, + if(initialization !== null) { new CodeWithContext(BaseUtils.getType(initialization), Optional.of(initialization), cf(initialization.code)) }, + false + ).noNewline.noTerminator; + result.children += cf('''«";"»'''); } return result; @@ -738,19 +840,23 @@ class StatementGenerator { if (ModelUtils.isInTryCatchFinally(stmt)) { ''' // THROW «stmt.exceptionType.name» - exception = «codeFragmentProvider.create('''«stmt.exceptionType.baseName»''').addHeader('MitaExceptions.h', true)»; + exception = «cf('''«stmt.exceptionType.baseName»''').addHeader('MitaExceptions.h', true)»; break; ''' } else { ''' // THROW «stmt.exceptionType.name» - return «codeFragmentProvider.create('''«stmt.exceptionType.baseName»''').addHeader('MitaExceptions.h', true)»; + return «cf('''«stmt.exceptionType.baseName»''').addHeader('MitaExceptions.h', true)»; ''' } } - + + dispatch def IGeneratorNode code(TypeSpecifier type) { + return cf('''«getCtype(BaseUtils.getType(type), type)»'''); + } + @Traced dispatch def IGeneratorNode code(TryStatement stmt) { - val bool = codeFragmentProvider.create('''bool''').addHeader('stdbool.h', true); + val bool = cf('''bool''').addHeader('stdbool.h', true); ''' // TRY returnFromWithinTryCatch = false; @@ -1071,7 +1177,7 @@ class StatementGenerator { private def getCtype(AbstractType type, EObject context) { val result = if(type instanceof TypeVariable) { - codeFragmentProvider.create('''void*''') + cf('''void*''') } else { typeGenerator.code(context, type); diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/TypeGenerator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/TypeGenerator.xtend index 6a2ae261..44061c48 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/TypeGenerator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/TypeGenerator.xtend @@ -99,7 +99,8 @@ class TypeGenerator implements IGenerator { // } public dispatch def CodeFragment code(EObject context, IntegerType type) { - var result = codeFragmentProvider.create('''«type.CName»''') + var result = codeFragmentProvider.create('''«type.CName»'''); + result.addHeader("inttypes.h", true); return result; } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/GeneratedTypeGenerator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/GeneratedTypeGenerator.xtend index 46913714..5939abc1 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/GeneratedTypeGenerator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/GeneratedTypeGenerator.xtend @@ -51,7 +51,27 @@ class GeneratedTypeGenerator { ].values.map[it.head] SEPARATOR("\n")» «type_generator.value.generateHeader(context.allUnits.head, type_generator.key)» «ENDFOR» + «FOR type_generator : generatorsWithTypeSpecs.groupBy[ + it.value.generateTypeSpecifier(it.key, context.allUnits.head).toString + ].values.map[it.head] SEPARATOR("\n")» + «type_generator.value.generateTypeImplementations(context.allUnits.head, type_generator.key)» + «ENDFOR» ''').addHeader(userTypeFiles.map[new IncludePath(it, false)]) .toHeader(context, 'MITA_GENERATED_TYPES_H') } + + def generateImplementation(CompilationContext context, List userTypeFiles) { + val generatedTypes = context.getAllGeneratedTypesUsed().filterNull.force; + val generators = generatedTypes.groupBy[it.name].values.map[it.head].map[registry.getGenerator(context.allUnits.head.eResource, it).castOrNull(AbstractTypeGenerator)].filterNull.toList; + + return codeFragmentProvider.create(''' + «FOR generator: generators SEPARATOR("\n")» + «generator.generateImplementation()» + «ENDFOR» + «"\n"» + ''') + .addHeader("MitaGeneratedTypes.h", false) + .addHeader(userTypeFiles.map[new IncludePath(it, false)]) + .toImplementation(context); + } } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/GeneratorRegistry.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/GeneratorRegistry.xtend index f4ac24a3..f3c2247c 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/GeneratorRegistry.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/GeneratorRegistry.xtend @@ -20,16 +20,17 @@ import com.google.common.cache.LoadingCache import com.google.inject.Inject import com.google.inject.Singleton import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.GeneratedType +import org.eclipse.mita.base.types.TypeUtils +import org.eclipse.mita.base.typesystem.BaseConstraintFactory import org.eclipse.mita.base.typesystem.types.AbstractType import org.eclipse.mita.platform.AbstractSystemResource -import org.eclipse.mita.program.GeneratedFunctionDefinition import org.eclipse.mita.program.generator.AbstractFunctionGenerator import org.eclipse.mita.program.generator.AbstractSystemResourceGenerator import org.eclipse.mita.program.generator.AbstractTypeGenerator import org.eclipse.mita.program.generator.IGenerator import org.eclipse.mita.program.resource.PluginResourceLoader -import org.eclipse.mita.base.typesystem.BaseConstraintFactory import org.eclipse.mita.base.types.TypeUtils /** diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/SystemResourceHandlingGenerator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/SystemResourceHandlingGenerator.xtend index dfe83d1e..aa119c71 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/SystemResourceHandlingGenerator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/SystemResourceHandlingGenerator.xtend @@ -16,12 +16,12 @@ package org.eclipse.mita.program.generator.internal import com.google.inject.Inject import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.mita.base.types.SystemResourceEvent import org.eclipse.mita.base.typesystem.types.AbstractType import org.eclipse.mita.base.typesystem.types.FunctionType import org.eclipse.mita.base.typesystem.types.TypeConstructorType import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.platform.AbstractSystemResource -import org.eclipse.mita.platform.SystemResourceEvent import org.eclipse.mita.program.SystemEventSource import org.eclipse.mita.program.SystemResourceSetup import org.eclipse.mita.program.generator.CodeFragmentProvider @@ -221,6 +221,8 @@ class SystemResourceHandlingGenerator { eventSource.eContainer as AbstractSystemResource; } else if(eventSource instanceof AbstractSystemResource) { eventSource; + } else if(eventSource instanceof SystemResourceSetup) { + eventSource.type } else { return false; } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/UserCodeFileGenerator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/UserCodeFileGenerator.xtend index 2384c5c0..e4169be9 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/UserCodeFileGenerator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/internal/UserCodeFileGenerator.xtend @@ -25,6 +25,7 @@ import org.eclipse.mita.platform.SystemSpecification import org.eclipse.mita.program.FunctionDefinition import org.eclipse.mita.program.NativeFunctionDefinition import org.eclipse.mita.program.Program +import org.eclipse.mita.program.generator.AbstractTypeGenerator import org.eclipse.mita.program.generator.CodeFragment.IncludePath import org.eclipse.mita.program.generator.CodeFragmentProvider import org.eclipse.mita.program.generator.CompilationContext @@ -32,10 +33,11 @@ import org.eclipse.mita.program.generator.GeneratorUtils import org.eclipse.mita.program.generator.IPlatformEventLoopGenerator import org.eclipse.mita.program.generator.IPlatformExceptionGenerator import org.eclipse.mita.program.generator.StatementGenerator +import org.eclipse.mita.program.model.ModelUtils import org.eclipse.xtext.EcoreUtil2 +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull import static extension org.eclipse.mita.program.generator.internal.ProgramCopier.getOrigin -import org.eclipse.mita.program.model.ModelUtils class UserCodeFileGenerator { @@ -56,7 +58,10 @@ class UserCodeFileGenerator { @Inject protected StatementGenerator statementGenerator - + + @Inject + protected GeneratorRegistry generatorRegistry + /** * Generates custom types used by the application. */ @@ -158,7 +163,11 @@ class UserCodeFileGenerator { val type = BaseUtils.getType(it); return !ModelUtils.isStructuralType(type, it); ]» - «statementGenerator.initializationCode(variable)» + «val type = BaseUtils.getType(variable)» + «val generator = generatorRegistry.getGenerator(program.eResource, type)?.castOrNull(AbstractTypeGenerator)» + «IF generator !== null» + «generator.generateGlobalInitialization(type, variable, codeFragmentProvider.create('''«variable.name»'''), variable.initialization)» + «ENDIF» «generateExceptionHandler(null, "exception")» «ENDFOR» @@ -166,20 +175,28 @@ class UserCodeFileGenerator { } ''') } + + + private def generateEventHandlers(CompilationContext context, Program program) { val exceptionType = exceptionGenerator.exceptionType; return codeFragmentProvider.create(''' «FOR handler : program.eventHandlers» - «exceptionType» «handler.handlerName»(«eventLoopGenerator.generateEventLoopHandlerSignature(context)») - { + «exceptionType» «handler.handlerName»_worker() + { + «statementGenerator.code(handler.block).noBraces» + return NO_EXCEPTION; + } - «eventLoopGenerator.generateEventLoopHandlerPreamble(context, handler)» - «statementGenerator.code(handler.block).noBraces» - - return NO_EXCEPTION; - } - + «exceptionType» «handler.handlerName»(«eventLoopGenerator.generateEventLoopHandlerSignature(context)») + { + «exceptionType» exception = NO_EXCEPTION; + «eventLoopGenerator.generateEventLoopHandlerPreamble(context, handler)» + exception = «handler.handlerName»_worker(); + «eventLoopGenerator.generateEventLoopHandlerEpilogue(context, handler)» + return NO_EXCEPTION; + } «ENDFOR» ''') .addHeader('MitaExceptions.h', false); diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AbstractTransformationStage.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AbstractTransformationStage.xtend index 5d887e92..7b80caf6 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AbstractTransformationStage.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AbstractTransformationStage.xtend @@ -24,6 +24,7 @@ import org.eclipse.mita.program.ProgramBlock import org.eclipse.mita.program.generator.GeneratorUtils import org.eclipse.mita.program.generator.internal.ProgramCopier import org.eclipse.xtext.scoping.IScopeProvider +import org.eclipse.mita.program.generator.CompilationContext abstract class AbstractTransformationStage { @@ -50,8 +51,14 @@ abstract class AbstractTransformationStage { public static final int ORDER_VERY_LATE = 900; public static final int ORDER_CUSTOM_STUFF = 1100; + static def before(int x) { + return x - 10; + } + static def afterwards(int x) { + return x + 10; + } - def transform(ITransformationPipelineInfoProvider pipeline, Program program) { + def transform(ITransformationPipelineInfoProvider pipeline, CompilationContext context, Program program) { pipelineInfoProvider = pipeline; program.doTransform(); diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddEventHandlerRingbufferStage.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddEventHandlerRingbufferStage.xtend new file mode 100644 index 00000000..366a9dbf --- /dev/null +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddEventHandlerRingbufferStage.xtend @@ -0,0 +1,189 @@ +/******************************************************************************** + * Copyright (c) 2017, 2018 Bosch Connected Devices and Solutions GmbH. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * Contributors: + * Bosch Connected Devices and Solutions GmbH - initial contribution + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +package org.eclipse.mita.program.generator.transformation + +import com.google.inject.Inject +import org.eclipse.emf.ecore.util.EcoreUtil +import org.eclipse.mita.base.expressions.ExpressionsFactory +import org.eclipse.mita.base.expressions.ExpressionsPackage +import org.eclipse.mita.base.types.GeneratedFunctionDefinition +import org.eclipse.mita.base.types.NullTypeSpecifier +import org.eclipse.mita.base.types.PresentTypeSpecifier +import org.eclipse.mita.base.types.SystemResourceEvent +import org.eclipse.mita.base.types.Type +import org.eclipse.mita.base.types.TypesFactory +import org.eclipse.mita.base.types.TypesPackage +import org.eclipse.mita.base.typesystem.types.TypeVariable +import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.platform.AbstractSystemResource +import org.eclipse.mita.platform.SystemSpecification +import org.eclipse.mita.program.EventHandlerDeclaration +import org.eclipse.mita.program.Program +import org.eclipse.mita.program.ProgramFactory +import org.eclipse.mita.program.SystemEventSource +import org.eclipse.mita.program.SystemResourceSetup +import org.eclipse.mita.program.VariableDeclaration +import org.eclipse.mita.program.generator.CompilationContext +import org.eclipse.mita.program.generator.GeneratorUtils +import org.eclipse.mita.program.generator.IComponentConfiguration +import org.eclipse.mita.program.generator.MainSystemResourceGenerator +import org.eclipse.mita.program.generator.internal.MapBasedComponentConfiguration +import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.xtext.naming.QualifiedName +import org.eclipse.xtext.scoping.IScopeProvider + +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull +import static extension org.eclipse.mita.base.util.BaseUtils.computeOrigin + +class AddEventHandlerRingbufferStage extends AbstractTransformationStage { + + @Inject + IScopeProvider scopeProvider + + @Inject + protected extension GeneratorUtils + + @Inject(optional=true) + protected MainSystemResourceGenerator queueSizeProvider + + override getOrder() { + return before(AddExceptionVariableStage.ORDER); + } + + // HACK for preparation + protected def IComponentConfiguration getConfiguration(CompilationContext context, AbstractSystemResource component, SystemResourceSetup setup) { + return new MapBasedComponentConfiguration(component, context, setup); + } + + override transform(ITransformationPipelineInfoProvider pipeline, CompilationContext context, Program program) { + val componentAndSetup = context.platform.getComponentAndSetup(context); + val component = componentAndSetup.key; + val setup = componentAndSetup.value; + + queueSizeProvider.prepare(context, component, setup, getConfiguration(context, component, setup), #[]); + return super.transform(pipeline, context, program); + } + + protected dispatch def void doTransform(EventHandlerDeclaration decl) { + val varDecl = addRingbufferDeclaration(decl); + if(varDecl === null) { + return; + } + addRingbufferPop(decl, varDecl); + } + + protected def void addRingbufferPop(EventHandlerDeclaration decl, VariableDeclaration ringBuffer) { + val pf = ProgramFactory.eINSTANCE; + val tf = TypesFactory.eINSTANCE; + val ef = ExpressionsFactory.eINSTANCE; + + val block = decl.block; + + val scope = scopeProvider.getScope(decl, ExpressionsPackage.eINSTANCE.elementReferenceExpression_Reference); + val popFunctions = scope.getElements(QualifiedName.create("pop")) + .map[it.EObjectOrProxy] + .filter(GeneratedFunctionDefinition) + .filter[it.generator.contains("RingbufferGenerator")]; + val popFunction = popFunctions.head; + + if(popFunction === null) { + println("function 'pop' not in scope"); + return; + } + + val popCallExpression = ef.createElementReferenceExpression; + popCallExpression.reference = popFunction; + + val rbReferenceArg = ef.createArgument; + val rbReference = ef.createElementReferenceExpression; + rbReference.reference = ringBuffer; + rbReferenceArg.value = rbReference; + popCallExpression.arguments += rbReferenceArg; + popCallExpression.operationCall = true; + + val popCallStmts = if(decl.payload === null) { + val stmt = ef.createExpressionStatement; + stmt.expression = popCallExpression; + #[stmt]; + } + else { + val vdecl = pf.createEventHandlerVariableDeclaration; + vdecl.name = decl.payload.name; + vdecl.initialization = popCallExpression; + vdecl.typeSpecifier = tf.createNullTypeSpecifier; + + #[vdecl as VariableDeclaration]; + } + + block.content.addAll(0, popCallStmts); + } + + protected def VariableDeclaration addRingbufferDeclaration(EventHandlerDeclaration decl) { + val type = BaseUtils.getType(decl.event.computeOrigin); + if(type === null || type instanceof TypeVariable) { + // no payload for this event --> free type var + return null; + } + + val program = EcoreUtil2.getContainerOfType(decl, Program); + if(program === null) { + return null; + } + + val eventTypeSpec = decl.event.castOrNull(SystemEventSource)?.source?.typeSpecifier; + if(eventTypeSpec === null || eventTypeSpec instanceof NullTypeSpecifier) { + println("Event has type but is not linked"); + return null; + } + + val scope = scopeProvider.getScope(decl, TypesPackage.eINSTANCE.typeReferenceSpecifier_Type); + val rbTypeDescription = scope.getElements(QualifiedName.create("ringbuffer")).head; + val rbType = rbTypeDescription?.EObjectOrProxy?.castOrNull(Type); + if(rbType === null || rbType instanceof NullTypeSpecifier) { + println("ringbuffer not found"); + return null; + } + + val pf = ProgramFactory.eINSTANCE; + val tf = TypesFactory.eINSTANCE; + val ef = ExpressionsFactory.eINSTANCE; + + // let rb_everyButtonOnePressed... + val rbDeclaration = pf.createVariableDeclaration; + rbDeclaration.name = "rb_" + decl.baseName; + rbDeclaration.writeable = false; + + // : ringbuffer<... + val rbTypeSpecifier = tf.createTypeReferenceSpecifier; + rbTypeSpecifier.type = rbType; + // bool, ... + rbTypeSpecifier.typeArguments += EcoreUtil.copy(eventTypeSpec) as PresentTypeSpecifier; + + // 10>; + val sizeTypeSpecifier = tf.createTypeExpressionSpecifier; + val sizeExpression = ef.createPrimitiveValueExpression; + val sizeLiteral = ef.createIntLiteral; + sizeLiteral.value = queueSizeProvider.getEventHandlerPayloadQueueSize(decl); + sizeExpression.value = sizeLiteral; + sizeTypeSpecifier.value = sizeExpression; + rbTypeSpecifier.typeArguments += sizeTypeSpecifier; + + rbDeclaration.typeSpecifier = rbTypeSpecifier; + + program.globalVariables += rbDeclaration; + + return rbDeclaration; + } + +} diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddExceptionVariableStage.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddExceptionVariableStage.xtend index 606c0252..ac07d6d8 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddExceptionVariableStage.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/AddExceptionVariableStage.xtend @@ -20,8 +20,10 @@ import org.eclipse.xtext.EcoreUtil2 class AddExceptionVariableStage extends AbstractTransformationStage { + public static val ORDER = ORDER_EARLY + override getOrder() { - ORDER_EARLY + return ORDER; } protected dispatch def void doTransform(ProgramBlock block) { diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/CoerceTypesStage.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/CoerceTypesStage.xtend index 7bfc2ef6..ea1dd241 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/CoerceTypesStage.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/CoerceTypesStage.xtend @@ -40,6 +40,7 @@ import org.eclipse.xtext.EcoreUtil2 import org.eclipse.xtext.scoping.IScopeProvider import static extension org.eclipse.mita.base.util.BaseUtils.computeOrigin +import org.eclipse.mita.program.generator.CompilationContext class CoerceTypesStage extends AbstractTransformationStage { @@ -58,7 +59,7 @@ class CoerceTypesStage extends AbstractTransformationStage { || #[AssignmentExpression, Argument, ReturnValueExpression].exists[it.isAssignableFrom(obj.class)] } - override transform(ITransformationPipelineInfoProvider pipeline, Program program) { + override transform(ITransformationPipelineInfoProvider pipeline, CompilationContext context, Program program) { constraintFactory.typeRegistry.isLinking = true; // we create a copy here because // - we want all subtype constraints to get coercions diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/GroupModalityAccessStage.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/GroupModalityAccessStage.xtend index d4e0c039..6ab0e7a0 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/GroupModalityAccessStage.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/GroupModalityAccessStage.xtend @@ -31,11 +31,7 @@ class GroupModalityAccessStage extends AbstractTransformationStage { // Make sure we run after the unravel modality access stage UnravelModalityAccessStage.ORDER.afterwards() } - - static def afterwards(int x) { - return x + 10; - } - + def protected dispatch doTransform(ProgramBlock obj) { obj.transformChildren diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/ProgramGenerationTransformationPipeline.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/ProgramGenerationTransformationPipeline.xtend index 0cd4860f..6851538b 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/ProgramGenerationTransformationPipeline.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/ProgramGenerationTransformationPipeline.xtend @@ -17,6 +17,7 @@ import org.eclipse.mita.program.Program import com.google.inject.Inject import org.eclipse.emf.ecore.EObject import org.eclipse.mita.base.types.Expression +import org.eclipse.mita.program.generator.CompilationContext class ProgramGenerationTransformationPipeline implements ITransformationPipelineInfoProvider { @@ -31,13 +32,14 @@ class ProgramGenerationTransformationPipeline implements ITransformationPipeline @Inject UnravelLiteralArraysStage unravelLiteralArrayReturnStage @Inject EnforceOperatorPrecedenceStage enforceOperatorPrecedenceStage @Inject UnravelFunctionCallsStage unravelFunctionCallsStage + @Inject AddEventHandlerRingbufferStage addEventHandlerRingbufferStage - def transform(Program program) { + def transform(CompilationContext context, Program program) { val stages = getOrderedStages(); var result = program; for(stage : stages) { - result = stage.transform(this, result); + result = stage.transform(this, context, result); } return result; } @@ -72,7 +74,8 @@ class ProgramGenerationTransformationPipeline implements ITransformationPipeline prepareArrayRuntimeChecksStage, unravelLiteralArrayReturnStage, enforceOperatorPrecedenceStage, - unravelFunctionCallsStage + unravelFunctionCallsStage, + addEventHandlerRingbufferStage ].sortBy[ x | x.order ]; } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelFunctionCallsStage.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelFunctionCallsStage.xtend index 2ec4bee1..3b1f1738 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelFunctionCallsStage.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelFunctionCallsStage.xtend @@ -19,19 +19,23 @@ import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.base.expressions.ExpressionStatement import org.eclipse.mita.base.expressions.ExpressionsFactory import org.eclipse.mita.base.types.Expression +import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.GeneratedTypeConstructor import org.eclipse.mita.base.types.Operation import org.eclipse.mita.base.types.TypeAccessor import org.eclipse.mita.base.types.TypeConstructor import org.eclipse.mita.base.types.VirtualFunction import org.eclipse.mita.base.util.BaseUtils -import org.eclipse.mita.program.GeneratedFunctionDefinition import org.eclipse.mita.program.NewInstanceExpression import org.eclipse.mita.program.ProgramBlock import org.eclipse.mita.program.ReturnValueExpression +import org.eclipse.mita.program.VariableDeclaration import org.eclipse.mita.program.generator.internal.GeneratorRegistry import org.eclipse.mita.program.generator.internal.ProgramCopier import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.mita.program.ForEachStatement +import org.eclipse.mita.program.AbstractLoopStatement +import org.eclipse.emf.ecore.util.EcoreUtil class UnravelFunctionCallsStage extends AbstractUnravelingStage { @@ -45,13 +49,12 @@ class UnravelFunctionCallsStage extends AbstractUnravelingStage { if(EcoreUtil2.getContainerOfType(expression, ProgramBlock) === null) { return false; } - if(expression instanceof NewInstanceExpression) { - return false; - } + if(expression instanceof ElementReferenceExpression) { val ref = expression.reference; if(ref instanceof Operation) { + val parent = expression.eContainer; // special case: for generated functions we need to ask the generator if the call should be unraveled. if(ref instanceof GeneratedFunctionDefinition) { val generator = generatorRegistry.getGenerator(ref); @@ -68,11 +71,19 @@ class UnravelFunctionCallsStage extends AbstractUnravelingStage { return false; } - if(expression.eContainer instanceof ReturnValueExpression) { + if(parent instanceof ReturnValueExpression) { // don't unravel direct returns return false; } + // we would unravel expressions into a variable declaration/assignment anyway. + if( parent instanceof VariableDeclaration) { + // variable declarations are safe, unless they are loop variables. + return parent.eContainer instanceof AbstractLoopStatement; + } else if((parent instanceof AssignmentExpression && parent.eContainer instanceof ExpressionStatement)) { + return false; + } + // some virtual functions can be translated to expressions if(ref instanceof VirtualFunction) { if(ref instanceof TypeConstructor && !(ref instanceof GeneratedTypeConstructor)) { @@ -105,14 +116,17 @@ class UnravelFunctionCallsStage extends AbstractUnravelingStage { } override protected createInitialization(Expression expression) { - // We can safely make this cast as needsUnraveling ensures that expression must be an ERE - val elementReferenceExpression = expression as ElementReferenceExpression; + if(expression instanceof ElementReferenceExpression) { + val newFunctionCall = ExpressionsFactory.eINSTANCE.createElementReferenceExpression; + newFunctionCall.reference = expression.reference; + newFunctionCall.operationCall = true; + newFunctionCall.arguments.addAll(expression.arguments); + return newFunctionCall; + } + else { + return EcoreUtil.copy(expression); + } - val newFunctionCall = ExpressionsFactory.eINSTANCE.createElementReferenceExpression; - newFunctionCall.reference = elementReferenceExpression.reference; - newFunctionCall.operationCall = true; - newFunctionCall.arguments.addAll(elementReferenceExpression.arguments); - return newFunctionCall; } } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelInterpolatedStringsStage.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelInterpolatedStringsStage.xtend index 0860c688..5334e3c1 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelInterpolatedStringsStage.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelInterpolatedStringsStage.xtend @@ -18,11 +18,14 @@ import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.base.expressions.ExpressionsPackage import org.eclipse.mita.base.expressions.PrimitiveValueExpression import org.eclipse.mita.base.types.Expression +import org.eclipse.mita.base.types.InterpolatedStringLiteral import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.program.generator.internal.ProgramCopier import org.eclipse.xtext.EcoreUtil2 -import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull; -import org.eclipse.mita.base.types.InterpolatedStringLiteral + +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull import org.eclipse.mita.program.generator.internal.ProgramCopier +import org.eclipse.mita.base.expressions.AssignmentExpression class UnravelInterpolatedStringsStage extends AbstractUnravelingStage { @@ -36,6 +39,11 @@ class UnravelInterpolatedStringsStage extends AbstractUnravelingStage { 'logError' ]); + var assignmentExpressionParent = EcoreUtil2.getContainerOfType(expression, AssignmentExpression); + if(assignmentExpressionParent !== null) { + return expression.isIps; + } + var isInPrintContext = false; val possibleFunctionCallContainer = EcoreUtil2.getContainerOfType(expression, ElementReferenceExpression); if(possibleFunctionCallContainer !== null) { @@ -46,9 +54,13 @@ class UnravelInterpolatedStringsStage extends AbstractUnravelingStage { } return possibleFunctionCallContainer !== null - && possibleFunctionCallContainer?.isOperationCall + && possibleFunctionCallContainer.isOperationCall && !isInPrintContext - && expression.castOrNull(PrimitiveValueExpression)?.value?.castOrNull(InterpolatedStringLiteral) !== null; + && expression.isIps; + } + + def boolean isIps(Expression expression) { + return expression.castOrNull(PrimitiveValueExpression)?.value?.castOrNull(InterpolatedStringLiteral) !== null; } override protected createInitialization(Expression expression) { @@ -59,5 +71,4 @@ class UnravelInterpolatedStringsStage extends AbstractUnravelingStage { ProgramCopier.linkOrigin(copy.value, ProgramCopier.getOrigin(original.value)); return copy; } - } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelModalityAccessStage.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelModalityAccessStage.xtend index 3480e2ef..0e5cb3e1 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelModalityAccessStage.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/generator/transformation/UnravelModalityAccessStage.xtend @@ -17,10 +17,10 @@ import org.eclipse.mita.base.expressions.AbstractStatement import org.eclipse.mita.base.expressions.ArgumentExpression import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.base.types.Expression +import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.TypeKind import org.eclipse.mita.platform.AbstractSystemResource import org.eclipse.mita.platform.Modality -import org.eclipse.mita.program.GeneratedFunctionDefinition import org.eclipse.mita.program.ModalityAccessPreparation import org.eclipse.mita.program.ProgramFactory @@ -36,7 +36,7 @@ class UnravelModalityAccessStage extends AbstractUnravelingStage { if(expression instanceof ElementReferenceExpression) { val ref = expression.reference; if(ref instanceof GeneratedFunctionDefinition) { - if(ref.generator.contains("ModalityReadGenerator")) { + if(ref.generator?.contains("ModalityReadGenerator")) { return true; } } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/ProgramSizeInferrer.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/ProgramSizeInferrer.xtend index 69c6ab5b..853938fb 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/ProgramSizeInferrer.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/ProgramSizeInferrer.xtend @@ -17,6 +17,7 @@ import com.google.inject.Inject import org.eclipse.emf.ecore.EObject import org.eclipse.emf.ecore.resource.Resource import org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer +import org.eclipse.mita.base.expressions.Argument import org.eclipse.mita.base.expressions.ArrayAccessExpression import org.eclipse.mita.base.expressions.AssignmentExpression import org.eclipse.mita.base.expressions.ElementReferenceExpression @@ -25,6 +26,7 @@ import org.eclipse.mita.base.expressions.IntLiteral import org.eclipse.mita.base.expressions.PrimitiveValueExpression import org.eclipse.mita.base.expressions.ValueRange import org.eclipse.mita.base.types.CoercionExpression +import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.NullTypeSpecifier import org.eclipse.mita.base.types.Operation import org.eclipse.mita.base.types.Parameter @@ -62,21 +64,24 @@ import org.eclipse.mita.base.typesystem.types.NumericAddType import org.eclipse.mita.base.typesystem.types.NumericMaxType import org.eclipse.mita.base.typesystem.types.TypeConstructorType import org.eclipse.mita.base.typesystem.types.TypeScheme +import org.eclipse.mita.platform.Signal import org.eclipse.mita.program.DereferenceExpression +import org.eclipse.mita.program.EventHandlerDeclaration +import org.eclipse.mita.program.EventHandlerVariableDeclaration import org.eclipse.mita.program.FunctionDefinition -import org.eclipse.mita.program.GeneratedFunctionDefinition import org.eclipse.mita.program.NewInstanceExpression import org.eclipse.mita.program.Program import org.eclipse.mita.program.ReturnValueExpression import org.eclipse.mita.program.SignalInstance +import org.eclipse.mita.program.SystemEventSource import org.eclipse.mita.program.VariableDeclaration import org.eclipse.mita.program.resource.PluginResourceLoader import org.eclipse.xtend.lib.annotations.Accessors import org.eclipse.xtext.EcoreUtil2 import org.eclipse.xtext.diagnostics.Severity -import static extension org.eclipse.mita.base.util.BaseUtils.force import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull +import static extension org.eclipse.mita.base.util.BaseUtils.force import static extension org.eclipse.mita.base.util.BaseUtils.zip /** @@ -259,6 +264,10 @@ class ProgramSizeInferrer extends AbstractSizeInferrer implements TypeSizeInferr doCreateConstraints(c, c.obj); } + dispatch def void doCreateConstraints(InferenceContext c, Argument arg) { + inferUnmodifiedFrom(c.system, arg, arg.value); + } + dispatch def void doCreateConstraints(InferenceContext c, Operation op) { val typeArgs = op.typeParameters.map[c.system.getTypeVariable(it)].force() var type = c.type; @@ -292,6 +301,10 @@ class ProgramSizeInferrer extends AbstractSizeInferrer implements TypeSizeInferr c.system.associate(c.type, c.tv.origin); } } + // signals are hard to type (see PlatformConstraintFactory), and this call's signalInstance parent should have enough information to type the function call anyways. + else if(fun instanceof Signal) { + return; + } else if(fun instanceof Operation) { inferUnmodifiedFrom(c.system, obj, fun.typeSpecifier); } @@ -306,7 +319,11 @@ class ProgramSizeInferrer extends AbstractSizeInferrer implements TypeSizeInferr } dispatch def void doCreateConstraints(InferenceContext c, SignalInstance siginst) { - inferUnmodifiedFrom(c.system, siginst, siginst.initialization); + inferUnmodifiedFrom(c.system, siginst, siginst.initialization); + } + + dispatch def void doCreateConstraints(InferenceContext c, SystemEventSource eventSource) { + inferUnmodifiedFrom(c.system, eventSource, eventSource.source); } dispatch def void doCreateConstraints(InferenceContext c, VariableDeclaration variable) { @@ -358,6 +375,10 @@ class ProgramSizeInferrer extends AbstractSizeInferrer implements TypeSizeInferr inferUnmodifiedFrom(c.system, typeSpecifier, typeSpecifier.value); } + dispatch def void doCreateConstraints(InferenceContext c, EventHandlerVariableDeclaration variable) { + inferUnmodifiedFrom(c.system, variable, EcoreUtil2.getContainerOfType(variable, EventHandlerDeclaration).event); + } + dispatch def void doCreateConstraints(InferenceContext c, NullTypeSpecifier typeSpecifier) { val funDef = typeSpecifier.eContainer; if(funDef instanceof FunctionDefinition) { @@ -409,6 +430,9 @@ class ProgramSizeInferrer extends AbstractSizeInferrer implements TypeSizeInferr val typeInstance = new TypeConstructorType(typeSpecifier, new AtomicType(typeSpecifier.type, typeName), typeArgs); typeInstance; } + else { + type + } // handle reference modifiers (a: &t) val referenceTypeVarOrigin = typeRegistry.getTypeModelObject(typeSpecifier, StdlibTypeRegistry.referenceTypeQID); @@ -419,7 +443,7 @@ class ProgramSizeInferrer extends AbstractSizeInferrer implements TypeSizeInferr //handle optional modifier (a: t?) val optionalTypeVarOrigin = typeRegistry.getTypeModelObject(typeSpecifier, StdlibTypeRegistry.optionalTypeQID); val typeWithOptionalModifier = if(typeSpecifier.optional) { - new TypeConstructorType(null, new AtomicType(optionalTypeVarOrigin, "reference"), #[typeWithReferenceModifiers -> Variance.INVARIANT]); + new TypeConstructorType(null, new AtomicType(optionalTypeVarOrigin, "optional"), #[typeWithReferenceModifiers -> Variance.INVARIANT]); } else { typeWithReferenceModifiers; diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/SizeConstraintSolver.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/SizeConstraintSolver.xtend index 3d8342c2..82f0e4c8 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/SizeConstraintSolver.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/inferrer/SizeConstraintSolver.xtend @@ -30,6 +30,7 @@ import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.base.typesystem.types.BottomType import org.eclipse.mita.base.typesystem.types.LiteralNumberType import org.eclipse.mita.base.typesystem.StdlibTypeRegistry +import org.eclipse.mita.base.typesystem.constraints.SubtypeConstraint import org.eclipse.mita.base.typesystem.types.LiteralTypeExpression // handles equality and max @@ -132,6 +133,11 @@ class SizeConstraintSolver implements IConstraintSolver { return SimplificationResult.success(system, Substitution.EMPTY); } + protected dispatch def SimplificationResult doSimplify(ConstraintSystem system, Substitution substitution, EObject typeResolutionOrigin, SubtypeConstraint constraint) { + // do nothing + return SimplificationResult.success(system, Substitution.EMPTY); + } + protected dispatch def SimplificationResult doSimplify(ConstraintSystem system, Substitution substitution, EObject typeResolutionOrigin, ExplicitInstanceConstraint constraint) { val ts = constraint.typeScheme; if(ts instanceof TypeScheme) { diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/model/ModelUtils.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/model/ModelUtils.xtend index 297bd9f7..f3a57550 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/model/ModelUtils.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/model/ModelUtils.xtend @@ -249,7 +249,7 @@ class ModelUtils { def static getSortedArguments(Iterable parameters, Iterable arguments) { - if(arguments.empty || arguments.head.parameter === null) { + if(arguments.empty || arguments.exists[it.parameter === null]) { arguments; } else { diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ElementReferenceScope.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ElementReferenceScope.xtend index 3d464a28..1d3a869c 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ElementReferenceScope.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ElementReferenceScope.xtend @@ -20,6 +20,7 @@ import org.eclipse.mita.base.expressions.AbstractStatement import org.eclipse.mita.base.types.PackageAssociation import org.eclipse.mita.base.types.TypeAccessor import org.eclipse.mita.base.types.TypeKind +import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.ForEachStatement import org.eclipse.mita.program.ForStatement import org.eclipse.mita.program.FunctionDefinition @@ -27,6 +28,7 @@ import org.eclipse.mita.program.IsAssignmentCase import org.eclipse.mita.program.IsDeconstructionCase import org.eclipse.mita.program.Program import org.eclipse.mita.program.ProgramBlock +import org.eclipse.mita.program.ReturnParameterDeclaration import org.eclipse.mita.program.VariableDeclaration import org.eclipse.xtext.naming.QualifiedName import org.eclipse.xtext.resource.IEObjectDescription @@ -37,7 +39,6 @@ import org.eclipse.xtext.util.SimpleAttributeResolver import static extension org.eclipse.emf.ecore.util.EcoreUtil.* import static extension org.eclipse.xtext.EcoreUtil2.* -import org.eclipse.mita.program.ReturnParameterDeclaration class ElementReferenceScope extends AbstractScope { @@ -60,6 +61,7 @@ class ElementReferenceScope extends AbstractScope { result.addForEachLoopIterator(context) result.addGlobalVariables(context) result.addDeconstructorVariables(context) + result.addEventHandlerPayloadVariable(context) result.addStructureAccessors(context) Scopes.scopedElementsFor(result, [obj | if(obj instanceof TypeKind) { @@ -131,4 +133,10 @@ class ElementReferenceScope extends AbstractScope { addProgramBlocks(result, programBlock.eContainer) } } + + def void addEventHandlerPayloadVariable(List result, EObject object) { + val eventHandler = object.getContainerOfType(EventHandlerDeclaration); + val variable = eventHandler?.payload; + result += #[variable].filterNull + } } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ProgramDslScopeProvider.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ProgramDslScopeProvider.xtend index 2905dbdb..87856eda 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ProgramDslScopeProvider.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/scoping/ProgramDslScopeProvider.xtend @@ -266,7 +266,7 @@ class ProgramDslScopeProvider extends AbstractProgramDslScopeProvider { protected def getExtensionMethodScope(Expression context, EReference reference, AbstractType type) { return new FilteringScope(delegate.getScope(context, reference), [ x | (x.EClass == ProgramPackage.Literals.FUNCTION_DEFINITION || - x.EClass == ProgramPackage.Literals.GENERATED_FUNCTION_DEFINITION) && x.isApplicableOn(type) + x.EClass == TypesPackage.Literals.GENERATED_FUNCTION_DEFINITION) && x.isApplicableOn(type) ]); } @@ -661,6 +661,9 @@ class ProgramDslScopeProvider extends AbstractProgramDslScopeProvider { return context.imports.exists[it.importedNamespace.equals(sysSpec)] } } + else if(obj instanceof SystemResourceSetup) { + return !obj.events.isNullOrEmpty + } return false; ]) } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/typesystem/ProgramConstraintFactory.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/typesystem/ProgramConstraintFactory.xtend index 7775d0e8..0a8cec86 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/typesystem/ProgramConstraintFactory.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/typesystem/ProgramConstraintFactory.xtend @@ -23,6 +23,7 @@ import org.eclipse.mita.base.expressions.PostFixOperator import org.eclipse.mita.base.expressions.PostFixUnaryExpression import org.eclipse.mita.base.types.CoercionExpression import org.eclipse.mita.base.types.Expression +import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.ImportStatement import org.eclipse.mita.base.types.InterpolatedStringLiteral import org.eclipse.mita.base.types.NullTypeSpecifier @@ -58,11 +59,11 @@ import org.eclipse.mita.program.ConfigurationItemValue import org.eclipse.mita.program.DereferenceExpression import org.eclipse.mita.program.DoWhileStatement import org.eclipse.mita.program.EventHandlerDeclaration +import org.eclipse.mita.program.EventHandlerVariableDeclaration import org.eclipse.mita.program.ExceptionBaseVariableDeclaration import org.eclipse.mita.program.ForEachStatement import org.eclipse.mita.program.ForStatement import org.eclipse.mita.program.FunctionDefinition -import org.eclipse.mita.program.GeneratedFunctionDefinition import org.eclipse.mita.program.IfStatement import org.eclipse.mita.program.IsAssignmentCase import org.eclipse.mita.program.IsDeconstructionCase @@ -81,8 +82,10 @@ import org.eclipse.mita.program.ReturnValueExpression import org.eclipse.mita.program.SignalInstance import org.eclipse.mita.program.SignalInstanceReadAccess import org.eclipse.mita.program.SignalInstanceWriteAccess +import org.eclipse.mita.program.SystemEventSource import org.eclipse.mita.program.SystemResourceSetup import org.eclipse.mita.program.ThrowExceptionStatement +import org.eclipse.mita.program.TimeIntervalEvent import org.eclipse.mita.program.TryStatement import org.eclipse.mita.program.VariableDeclaration import org.eclipse.mita.program.WhereIsStatement @@ -158,13 +161,33 @@ class ProgramConstraintFactory extends PlatformConstraintFactory { return system.associate(typeRegistry.getTypeModelObjectProxy(system, writeAccess, StdlibTypeRegistry.voidTypeQID), writeAccess); } + protected dispatch def TypeVariable computeConstraints(ConstraintSystem system, TimeIntervalEvent eventSource) { + return system.getTypeVariable(eventSource); + } + protected dispatch def TypeVariable computeConstraints(ConstraintSystem system, SystemEventSource eventSource) { + return system.associate(system.getTypeVariableProxy(eventSource, ProgramPackage.eINSTANCE.systemEventSource_Source), eventSource); + } + protected dispatch def TypeVariable computeConstraints(ConstraintSystem system, EventHandlerDeclaration eventHandler) { system.computeConstraints(eventHandler.block); + system.computeConstraints(eventHandler.event); + if(eventHandler.payload !== null) { + system.computeConstraints(eventHandler.payload); + } val voidType = typeRegistry.getTypeModelObjectProxy(system, eventHandler, StdlibTypeRegistry.voidTypeQID); return system.associate(new FunctionType(eventHandler, new AtomicType(eventHandler.event, eventHandler.event.toString), voidType, voidType), eventHandler); } + protected dispatch def TypeVariable computeConstraints(ConstraintSystem system, EventHandlerVariableDeclaration varDecl) { + val eventHandler = EcoreUtil2.getContainerOfType(varDecl, EventHandlerDeclaration); + val event = eventHandler?.event; + if(event !== null) { + system.associate(system.getTypeVariable(event), varDecl); + } + return system._computeConstraints(varDecl as VariableDeclaration); + } + protected dispatch def TypeVariable computeConstraints(ConstraintSystem system, ImportStatement __) { return null; } @@ -537,7 +560,7 @@ class ProgramConstraintFactory extends PlatformConstraintFactory { val args = newInstanceExpression.arguments.map[system.computeConstraints(it) as AbstractType]; system.computeArgumentConstraintsWithTypes(newInstanceExpression, constructorName, args.force); } - system.computeConstraintsForFunctionCall(newInstanceExpression, null, constructorName, argType, #[functionTypeVar]); + system.computeConstraintsForFunctionCall(newInstanceExpression, ExpressionsPackage.eINSTANCE.elementReferenceExpression_Reference, constructorName, argType, #[functionTypeVar]); return system.associate(returnType, newInstanceExpression); } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/typesystem/ProgramLinker.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/typesystem/ProgramLinker.xtend index 45adce57..d72d2594 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/typesystem/ProgramLinker.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/typesystem/ProgramLinker.xtend @@ -9,9 +9,10 @@ class ProgramLinker extends PlatformLinker { override shouldLink(EClass classifier) { super.shouldLink(classifier) - || PlatformPackage.eINSTANCE.systemResourceEvent.isSuperTypeOf(classifier) + || TypesPackage.eINSTANCE.systemResourceEvent.isSuperTypeOf(classifier) || TypesPackage.eINSTANCE.event.isSuperTypeOf(classifier) || PlatformPackage.eINSTANCE.configurationItem.isSuperTypeOf(classifier) + || PlatformPackage.eINSTANCE.hasEvents.isSuperTypeOf(classifier) } } \ No newline at end of file diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ProgramDslValidator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ProgramDslValidator.xtend index 1ddddee4..13bd4d23 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ProgramDslValidator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ProgramDslValidator.xtend @@ -31,9 +31,11 @@ import org.eclipse.mita.base.expressions.FeatureCallWithoutFeature import org.eclipse.mita.base.expressions.ValueRange import org.eclipse.mita.base.types.ExceptionTypeDeclaration import org.eclipse.mita.base.types.Expression +import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.GeneratedType import org.eclipse.mita.base.types.GenericElement import org.eclipse.mita.base.types.NamedElement +import org.eclipse.mita.base.types.Operation import org.eclipse.mita.base.types.Parameter import org.eclipse.mita.base.types.Property import org.eclipse.mita.base.types.TypeAccessor @@ -61,11 +63,11 @@ import org.eclipse.mita.program.DereferenceExpression import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.FunctionDefinition import org.eclipse.mita.program.FunctionParameterDeclaration -import org.eclipse.mita.program.GeneratedFunctionDefinition import org.eclipse.mita.program.NewInstanceExpression import org.eclipse.mita.program.Program import org.eclipse.mita.program.ProgramBlock import org.eclipse.mita.program.ProgramPackage +import org.eclipse.mita.program.ReturnParameterDeclaration import org.eclipse.mita.program.ReturnValueExpression import org.eclipse.mita.program.SignalInstance import org.eclipse.mita.program.SystemResourceSetup @@ -82,6 +84,7 @@ import org.eclipse.xtext.validation.ComposedChecks import static org.eclipse.mita.base.types.typesystem.ITypeSystem.VOID import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull + import org.eclipse.mita.program.ReturnParameterDeclaration import org.eclipse.mita.base.types.Operation @@ -314,6 +317,18 @@ class ProgramDslValidator extends AbstractProgramDslValidator { } } + @Check(CheckType.NORMAL) + def checkGeneratedTypeVariableDeclarations(VariableDeclaration variable) { + val type = BaseUtils.getType(variable); + if(TypeUtils.isGeneratedType(variable, type)) { + val cs = TypeUtils.getConstraintSystem(variable.eResource); + val validator = cs.getUserData(type, BaseConstraintFactory.VALIDATOR_KEY); + if(validator !== null) { + runLibraryValidator(EcoreUtil2.getContainerOfType(variable, Program), variable, variable.eResource, validator); + } + } + } + @Check(CheckType.FAST) def checkVariableDeclaration_isUniqueInProgramBlock(VariableDeclaration variable) { val parentBlock = EcoreUtil2.getContainerOfType(variable, ProgramBlock); @@ -479,7 +494,7 @@ class ProgramDslValidator extends AbstractProgramDslValidator { return; } else if(hasGeneratedTypeNext) { - error(NESTED_GENERATED_TYPES_ARE_NOT_SUPPORTED, obj, null); +// error(NESTED_GENERATED_TYPES_ARE_NOT_SUPPORTED, obj, null); return; } else { diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ProgramSetupValidator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ProgramSetupValidator.xtend index 34d3d1c5..8fbdbd1b 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ProgramSetupValidator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ProgramSetupValidator.xtend @@ -22,6 +22,7 @@ import org.eclipse.xtext.validation.AbstractDeclarativeValidator import org.eclipse.xtext.validation.Check import org.eclipse.xtext.validation.CheckType import org.eclipse.xtext.validation.EValidatorRegistrar +import org.eclipse.mita.platform.PlatformPackage class ProgramSetupValidator extends AbstractDeclarativeValidator { public static val String INCOMPATIBLE_VALUE_TYPE_MSG = "The type '%s' is not compatible with the configuration item's type '%s'"; @@ -82,7 +83,7 @@ class ProgramSetupValidator extends AbstractDeclarativeValidator { // cannot be named if(setup.name !== null && !setup.name.trim.empty) { error(ProgramSetupValidator.SETUP_MUST_NOT_HAVE_NAME_MSG, setup, - ProgramPackage.Literals.SYSTEM_RESOURCE_SETUP__NAME, SETUP_MUST_NOT_HAVE_NAME_CODE); + TypesPackage.Literals.NAMED_ELEMENT__NAME, SETUP_MUST_NOT_HAVE_NAME_CODE); } } } diff --git a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ReferenceTypesValidator.xtend b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ReferenceTypesValidator.xtend index 291e0b2a..a0109c44 100644 --- a/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ReferenceTypesValidator.xtend +++ b/bundles/org.eclipse.mita.program/src/org/eclipse/mita/program/validation/ReferenceTypesValidator.xtend @@ -134,6 +134,9 @@ class ReferenceTypesValidator extends AbstractDeclarativeValidator implements IV @Check def forbiddenReferenceReturn(FunctionDefinition funDecl) { + if(funDecl.typeSpecifier === null) { + return; + } val funDeclTypeIR = BaseUtils.getType(funDecl.typeSpecifier); if(hasReferenceInType(funDeclTypeIR)) { error(FORBIDDEN_RETURN, funDecl, TypesPackage.Literals.NAMED_ELEMENT__NAME); diff --git a/platforms/org.eclipse.mita.platform.arduino/src/org/eclipse/mita/platform/arduino/platform/EventLoopGenerator.xtend b/platforms/org.eclipse.mita.platform.arduino/src/org/eclipse/mita/platform/arduino/platform/EventLoopGenerator.xtend index 931e8a6c..8ec1041f 100644 --- a/platforms/org.eclipse.mita.platform.arduino/src/org/eclipse/mita/platform/arduino/platform/EventLoopGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.arduino/src/org/eclipse/mita/platform/arduino/platform/EventLoopGenerator.xtend @@ -75,6 +75,8 @@ class EventLoopGenerator implements IPlatformEventLoopGenerator { override generateEnablePreamble(CompilationContext context) { return CodeFragment.EMPTY; + } + override CodeFragment generateEventLoopHandlerEpilogue(CompilationContext context, EventHandlerDeclaration declaration) { + return CodeFragment.EMPTY } - } diff --git a/platforms/org.eclipse.mita.platform.arduino/src/org/eclipse/mita/platform/arduino/platform/Validation.xtend b/platforms/org.eclipse.mita.platform.arduino/src/org/eclipse/mita/platform/arduino/platform/Validation.xtend index 24409e73..12cc37a4 100644 --- a/platforms/org.eclipse.mita.platform.arduino/src/org/eclipse/mita/platform/arduino/platform/Validation.xtend +++ b/platforms/org.eclipse.mita.platform.arduino/src/org/eclipse/mita/platform/arduino/platform/Validation.xtend @@ -7,12 +7,11 @@ import org.eclipse.mita.base.expressions.ElementReferenceExpression import org.eclipse.mita.base.expressions.ExpressionsPackage import org.eclipse.mita.base.expressions.FeatureCall import org.eclipse.mita.base.expressions.util.ExpressionUtils +import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.Operation import org.eclipse.mita.platform.AbstractSystemResource import org.eclipse.mita.platform.Signal -import org.eclipse.mita.program.GeneratedFunctionDefinition import org.eclipse.mita.program.Program -import org.eclipse.mita.program.model.ModelUtils import org.eclipse.mita.program.validation.IResourceValidator import org.eclipse.mita.program.validation.MethodCall import org.eclipse.mita.program.validation.MethodCall.MethodCallSigInst diff --git a/platforms/org.eclipse.mita.platform.cgw/src/org/eclipse/mita/platform/cgw/platform/EventLoopGenerator.xtend b/platforms/org.eclipse.mita.platform.cgw/src/org/eclipse/mita/platform/cgw/platform/EventLoopGenerator.xtend index c1374feb..88611fb2 100644 --- a/platforms/org.eclipse.mita.platform.cgw/src/org/eclipse/mita/platform/cgw/platform/EventLoopGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.cgw/src/org/eclipse/mita/platform/cgw/platform/EventLoopGenerator.xtend @@ -87,4 +87,8 @@ class EventLoopGenerator implements IPlatformEventLoopGenerator { return CodeFragment.EMPTY; } + override generateEventLoopHandlerEpilogue(CompilationContext context, EventHandlerDeclaration declaration) { + return CodeFragment.EMPTY; + } + } diff --git a/platforms/org.eclipse.mita.platform.cgw/src/org/eclipse/mita/platform/cgw/sensors/Bma280Generator.xtend b/platforms/org.eclipse.mita.platform.cgw/src/org/eclipse/mita/platform/cgw/sensors/Bma280Generator.xtend index 4858e3d2..c862edf1 100644 --- a/platforms/org.eclipse.mita.platform.cgw/src/org/eclipse/mita/platform/cgw/sensors/Bma280Generator.xtend +++ b/platforms/org.eclipse.mita.platform.cgw/src/org/eclipse/mita/platform/cgw/sensors/Bma280Generator.xtend @@ -14,19 +14,11 @@ package org.eclipse.mita.platform.cgw.sensors import com.google.inject.Inject -import org.eclipse.mita.platform.AbstractSystemResource -import org.eclipse.mita.platform.SystemResourceEvent -import org.eclipse.mita.platform.cgw.platform.EventLoopGenerator -import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.ModalityAccess import org.eclipse.mita.program.ModalityAccessPreparation -import org.eclipse.mita.program.SystemEventSource import org.eclipse.mita.program.generator.AbstractSystemResourceGenerator -import org.eclipse.mita.program.generator.CodeFragment -import org.eclipse.mita.program.generator.CodeFragment.IncludePath import org.eclipse.mita.program.generator.CodeFragmentProvider import org.eclipse.mita.program.generator.GeneratorUtils -import org.eclipse.mita.program.generator.IComponentConfiguration class Bma280Generator extends AbstractSystemResourceGenerator { diff --git a/platforms/org.eclipse.mita.platform.unittest/platform/unittests.platform b/platforms/org.eclipse.mita.platform.unittest/platform/unittests.platform index 31afd9a1..cdb552b6 100644 --- a/platforms/org.eclipse.mita.platform.unittest/platform/unittests.platform +++ b/platforms/org.eclipse.mita.platform.unittest/platform/unittests.platform @@ -30,6 +30,9 @@ sensor MySensor { event event00 event event01 event event02 + event event03: uint32 + event event04: string<100> + event event05: array, 5> } sensor MyOtherSensor { @@ -97,6 +100,7 @@ alias vci01 for MyOtherSensor platform UnitTestPlatform { module "org.eclipse.mita.platform.unittest.UnitTestPlatformGeneratorModule" + generator "org.eclipse.mita.platform.unittest.UnittestPlatformGenerator" event foo @@ -108,5 +112,7 @@ platform UnitTestPlatform { has MyConnectivity has MySingletonConnectivity has MyConnectivityWithRequires + + configuration-item queueSize: uint32 = 10 } diff --git a/platforms/org.eclipse.mita.platform.unittest/src/org/eclipse/mita/platform/unittest/SomeTypeGenerator.xtend b/platforms/org.eclipse.mita.platform.unittest/src/org/eclipse/mita/platform/unittest/SomeTypeGenerator.xtend index 02d3b465..17ee50ad 100644 --- a/platforms/org.eclipse.mita.platform.unittest/src/org/eclipse/mita/platform/unittest/SomeTypeGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.unittest/src/org/eclipse/mita/platform/unittest/SomeTypeGenerator.xtend @@ -26,7 +26,7 @@ import org.eclipse.mita.program.generator.AbstractFunctionGenerator import org.eclipse.mita.program.generator.AbstractTypeGenerator import org.eclipse.mita.program.generator.CodeFragment import org.eclipse.mita.program.generator.CodeFragmentProvider -import org.eclipse.xtext.generator.trace.node.IGeneratorNode +import org.eclipse.mita.program.generator.CodeWithContext class SomeTypeGenerator extends AbstractTypeGenerator { @@ -40,22 +40,17 @@ class SomeTypeGenerator extends AbstractTypeGenerator { override generateTypeSpecifier(AbstractType type, EObject context) { codeFragmentProvider.create('''«typeGenerator.code(context, (type as TypeConstructorType).typeArguments.tail.head)»''') } - - override generateNewInstance(AbstractType type, NewInstanceExpression expr) { - CodeFragment.EMPTY; - } - + static class GetElementGenerator extends AbstractFunctionGenerator { @Inject protected CodeFragmentProvider codeFragmentProvider - - override generate(ElementReferenceExpression ref, IGeneratorNode resultVariableName) { - val variable = ExpressionUtils.getArgumentValue(ref.reference as Operation, ref, 'self'); + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val variable = ExpressionUtils.getArgumentValue(functionCall.reference as Operation, functionCall, 'self'); - return codeFragmentProvider.create('''«resultVariableName» = «variable.generate»'''); + return codeFragmentProvider.create('''«IF resultVariable !== null»«resultVariable.code» = «ENDIF»«variable.generate»'''); } } @@ -65,14 +60,25 @@ class SomeTypeGenerator extends AbstractTypeGenerator { @Inject protected CodeFragmentProvider codeFragmentProvider - - override generate(ElementReferenceExpression ref, IGeneratorNode resultVariableName) { - val variable = ExpressionUtils.getArgumentValue(ref.reference as Operation, ref, 'self'); - val value = ExpressionUtils.getArgumentValue(ref.reference as Operation, ref, 'value'); + override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) { + val variable = ExpressionUtils.getArgumentValue(functionCall.reference as Operation, functionCall, 'self'); + val value = ExpressionUtils.getArgumentValue(functionCall.reference as Operation, functionCall, 'value'); return codeFragmentProvider.create('''«variable.generate» = «value.generate»;'''); } } + override generateBulkCopyStatements(EObject context, CodeFragment i, CodeWithContext left, CodeWithContext right, CodeFragment count) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override generateBulkAllocation(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count, boolean isTopLevel) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + + override generateBulkAssignment(EObject context, CodeFragment cVariablePrefix, CodeWithContext left, CodeFragment count) { + throw new UnsupportedOperationException("TODO: auto-generated method stub") + } + } diff --git a/platforms/org.eclipse.mita.platform.unittest/src/org/eclipse/mita/platform/unittest/UnittestPlatformGenerator.xtend b/platforms/org.eclipse.mita.platform.unittest/src/org/eclipse/mita/platform/unittest/UnittestPlatformGenerator.xtend new file mode 100644 index 00000000..52a2f3a8 --- /dev/null +++ b/platforms/org.eclipse.mita.platform.unittest/src/org/eclipse/mita/platform/unittest/UnittestPlatformGenerator.xtend @@ -0,0 +1,19 @@ +package org.eclipse.mita.platform.unittest + +import org.eclipse.mita.program.EventHandlerDeclaration +import org.eclipse.mita.program.generator.CodeFragment +import org.eclipse.mita.program.generator.MainSystemResourceGenerator + +class UnittestPlatformGenerator extends MainSystemResourceGenerator { + override long getEventHandlerPayloadQueueSize(EventHandlerDeclaration handler) { + return 10; + } + + override CodeFragment generateSetup() { + return codeFragmentProvider.create(); + } + + override CodeFragment generateEnable() { + return codeFragmentProvider.create(); + } +} diff --git a/platforms/org.eclipse.mita.platform.x86/1.0.0/x86.platform b/platforms/org.eclipse.mita.platform.x86/1.0.0/x86.platform index e66fad60..8dd5ac53 100644 --- a/platforms/org.eclipse.mita.platform.x86/1.0.0/x86.platform +++ b/platforms/org.eclipse.mita.platform.x86/1.0.0/x86.platform @@ -4,5 +4,8 @@ package platforms.x86; platform x86 { module "org.eclipse.mita.platform.x86.platform.X86PlatformGeneratorModule" - event startup + generator "org.eclipse.mita.platform.x86.platform.X86PlatformGenerator" + + // payload is current time in ms since epoch (1970/1/1) + event startup: int32 } diff --git a/platforms/org.eclipse.mita.platform.x86/META-INF/MANIFEST.MF b/platforms/org.eclipse.mita.platform.x86/META-INF/MANIFEST.MF index 8703d66a..a569cd18 100644 --- a/platforms/org.eclipse.mita.platform.x86/META-INF/MANIFEST.MF +++ b/platforms/org.eclipse.mita.platform.x86/META-INF/MANIFEST.MF @@ -10,6 +10,7 @@ Require-Bundle: org.eclipse.mita.library.extension, com.google.guava, org.eclipse.xtext.xbase.lib, org.eclipse.xtend.lib, - org.eclipse.xtend.lib.macro + org.eclipse.xtend.lib.macro, + org.eclipse.mita.library.stdlib Bundle-Vendor: Eclipse.org/Mita diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/EventLoopGenerator.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/EventLoopGenerator.xtend index e21c765e..4e9a1f26 100644 --- a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/EventLoopGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/EventLoopGenerator.xtend @@ -15,7 +15,6 @@ package org.eclipse.mita.platform.x86.platform import com.google.inject.Inject -import org.eclipse.mita.platform.SystemResourceEvent import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.SystemEventSource import org.eclipse.mita.program.TimeIntervalEvent @@ -85,5 +84,7 @@ class EventLoopGenerator implements IPlatformEventLoopGenerator { override generateEnablePreamble(CompilationContext context) { return CodeFragment.EMPTY; } - + override CodeFragment generateEventLoopHandlerEpilogue(CompilationContext context, EventHandlerDeclaration declaration) { + return CodeFragment.EMPTY + } } diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/MakefileGenerator.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/MakefileGenerator.xtend index 425bef24..fbf8c0e0 100644 --- a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/MakefileGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/MakefileGenerator.xtend @@ -21,7 +21,7 @@ class MakefileGenerator extends PlatformMakefileGenerator { override generateMakefile(CompilationContext context, List sourceFiles) { return codeFragmentProvider.create(''' export CC=gcc - export CCFLAGS=-Wall -std=c99 -D_POSIX_C_SOURCE=199309L -D_DEFAULT_SOURCE + export CCFLAGS=-Wall -std=c99 -D_POSIX_C_SOURCE=199309L -D_DEFAULT_SOURCE -g export BUILDDIR=./build export SOURCE_INCLUDES = -I. -I./base export SOURCE_DIR=. diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/StartupGenerator.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/StartupGenerator.xtend index 87222c18..bc5bb07d 100644 --- a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/StartupGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/StartupGenerator.xtend @@ -13,13 +13,20 @@ package org.eclipse.mita.platform.x86.platform -import org.eclipse.mita.program.generator.IPlatformStartupGenerator -import org.eclipse.mita.program.generator.CompilationContext import com.google.inject.Inject +import java.util.Optional +import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.library.stdlib.RingbufferGenerator +import org.eclipse.mita.library.stdlib.RingbufferGenerator.PushGenerator +import org.eclipse.mita.program.SystemEventSource +import org.eclipse.mita.program.TimeIntervalEvent import org.eclipse.mita.program.generator.CodeFragmentProvider +import org.eclipse.mita.program.generator.CodeWithContext +import org.eclipse.mita.program.generator.CompilationContext import org.eclipse.mita.program.generator.GeneratorUtils -import org.eclipse.mita.program.TimeIntervalEvent +import org.eclipse.mita.program.generator.IPlatformStartupGenerator import org.eclipse.mita.program.model.ModelUtils +import org.eclipse.mita.base.typesystem.StdlibTypeRegistry class StartupGenerator implements IPlatformStartupGenerator { @@ -29,10 +36,36 @@ class StartupGenerator implements IPlatformStartupGenerator { @Inject protected extension GeneratorUtils + @Inject + protected PushGenerator pushGenerator + + @Inject + StdlibTypeRegistry typeRegistry + override generateMain(CompilationContext context) { + val startupEventHandlersAndEvents = context.allEventHandlers + .map[it -> it.event] + .filter[it.value instanceof SystemEventSource] + .map[it.key -> it.value as SystemEventSource] + .map[it.key -> it.value.source] + .filter[it.value.name == "startup"] return codeFragmentProvider.create(''' Mita_initialize(); Mita_goLive(); + int32_t exception = 0; + «FOR startupEventHandler_event: startupEventHandlersAndEvents» + «val startupEventHandler = startupEventHandler_event.key» + «val event = startupEventHandler_event.value» + «pushGenerator.generate( + startupEventHandler, + new CodeWithContext( + RingbufferGenerator.wrapInRingbuffer(typeRegistry, startupEventHandler, BaseUtils.getType(event)), + Optional.empty, + codeFragmentProvider.create('''rb_«startupEventHandler.baseName»''') + ), + codeFragmentProvider.create('''getTime()''') + )» + «ENDFOR» while(1) { int32_t now = getTime(); «FOR handler : context.allEventHandlers» @@ -55,6 +88,11 @@ class StartupGenerator implements IPlatformStartupGenerator { } return 0; ''') + .setPreamble(''' + «FOR startupEventHandler_event: startupEventHandlersAndEvents» + extern ringbuffer_int32_t rb_«startupEventHandler_event.key.baseName»; + «ENDFOR» + ''') .addHeader('time.h', true) .addHeader('stdio.h', true) .addHeader('stdbool.h', true); diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/TimeGenerator.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/TimeGenerator.xtend index 9bf08a8b..79b67cf7 100644 --- a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/TimeGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/TimeGenerator.xtend @@ -49,7 +49,7 @@ class TimeGenerator implements IPlatformTimeGenerator { } int32_t getTime(void) { struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); + clock_gettime(CLOCK_REALTIME, &ts); return 1000*ts.tv_sec + ts.tv_nsec/1000000; } #endif diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/X86PlatformGenerator.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/X86PlatformGenerator.xtend new file mode 100644 index 00000000..a16352cd --- /dev/null +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/X86PlatformGenerator.xtend @@ -0,0 +1,20 @@ +package org.eclipse.mita.platform.x86.platform + +import org.eclipse.mita.program.generator.MainSystemResourceGenerator +import org.eclipse.mita.program.EventHandlerDeclaration + +class X86PlatformGenerator extends MainSystemResourceGenerator { + + override getEventHandlerPayloadQueueSize(EventHandlerDeclaration handler) { + return 2L; + } + + override generateSetup() { + return codeFragmentProvider.create(); + } + + override generateEnable() { + return codeFragmentProvider.create(); + } + +} \ No newline at end of file diff --git a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/X86PlatformGeneratorModule.xtend b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/X86PlatformGeneratorModule.xtend index 509ca305..baa93683 100644 --- a/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/X86PlatformGeneratorModule.xtend +++ b/platforms/org.eclipse.mita.platform.x86/src/org/eclipse/mita/platform/x86/platform/X86PlatformGeneratorModule.xtend @@ -36,5 +36,9 @@ class X86PlatformGeneratorModule extends EmptyPlatformGeneratorModule { override bindPlatformBuildSystemGenerator() { MakefileGenerator } - + + override bindMainSystemResourceGenerator() { + X86PlatformGenerator + } + } diff --git a/platforms/org.eclipse.mita.platform.xdk110/1.0.0/xdk110.platform b/platforms/org.eclipse.mita.platform.xdk110/1.0.0/xdk110.platform index 2dd2920d..ed54b21d 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/1.0.0/xdk110.platform +++ b/platforms/org.eclipse.mita.platform.xdk110/1.0.0/xdk110.platform @@ -556,6 +556,8 @@ sensor Button { * Fires after the button was released. */ event released + + event changed: bool } enum ADC_Channel { @@ -828,6 +830,7 @@ connectivity many MQTT { */ signal topic(name : string, qos : uint32 = 0) : string + event msgReceived: string<500> } alt HonoAuthentication { diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttGenerator.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttGenerator.xtend index 87c914ff..75325cc3 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttGenerator.xtend @@ -15,6 +15,8 @@ package org.eclipse.mita.platform.xdk110.connectivity import com.google.inject.Inject import java.net.URI +import java.util.stream.Collectors +import org.eclipse.mita.library.stdlib.RingbufferGenerator.PushGenerator import org.eclipse.mita.program.SignalInstance import org.eclipse.mita.program.generator.AbstractSystemResourceGenerator import org.eclipse.mita.program.generator.CodeFragment @@ -27,8 +29,15 @@ import org.eclipse.mita.program.inferrer.StaticValueInferrer import org.eclipse.mita.program.inferrer.StaticValueInferrer.SumTypeRepr import org.eclipse.mita.program.model.ModelUtils import org.eclipse.xtext.generator.IFileSystemAccess2 -import java.util.stream.Collectors -import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull +import java.util.Optional +import org.eclipse.mita.program.generator.CodeWithContext +import org.eclipse.mita.base.typesystem.types.TypeConstructorType +import org.eclipse.mita.base.util.BaseUtils +import org.eclipse.mita.base.types.Variance +import org.eclipse.mita.library.stdlib.RingbufferGenerator +import org.eclipse.mita.base.typesystem.StdlibTypeRegistry +import org.eclipse.mita.program.SystemEventSource +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull; class MqttGenerator extends AbstractSystemResourceGenerator { @@ -44,6 +53,12 @@ class MqttGenerator extends AbstractSystemResourceGenerator { @Inject protected extension GeneratorUtils generatorUtils + @Inject + protected PushGenerator pushGenerator + + @Inject + StdlibTypeRegistry typeRegistry + override generateAdditionalFiles(IFileSystemAccess2 fsa) { val brokerUri = new URI(configuration.getString("url")); val isSecure = brokerUri.scheme == "mqtts"; @@ -88,6 +103,7 @@ class MqttGenerator extends AbstractSystemResourceGenerator { } val auth = StaticValueInferrer.infer(configuration.getExpression("authentication"), []); + val topics = setup.signalInstances.map[it.name -> it.topicName]; val result = codeFragmentProvider.create(''' Retcode_T exception = RETCODE_OK; @@ -97,6 +113,9 @@ class MqttGenerator extends AbstractSystemResourceGenerator { StringDescr_wrap(&password, passwordBuf); «ENDIF» «ENDIF» + «FOR topic: topics.indexed» + StringDescr_wrap(&topics[«topic.key»], «topic.value.key»TopicBuf); + «ENDFOR» «servalpalGenerator.generateSetup(isSecure)» @@ -189,6 +208,15 @@ class MqttGenerator extends AbstractSystemResourceGenerator { .ServerPort = «sntpPort» }; «ENDIF» + + «FOR topic: topics.indexed» + char* «topic.value.key»TopicBuf = "«topic.value.value»"; + size_t «topic.value.key»TopicIdx = «topic.key»; + «ENDFOR» + + StringDescr_T topics[«topics.size»]; + Mqtt_qos_t qoss[] = {«FOR topic: setup.signalInstances SEPARATOR(", ")»«getQosFromInt(getQosLevel(topic))»«ENDFOR»}; + ''') .addHeader("Serval_Mqtt.h", true, IncludePath.LOW_PRIORITY) .addHeader("stdint.h", true, IncludePath.HIGH_PRIORITY) @@ -400,6 +428,10 @@ class MqttGenerator extends AbstractSystemResourceGenerator { val isSecure = brokerUri.scheme == "mqtts"; codeFragmentProvider.create(''' + «FOR handler: eventHandler» + extern ringbuffer_array_char rb_«handler.baseName»; + «ENDFOR» + /** * @brief Callback function used by the stack to communicate events to the application. * Each event will bring with it specialized data that will contain more information. @@ -462,8 +494,26 @@ class MqttGenerator extends AbstractSystemResourceGenerator { case MQTT_SUBSCRIPTION_REMOVED: exception = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_MQTT_SUBSCRIBE_REMOVED); break; - case MQTT_INCOMING_PUBLISH: + case MQTT_INCOMING_PUBLISH: { + array_char msg = (array_char) { + .data = eventData->publish.payload, + .capacity = eventData->publish.length, + .length = eventData->publish.length + }; + «FOR handler: eventHandler» + «pushGenerator.generate( + handler, + new CodeWithContext(RingbufferGenerator.wrapInRingbuffer(typeRegistry, handler, BaseUtils.getType(handler.event.castOrNull(SystemEventSource).source)), Optional.empty, codeFragmentProvider.create('''rb_«handler.baseName»''')), + codeFragmentProvider.create('''msg''') + )» + exception = CmdProcessor_enqueue(&Mita_EventQueue, «handler.handlerName», NULL, 0); + if(exception != RETCODE_OK) + { + Retcode_RaiseError(exception); + } + «ENDFOR» break; + } case MQTT_PUBLISHED_DATA: mqttWasPublished = true; if (pdTRUE != xSemaphoreGive(mqttPublishHandle)) @@ -548,12 +598,27 @@ class MqttGenerator extends AbstractSystemResourceGenerator { «loggingGenerator.generateLogStatement(LogLevel.Error, "MQTT_Connect : Failed since Post CB was not received")» return RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_MQTT_CONNECT_CB_NOT_RECEIVED); } + xSemaphoreGive(mqttConnectHandle); if (!mqttIsConnected) { «loggingGenerator.generateLogStatement(LogLevel.Error, "MQTT_Connect : Failed to connect")» Mqtt_disconnect(&mqttSession); return RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_MQTT_CONNECT_STATUS_ERROR); } + + xSemaphoreTake(mqttSubscribeHandle, 0UL); + rc = Mqtt_subscribe(&mqttSession, sizeof(topics)/sizeof(StringDescr_T), topics, qoss); + if(RC_OK != rc) { + «loggingGenerator.generateLogStatement(LogLevel.Error, '''MQTT_Connect : Failed to subscribe to topics: 0x%d''', codeFragmentProvider.create('''rc'''))» + return RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_MQTT_SUBSCRIBE_FAILED); + } + if (pdTRUE != xSemaphoreTake(mqttSubscribeHandle, pdMS_TO_TICKS(30000))) + { + «loggingGenerator.generateLogStatement(LogLevel.Error, "MQTT_Connect : Subscribe failed since Post CB was not received")» + return RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_MQTT_SUBSCRIBE_CB_NOT_RECEIVED); + } + xSemaphoreGive(mqttSubscribeHandle); + return RETCODE_OK; } ''') @@ -562,6 +627,8 @@ class MqttGenerator extends AbstractSystemResourceGenerator { static Retcode_T connectToBackend(void); static void mqttPing(void* userParameter1, uint32_t userParameter2); ''') + .addHeader("MitaGeneratedTypes.h", false) + .addHeader('MitaEvents.h', false) } def getQosFromInt(int qos) { @@ -592,15 +659,12 @@ class MqttGenerator extends AbstractSystemResourceGenerator { } «generatorUtils.generateExceptionHandler(signalInstance, "exception")» - static StringDescr_T publishTopicDescription; - static char *topic = "«getTopicName(signalInstance)»"; - StringDescr_wrap(&publishTopicDescription, topic); mqttWasPublished = false; /* This is a dummy take. In case of any callback received * after the previous timeout will be cleared here. */ (void) xSemaphoreTake(mqttPublishHandle, 0UL); - if (RC_OK != Mqtt_publish(&mqttSession, publishTopicDescription, value->data, value->length, (uint8_t) «qos», false)) + if (RC_OK != Mqtt_publish(&mqttSession,topics[«signalInstance.name»TopicIdx], value->data, value->length, (uint8_t) «qos», false)) { exception = RETCODE(RETCODE_SEVERITY_ERROR, RETCODE_MQTT_PUBLISH_FAILED); } diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttValidator.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttValidator.xtend index 96e4ae4c..21174762 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttValidator.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/MqttValidator.xtend @@ -119,7 +119,7 @@ class MqttValidator implements IResourceValidator { def validateTopicQualityOfService(SystemResourceSetup setup, ValidationMessageAcceptor acceptor) { for(siginst : setup.signalInstances) { - if(siginst.instanceOf.name == 'topic' || siginst.instanceOf.name == 'telemetry') { + if(siginst.instanceOf?.name == 'topic' || siginst.instanceOf?.name == 'telemetry') { val qos = ModelUtils.getArgumentValue(siginst, "qos") if(qos !== null) { val qosValue = StaticValueInferrer.infer(qos, []); diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/WlanGenerator.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/WlanGenerator.xtend index 1bdd932a..951e0a02 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/WlanGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/connectivity/WlanGenerator.xtend @@ -198,10 +198,10 @@ class WlanGenerator extends AbstractSystemResourceGenerator { #define NETWORK_SSID "«configuration.getString("ssid")»" «IF auth instanceof SumTypeRepr» «IF auth.name == "Personal"» - #define NETWORK_PSK «auth.properties.get("psk").code» + #define NETWORK_PSK "«StaticValueInferrer.infer(auth.properties.get("psk"), [])»" «ELSEIF auth.name == "Enterprise"» - #define NETWORK_USERNAME «auth.properties.get("username").code» - #define NETWORK_PASSWORD «auth.properties.get("password").code» + #define NETWORK_USERNAME "«StaticValueInferrer.infer(auth.properties.get("username"), [])»" + #define NETWORK_PASSWORD "«StaticValueInferrer.infer(auth.properties.get("password"), [])»" «ENDIF» «ELSE» ERROR: INVALID CONFIGURATION: authentication diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/EventLoopGenerator.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/EventLoopGenerator.xtend index 9c59747a..31c91e3f 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/EventLoopGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/EventLoopGenerator.xtend @@ -14,21 +14,23 @@ package org.eclipse.mita.platform.xdk110.platform import com.google.inject.Inject +import org.eclipse.mita.base.typesystem.types.TypeVariable +import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.generator.CodeFragment import org.eclipse.mita.program.generator.CodeFragmentProvider import org.eclipse.mita.program.generator.CompilationContext +import org.eclipse.mita.program.generator.GeneratorUtils import org.eclipse.mita.program.generator.IPlatformEventLoopGenerator import org.eclipse.mita.program.generator.StatementGenerator import org.eclipse.mita.program.inferrer.StaticValueInferrer -import org.eclipse.mita.program.generator.GeneratorUtils class EventLoopGenerator implements IPlatformEventLoopGenerator { @Inject protected CodeFragmentProvider codeFragmentProvider; @Inject - protected StatementGenerator statementGenerator; + protected extension StatementGenerator statementGenerator; @Inject protected extension GeneratorUtils generatorUtils; @@ -92,6 +94,8 @@ class EventLoopGenerator implements IPlatformEventLoopGenerator { } override generateEnablePreamble(CompilationContext context) { return CodeFragment.EMPTY; - } - + } + override CodeFragment generateEventLoopHandlerEpilogue(CompilationContext context, EventHandlerDeclaration declaration) { + return CodeFragment.EMPTY + } } \ No newline at end of file diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Validation.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Validation.xtend index 037288be..400f116c 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Validation.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Validation.xtend @@ -22,11 +22,12 @@ import org.eclipse.mita.base.expressions.ExpressionsPackage import org.eclipse.mita.base.expressions.FeatureCallWithoutFeature import org.eclipse.mita.base.expressions.util.ExpressionUtils import org.eclipse.mita.base.types.Enumerator +import org.eclipse.mita.base.types.GeneratedFunctionDefinition import org.eclipse.mita.base.types.Operation +import org.eclipse.mita.library.stdlib.ArrayGenerator import org.eclipse.mita.platform.AbstractSystemResource import org.eclipse.mita.platform.Signal import org.eclipse.mita.platform.xdk110.sensors.NoiseSensorValidator -import org.eclipse.mita.program.GeneratedFunctionDefinition import org.eclipse.mita.program.Program import org.eclipse.mita.program.SignalInstance import org.eclipse.mita.program.inferrer.StaticValueInferrer diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Xdk110PlatformGenerator.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Xdk110PlatformGenerator.xtend index c79a2c30..a719fb70 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Xdk110PlatformGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Xdk110PlatformGenerator.xtend @@ -1,24 +1,18 @@ package org.eclipse.mita.platform.xdk110.platform -import com.google.common.base.Optional import com.google.inject.Inject -import org.eclipse.mita.base.types.Enumerator -import org.eclipse.mita.platform.AbstractSystemResource -import org.eclipse.mita.platform.Platform +import org.eclipse.mita.base.util.BaseUtils import org.eclipse.mita.platform.xdk110.connectivity.AdcGenerator import org.eclipse.mita.platform.xdk110.connectivity.AdcGenerator.SignalInfo +import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.ModalityAccess import org.eclipse.mita.program.ModalityAccessPreparation -import org.eclipse.mita.program.Program -import org.eclipse.mita.program.SignalInstance -import org.eclipse.mita.program.generator.AbstractSystemResourceGenerator -import org.eclipse.mita.program.generator.CompilationContext import org.eclipse.mita.program.generator.GeneratorUtils -import org.eclipse.mita.program.inferrer.StaticValueInferrer -import org.eclipse.mita.program.model.ModelUtils -import org.eclipse.xtext.EcoreUtil2 +import org.eclipse.mita.program.generator.MainSystemResourceGenerator -class Xdk110PlatformGenerator extends AbstractSystemResourceGenerator { +import static extension org.eclipse.mita.base.util.BaseUtils.computeOrigin + +class Xdk110PlatformGenerator extends MainSystemResourceGenerator { @Inject extension GeneratorUtils @@ -93,4 +87,12 @@ class Xdk110PlatformGenerator extends AbstractSystemResourceGenerator { .addHeader("xdk110Types.h", false) } + override getEventHandlerPayloadQueueSize(EventHandlerDeclaration handler) { + val type = BaseUtils.getType(handler.event.computeOrigin); + if(type.name == "string") { + return 2; + } + return 10; + } + } \ No newline at end of file diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Xdk110PlatformGeneratorModule.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Xdk110PlatformGeneratorModule.xtend index 773848f1..16857774 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Xdk110PlatformGeneratorModule.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/platform/Xdk110PlatformGeneratorModule.xtend @@ -41,4 +41,8 @@ class Xdk110PlatformGeneratorModule extends EmptyPlatformGeneratorModule { LoggingGenerator } + override bindMainSystemResourceGenerator() { + Xdk110PlatformGenerator + } + } \ No newline at end of file diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/Bma280Generator.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/Bma280Generator.xtend index 8b7592ef..6b4e0263 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/Bma280Generator.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/Bma280Generator.xtend @@ -13,8 +13,9 @@ package org.eclipse.mita.platform.xdk110.sensors +import com.google.inject.Inject +import org.eclipse.mita.base.types.SystemResourceEvent import org.eclipse.mita.platform.AbstractSystemResource -import org.eclipse.mita.platform.SystemResourceEvent import org.eclipse.mita.platform.xdk110.platform.EventLoopGenerator import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.ModalityAccess @@ -26,7 +27,6 @@ import org.eclipse.mita.program.generator.CodeFragment.IncludePath import org.eclipse.mita.program.generator.CodeFragmentProvider import org.eclipse.mita.program.generator.GeneratorUtils import org.eclipse.mita.program.generator.IComponentConfiguration -import com.google.inject.Inject class Bma280Generator extends AbstractSystemResourceGenerator { diff --git a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/ButtonGenerator.xtend b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/ButtonGenerator.xtend index 7a9109b2..3bc32dc6 100644 --- a/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/ButtonGenerator.xtend +++ b/platforms/org.eclipse.mita.platform.xdk110/src/org/eclipse/mita/platform/xdk110/sensors/ButtonGenerator.xtend @@ -14,6 +14,8 @@ package org.eclipse.mita.platform.xdk110.sensors import com.google.inject.Inject +import org.eclipse.mita.base.typesystem.StdlibTypeRegistry +import org.eclipse.mita.library.stdlib.RingbufferGenerator.PushGenerator import org.eclipse.mita.platform.AbstractSystemResource import org.eclipse.mita.program.EventHandlerDeclaration import org.eclipse.mita.program.ModalityAccess @@ -24,6 +26,11 @@ import org.eclipse.mita.program.generator.CodeFragment import org.eclipse.mita.program.generator.CodeFragment.IncludePath import org.eclipse.mita.program.generator.CodeFragmentProvider import org.eclipse.mita.program.generator.GeneratorUtils +import org.eclipse.mita.program.generator.CodeWithContext +import org.eclipse.mita.library.stdlib.RingbufferGenerator +import org.eclipse.mita.base.util.BaseUtils +import java.util.Optional +import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull; class ButtonGenerator extends AbstractSystemResourceGenerator { @@ -33,6 +40,12 @@ class ButtonGenerator extends AbstractSystemResourceGenerator { @Inject protected CodeFragmentProvider codeFragmentProvider + @Inject + protected PushGenerator pushGenerator + + @Inject + StdlibTypeRegistry typeRegistry + override generateSetup() { codeFragmentProvider.create(''' return BSP_Button_Connect(); @@ -42,18 +55,43 @@ class ButtonGenerator extends AbstractSystemResourceGenerator { .addHeader('BSP_BoardType.h', true, IncludePath.HIGH_PRIORITY) .addHeader('BCDS_BSP_Button.h', true) .addHeader('MitaEvents.h', true) + .addHeader("MitaGeneratedTypes.h", false) .setPreamble(''' «FOR handlergrp : eventHandler.groupBy[it.sensorInstance.buttonNumber].values» - void «handlergrp.head.internalHandlerName»(uint32_t data) + «val changedHandlers = handlergrp.filter[(it.event as SystemEventSource)?.source?.name == "changed"]» + «FOR changedHandler: changedHandlers» + extern ringbuffer_bool rb_«changedHandler.baseName»; + «ENDFOR» + + Retcode_T «handlergrp.head.internalHandlerName»(uint32_t data) { + Retcode_T exception = RETCODE_OK; «FOR idx_handler: handlergrp.indexed» + «IF #["pressed", "released"].contains((idx_handler.value.event as SystemEventSource)?.source?.name)» «IF idx_handler.key > 0»else «ENDIF»if(data == «getButtonStatusEnumName(idx_handler.value)») { - Retcode_T retcode = CmdProcessor_enqueueFromIsr(&Mita_EventQueue, «idx_handler.value.handlerName», NULL, data); - if(retcode != RETCODE_OK) + exception = CmdProcessor_enqueueFromIsr(&Mita_EventQueue, «idx_handler.value.handlerName», NULL, data); + if(exception != RETCODE_OK) { - Retcode_RaiseErrorFromIsr(retcode); + Retcode_RaiseErrorFromIsr(exception); } } + «ENDIF» + «ENDFOR» + «FOR changedHandler: changedHandlers» + «pushGenerator.generate( + changedHandler, + new CodeWithContext( + RingbufferGenerator.wrapInRingbuffer(typeRegistry, changedHandler, BaseUtils.getType(changedHandler.event.castOrNull(SystemEventSource).source)), + Optional.empty, + codeFragmentProvider.create('''rb_«changedHandler.baseName»''') + ), + codeFragmentProvider.create('''data == BSP_XDK_BUTTON_PRESSED''') + )» + exception = CmdProcessor_enqueueFromIsr(&Mita_EventQueue, «changedHandler.handlerName», NULL, data); + if(exception != RETCODE_OK) + { + Retcode_RaiseErrorFromIsr(exception); + } «ENDFOR» } diff --git a/website/site/content/language/generatedThings.md b/website/site/content/language/generatedThings.md new file mode 100644 index 00000000..22748510 --- /dev/null +++ b/website/site/content/language/generatedThings.md @@ -0,0 +1,68 @@ +--- +title: "Generated Types and Functions" +description: "The definite reference of the Mita language; all its keywords, constructs and tricks." +weight: 100 +draft: false +toc: false +type: index +menu: + main: + parent: Language + identifier: generatedThings + weight: 100 +--- + +## Introduction + +Mita compiles to C with static memory management without large state machines or spaghetti code (unless you write that yourself). This is great for understanding how Mita code executes and runtime behaviour, however it imposes some serious limitations on what you can reasonably express in the language itself. + +To extend this there are generated types and functions. They can be used by users very easily and are more flexible than core types and functions, but need to be compiled by a small compiler fragment or generator. However they support [parametric polymorphism](https://en.wikipedia.org/wiki/Parametric_polymorphism) and types with a dynamic size, like arrays and strings. + +### Generated Types + +Generated types are declared like this: + +```typescript +export generated type array + generator "org.eclipse.mita.library.stdlib.ArrayGenerator" + size-inferrer "org.eclipse.mita.library.stdlib.ArraySizeInferrer" + + constructor con(); +``` + +Lets go through this line by line. +- `export` means this type is visible outside the package its declared in. This is optional. +- `generated type` is the keyword the parser uses to identify that you are declaring a generated type. +- `array` is the name of this parametric type, along with its parameters. There are two kinds of parameters: + - Normal ones, `T`, are just a placeholder for specific instances, for example in `optional`. + - Size parameters, `Size is uint32`, are placeholders for actual sizes that are checked and inferred at compile time. +- `generator ""` specifies the Java class name of your generator generating this type. +- `size-inferrer ""` specifies the Java class name of the size inferrer of this type. In most cases you can just specialize `org.eclipse.mita.library.stdlib.GenericContainerSizeInferrer` for a default sensible behaviour. +- Generated types may specify a validator that gets called per file with `validator ""`. +- `constructor con()` declares that users can write `new array()`. `con` is a generated function and may have parameters. If you want to handle this in a special way you can specify a generator, size inferrer and validator, otherwise calls to `new` are translated by the empty statement and won't be part of initializations. + +#### Type Generators + +Type generators are responsible for generating C code that implements all operations on types. These are: +- generating type declarations and definitions for `MitaGeneratedTypes.h` +- declaring a variable +- copying from right to left +- allocating memory for `n` instances, and assigning those instances to a C array +- copying `n` instances between C arrays + +We will go over these roughly, for comprehensive examples its always best to look at the standard library. + +In C there are two different kinds of type statements: declarations and definitions. Declarations sufficient to let the C compiler know that a type exists and is a structure, at that point pointers to those types can be compiled. Definitions further provide size, names and layouting to the compiler. + +Both of these go into `MitaGeneratedTypes.h`, but by separating them you can declare recursive data structures. + +#### Type Size Inferrers + +Most types will just want to extend `org.eclipse.mita.library.stdlib.GenericContainerSizeInferrer`. It handles normal statements/expressions correctly, and you just need to specify which type parameters are data and which are size parameters. Indices for these start at one, so for example the `ArraySizeInferrer` specifies that 1: data and 2: size. +You can then extend this size inferrer for special expressions, but you probably won't need to. + +### Generated Functions + +#### Function Generators + +#### Function Size Inferrers