Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Events per signal instance #367

Merged
merged 12 commits into from
Nov 29, 2019
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.eclipse.mita.base.typesystem.infra
import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.mita.base.types.TypeSpecifier
import org.eclipse.mita.base.types.validation.IValidationIssueAcceptor.ValidationIssue
import org.eclipse.mita.base.typesystem.constraints.MaxConstraint
import org.eclipse.mita.base.typesystem.constraints.SumConstraint
import org.eclipse.mita.base.typesystem.solver.ConstraintSolution
Expand All @@ -12,7 +13,6 @@ import org.eclipse.mita.base.typesystem.types.TypeVariable
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtend.lib.annotations.EqualsHashCode
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
import org.eclipse.mita.base.types.validation.IValidationIssueAcceptor.ValidationIssue

abstract class AbstractSizeInferrer {
def ConstraintSolution createSizeConstraints(ConstraintSolution cs, Resource r);
Expand Down Expand Up @@ -72,9 +72,9 @@ interface TypeSizeInferrer extends FunctionSizeInferrer {
def Iterable<ValidationIssue> validateSizeInference(Resource r, ConstraintSystem system, EObject origin, AbstractType type);
}

@FinalFieldsConstructor
@Accessors
@EqualsHashCode
@FinalFieldsConstructor
class InferenceContext {
val ConstraintSystem system;
val Resource r;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,6 @@ class Substitution {
}

def void addToContent(TypeVariable tv, AbstractType typ) {
if(tv.idx == 2679 && typ.toString == "uint32") {
print("")
}
Comment on lines -185 to -187

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always happy to see those go :)

content.put(tv.idx, typ);
idxToTypeVariable.put(tv.idx, tv);
val freeVars = typ.freeVars;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ class ArrayGenerator extends AbstractTypeGenerator {
@Inject
protected CodeFragmentProvider codeFragmentProvider

@Inject
protected extension StatementGenerator

override generate(CodeWithContext resultVariable, ElementReferenceExpression functionCall) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,9 @@ abstract class GenericContainerSizeInferrer implements TypeSizeInferrer {
dispatch def void doCreateConstraints(InferenceContext c, EObject obj, AbstractType t) {
delegate.createConstraints(c);
}
dispatch def void doCreateConstraints(InferenceContext c, Void obj, AbstractType t) {
delegate.createConstraints(c);
}

// create max constraints for all sizes
override createConstraintsForMax(ConstraintSystem system, Resource r, MaxConstraint constraint) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,32 @@ import com.google.inject.Inject
import org.eclipse.emf.ecore.EObject
import org.eclipse.mita.base.expressions.ElementReferenceExpression
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.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.FunctionType
import org.eclipse.mita.base.typesystem.types.LiteralNumberType
import org.eclipse.mita.base.typesystem.types.ProdType
import org.eclipse.mita.base.typesystem.types.TypeConstructorType
import org.eclipse.mita.library.stdlib.functions.SignalInstanceSizeInferrer
import org.eclipse.mita.platform.Signal
import org.eclipse.mita.program.EventHandlerDeclaration
import org.eclipse.mita.program.EventHandlerVariableDeclaration
import org.eclipse.mita.program.SignalInstance
import org.eclipse.mita.program.SystemEventSource
import org.eclipse.mita.program.SystemResourceSetup
import org.eclipse.mita.program.inferrer.StaticValueInferrer
import org.eclipse.mita.program.model.ModelUtils
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtext.EcoreUtil2

import static extension org.eclipse.mita.base.util.BaseUtils.castOrNull
import static extension org.eclipse.mita.base.util.BaseUtils.init
import org.eclipse.mita.base.typesystem.constraints.ExplicitInstanceConstraint
import org.eclipse.xtext.EcoreUtil2
import org.eclipse.mita.program.SystemResourceSetup
import org.eclipse.mita.base.types.NamedElement
import org.eclipse.mita.library.stdlib.functions.SignalInstanceSizeInferrer
import org.eclipse.mita.base.typesystem.infra.TypeSizeInferrer
import org.eclipse.mita.program.inferrer.ProgramSizeInferrer
import org.eclipse.mita.base.typesystem.solver.ConstraintSystem

/**
* This inferrer can handle all types in the stdlib, so if you're returning
Expand All @@ -53,45 +54,75 @@ class GenericPlatformSizeInferrer implements FunctionSizeInferrer {
return 'length';
}



protected dispatch def void doCreateConstraints(InferenceContext c, SignalInstance instance, TypeConstructorType type) {
if(!#["string", "array"].contains(type.name)) {
return;
protected def AbstractType computeSigInstDataType(ConstraintSystem system, SignalInstance instance, TypeConstructorType scheme) {
if(!#["string", "array"].contains(scheme.name)) {
return null;
}

val lengthArg = ModelUtils.getArgumentValue(instance, instance.lengthParameterName);
if(lengthArg !== null) {
val maxLength = StaticValueInferrer.infer(lengthArg, [ ])?.castOrNull(Long);
if(maxLength !== null) {
val u32 = typeRegistry.getTypeModelObject(instance, StdlibTypeRegistry.u32TypeQID);
// sigInst has type resource -> sigInst<string<Size>>
// create string<'10>
val innerReturnType = new TypeConstructorType(instance, type.name,
type.typeArgumentsAndVariances.init + #[
new LiteralNumberType(lengthArg, maxLength, c.system.getTypeVariable(u32)) as AbstractType ->
val innerReturnType = new TypeConstructorType(instance, scheme.name,
scheme.typeArgumentsAndVariances.init + #[
new LiteralNumberType(lengthArg, maxLength, system.getTypeVariable(u32)) as AbstractType ->
Variance.COVARIANT
]
);
// create sigInst<string<'10>>
val returnType = SignalInstanceSizeInferrer.wrapInSigInst(c, typeRegistry, innerReturnType);
val signal = instance.initialization?.castOrNull(ElementReferenceExpression)?.reference?.castOrNull(Signal);
val setup = EcoreUtil2.getContainerOfType(instance, SystemResourceSetup);
val systemResource = setup?.type;
return innerReturnType;
}
}
}

protected dispatch def void doCreateConstraints(InferenceContext c, SystemEventSource eventSource, TypeConstructorType type) {
if(eventSource.signalInstance !== null) {
// we already type this via the eventVariable
return;
}
delegate.createConstraints(c);
}
protected dispatch def void doCreateConstraints(InferenceContext c, EventHandlerVariableDeclaration eventVariable, TypeConstructorType type) {
// if event is part of a signal instance, its initialization could have a size argument which we will use here
if(!#["string", "array"].contains(type.name)) {
return;
}
val eventSource = EcoreUtil2.getContainerOfType(eventVariable, EventHandlerDeclaration)?.event;
val signalInstance = eventSource?.castOrNull(SystemEventSource)?.signalInstance;
if(signalInstance !== null) {
doCreateConstraints(c, signalInstance, type);
ProgramSizeInferrer.inferUnmodifiedFrom(c.system, eventSource, eventVariable);
// signal instance is now typed. Next we need to extract its size
val typeWithSize = computeSigInstDataType(c.system, signalInstance, type);
c.system.associate(typeWithSize, eventVariable);
}
}

protected dispatch def void doCreateConstraints(InferenceContext c, SignalInstance instance, TypeConstructorType type) {
if(!#["string", "array"].contains(type.name)) {
return;
}

val signalTv = c.system.getTypeVariable(signal);
val sigInstFunName = signal?.name + "_inst";
// create resource -> sigInst<string<'10>>
val sigInstSetupType = new FunctionType(
null,
new AtomicType(instance, sigInstFunName),
new ProdType(null, new AtomicType(instance, "__args"), #[c.system.getTypeVariable(systemResource)]),
returnType
);
val innerReturnType = computeSigInstDataType(c.system, instance, type);
if(innerReturnType !== null) {
// create sigInst<string<'10>>
val returnType = SignalInstanceSizeInferrer.wrapInSigInst(c, typeRegistry, innerReturnType);
val signal = instance.initialization?.castOrNull(ElementReferenceExpression)?.reference?.castOrNull(Signal);
val setup = EcoreUtil2.getContainerOfType(instance, SystemResourceSetup);
val systemResource = setup?.type;

val sigInstFunName = signal?.name + "_inst";
// create resource -> sigInst<string<'10>>
val sigInstSetupType = new FunctionType(
null,
new AtomicType(instance, sigInstFunName),
new ProdType(null, new AtomicType(instance, "__args"), #[c.system.getTypeVariable(systemResource)]),
returnType
);
// c.system.addConstraint(new EqualityConstraint(sigInstSetupType, signalTv, new ValidationIssue('''''', c.obj)))
// type sigInst
c.system.associate(sigInstSetupType, instance);
}
// type sigInst
c.system.associate(sigInstSetupType, instance);
}

return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ class RingbufferGenerator extends AbstractTypeGenerator {
),
true
«rbRef.code».length++;
++«rbRef.code».length;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this just a readability issue or did this produce compilation errors?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, preincrement > postincrement, since the latter generates a temporary copy ;)

''').addHeader("MitaGeneratedTypes.h", false);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Ignore everything in this directory
*
# Except the gitignore
!.gitignore
!.gitignore
1 change: 1 addition & 0 deletions bundles/org.eclipse.mita.platform/model/platforms.xcore
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class ConfigurationItem extends Property {
}

class Signal extends Operation {
contains SystemResourceEvent[] events
}
class Modality extends Property {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ ConfigurationItem returns platform::ConfigurationItem:
;

Signal returns platform::Signal:
'signal' name=ID '(' (parameters+=SignalParameter (',' parameters+=SignalParameter)*)? ')' ':' typeSpecifier=TypeSpecifier
'signal' name=ID '(' (parameters+=SignalParameter (',' parameters+=SignalParameter)*)? ')' ':' typeSpecifier=TypeSpecifier ('{'
(events += SystemResourceEvent)*
'}')?
;

SignalParameter returns platform::SignalParameter:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class PlatformConstraintFactory extends BaseConstraintFactory {
// signals are accessed like `mqtt.t.write("foo")`.
// Therefore, t needs the type "(SystemResource, arg1, ...) -> siginst<concreteType>"
// and topic needs to be of type (String, u32) -> ((SystemResource, arg1, ...) -> siginst<concreteType>)
sig.events.forEach[system.computeConstraints(it)];
val returnType = system.computeConstraints(sig.typeSpecifier);
// \T. sigInst<T>
val sigInstType = typeRegistry.getTypeModelObjectProxy(system, sig, StdlibTypeRegistry.sigInstTypeQID);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@
import org.junit.runners.Suite.SuiteClasses;

@SuiteClasses({
ArraysTest.class,
BasicControlStructuresTest.class,
EnumsTest.class,
FunctionOverloadingTest.class,
GlobalAndLocalVariables.class,
PrepareLoopForFunctionUnvravelingStageTest.class,
SensorAccessTest.class,
SetupTest.class,
StructsTest.class,
TryCatchGeneratorTest.class,
UnravelFunctionCallsTest.class,
SumTypesTest.class,
SetupTest.class,
GlobalAndLocalVariables.class,
ArraysTest.class,
SetupTest.class
TryCatchGeneratorTest.class,
UnravelFunctionCallsTest.class
})
@RunWith(Suite.class)
public class AllTests {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class BasicControlStructuresTest extends AbstractGeneratorTest {
''')

ast.assertNoCompileErrors();
val generatedFunction = ast.value.findFunction("HandleEvery100Millisecond1_worker");
val generatedFunction = ast.value.findFunction("HandleEvery100Millisecond_1_worker");
assertNotNull("No event handler was generated", generatedFunction);
val body = generatedFunction.body as IASTCompoundStatement;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import org.junit.Test

import static org.junit.Assert.*
import org.eclipse.cdt.core.dom.ast.IASTDoStatement
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression

class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest {

Expand Down Expand Up @@ -54,7 +56,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest {

val forCondition = forLoop.conditionExpression;
assertTrue("For loop condition was not rewritten", forCondition instanceof IASTIdExpression);
assertEquals("For loop condition was not rewritten to TRUE", "TRUE", (forCondition as IASTIdExpression).name.toString());
assertEquals("For loop condition was not rewritten to true", "true", (forCondition as IASTIdExpression).name.toString());

(forLoop.body as IASTCompoundStatement).assertHasBreakerIf();
}
Expand All @@ -63,6 +65,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest {
def void testForLoopWithCallInPostLoopStatement() {
val ast = generateAndParseApplication('''
package main;
import platforms.unittest;

fn foo() {
return 10;
Expand All @@ -84,19 +87,23 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest {

assertNull("Post loop statement was not rewritten", forLoop.iterationExpression);

val lastStatement = (forLoop.body as IASTCompoundStatement).children.last;
assertTrue("Post loop statement is not the last statement in the loop", lastStatement instanceof IASTExpressionStatement);
val lastExpression = (lastStatement as IASTExpressionStatement).expression;
assertTrue("Post loop statement is not the last statement in the loop", lastExpression instanceof IASTBinaryExpression);
val leftOperand = (lastExpression as IASTBinaryExpression).operand1;
assertTrue("Post loop statement is not the last statement in the loop", leftOperand instanceof IASTIdExpression);
assertEquals("Post loop statement is not the last statement in the loop", "i", (leftOperand as IASTIdExpression).name.toString());
val secondToLastStatement = (forLoop.body as IASTCompoundStatement).children.reverse.get(1);
assertTrue("Post loop statement is not the second to last statement in the loop", secondToLastStatement instanceof IASTExpressionStatement);
val secondToLastExpression = (secondToLastStatement as IASTExpressionStatement).expression;
assertTrue("Post loop statement is not the second to last statement in the loop", secondToLastExpression instanceof IASTBinaryExpression);
val fooCall = (secondToLastExpression as IASTBinaryExpression).operand2;
assertTrue("Post loop statement is not the second to last statement in the loop", fooCall instanceof IASTFunctionCallExpression);
val iRefArg = (fooCall as IASTFunctionCallExpression).arguments.head;
assertTrue("Post loop statement is not the second to last statement in the loop", iRefArg instanceof IASTUnaryExpression);
val iVariable = (iRefArg as IASTUnaryExpression).operand;
assertEquals("Post loop statement is not the second to last statement in the loop", "i", (iVariable as IASTIdExpression).name.toString());
}

@Test
def void testWhileLoopWithCallInCondition() {
val ast = generateAndParseApplication('''
package main;
import platforms.unittest;

fn foo() {
return 10;
Expand All @@ -119,7 +126,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest {

val condition = loop.condition;
assertTrue("For loop condition was not rewritten", condition instanceof IASTIdExpression);
assertEquals("For loop condition was not rewritten to TRUE", "TRUE", (condition as IASTIdExpression).name.toString());
assertEquals("For loop condition was not rewritten to true", "true", (condition as IASTIdExpression).name.toString());

(loop.body as IASTCompoundStatement).assertHasBreakerIf();
}
Expand All @@ -128,6 +135,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest {
def void testDoWhileLoopWithCallInCondition() {
val ast = generateAndParseApplication('''
package main;
import platforms.unittest;

fn foo() {
return 10;
Expand All @@ -150,7 +158,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest {

val condition = loop.condition;
assertTrue("For loop condition was not rewritten", condition instanceof IASTIdExpression);
assertEquals("For loop condition was not rewritten to TRUE", "TRUE", (condition as IASTIdExpression).name.toString());
assertEquals("For loop condition was not rewritten to true", "true", (condition as IASTIdExpression).name.toString());

(loop.body as IASTCompoundStatement).assertHasBreakerIf();
}
Expand All @@ -165,7 +173,7 @@ class PrepareLoopForFunctionUnvravelingStageTest extends AbstractGeneratorTest {
return op.operand1 instanceof IASTIdExpression && ((op.operand1 as IASTIdExpression).name.toString() == "i");
];
assertNotNull("No breaker if statement was generated", breakerIf);
val hasBreakStatement = (breakerIf.thenClause as IASTCompoundStatement).statements.exists[ it instanceof IASTBreakStatement ];
val hasBreakStatement = (breakerIf.elseClause as IASTCompoundStatement).statements.exists[ it instanceof IASTBreakStatement ];
assertTrue("Breaker if has no break statement", hasBreakStatement);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class SensorAccessTest extends AbstractGeneratorTest {
''');
ast.assertNoCompileErrors();

val eventHandler = ast.value.findFunction("HandleEvery100Millisecond1_worker")
val eventHandler = ast.value.findFunction("HandleEvery100Millisecond_1_worker")
assertNotNull("No event handler was generated", eventHandler);
val body = eventHandler.body as IASTCompoundStatement;
/*
Expand Down
Loading