Effects: add interpreters of ContractDescription

Interpreters convert declarative representation of contracts
(ContractDescription) in internal representation convenient for usage
inside compiler (Computations, Effects, etc.)

==========
Effect System introduction: 3/18
This commit is contained in:
Dmitry Savvinov
2017-10-03 15:02:27 +03:00
parent afc15e9211
commit d2e582698e
5 changed files with 246 additions and 0 deletions
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.interpretation
import org.jetbrains.kotlin.contracts.description.*
import org.jetbrains.kotlin.contracts.description.expressions.*
import org.jetbrains.kotlin.contracts.model.ESExpression
import org.jetbrains.kotlin.contracts.model.functors.IsFunctor
import org.jetbrains.kotlin.contracts.model.structure.*
internal class ConditionInterpreter(private val dispatcher: ContractInterpretationDispatcher) : ContractDescriptionVisitor<ESExpression?, Unit> {
override fun visitLogicalOr(logicalOr: LogicalOr, data: Unit): ESExpression? {
val left = logicalOr.left.accept(this, data) ?: return null
val right = logicalOr.right.accept(this, data) ?: return null
return ESOr(left, right)
}
override fun visitLogicalAnd(logicalAnd: LogicalAnd, data: Unit): ESExpression? {
val left = logicalAnd.left.accept(this, data) ?: return null
val right = logicalAnd.right.accept(this, data) ?: return null
return ESAnd(left, right)
}
override fun visitLogicalNot(logicalNot: LogicalNot, data: Unit): ESExpression? {
val arg = logicalNot.arg.accept(this, data) ?: return null
return ESNot(arg)
}
override fun visitIsInstancePredicate(isInstancePredicate: IsInstancePredicate, data: Unit): ESExpression? {
val esVariable = dispatcher.interpretVariable(isInstancePredicate.arg) ?: return null
return ESIs(esVariable, IsFunctor(isInstancePredicate.type, isInstancePredicate.isNegated))
}
override fun visitIsNullPredicate(isNullPredicate: IsNullPredicate, data: Unit): ESExpression? {
val variable = dispatcher.interpretVariable(isNullPredicate.arg) ?: return null
return ESEqual(variable, ESConstant.NULL, isNullPredicate.isNegated)
}
override fun visitBooleanConstantDescriptor(booleanConstantDescriptor: BooleanConstantReference, data: Unit): ESExpression? =
dispatcher.interpretConstant(booleanConstantDescriptor)
override fun visitBooleanVariableReference(booleanVariableReference: BooleanVariableReference, data: Unit): ESExpression? =
dispatcher.interpretVariable(booleanVariableReference)
}
@@ -0,0 +1,33 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.interpretation
import org.jetbrains.kotlin.contracts.description.expressions.BooleanConstantReference
import org.jetbrains.kotlin.contracts.description.expressions.ConstantReference
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
import org.jetbrains.kotlin.contracts.model.structure.lift
internal class ConstantValuesInterpreter {
fun interpretConstant(constantReference: ConstantReference): ESConstant? = when (constantReference) {
BooleanConstantReference.TRUE -> true.lift()
BooleanConstantReference.FALSE -> false.lift()
ConstantReference.NULL-> ESConstant.NULL
ConstantReference.NOT_NULL -> ESConstant.NOT_NULL
ConstantReference.WILDCARD -> ESConstant.WILDCARD
else -> null
}
}
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.interpretation
import org.jetbrains.kotlin.contracts.description.*
import org.jetbrains.kotlin.contracts.description.expressions.ConstantReference
import org.jetbrains.kotlin.contracts.description.expressions.VariableReference
import org.jetbrains.kotlin.contracts.model.functors.SubstitutingFunctor
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
import org.jetbrains.kotlin.contracts.model.structure.ESVariable
import org.jetbrains.kotlin.contracts.model.ESEffect
import org.jetbrains.kotlin.contracts.model.ESExpression
import org.jetbrains.kotlin.contracts.model.Functor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
/**
* This class manages conversion of [ContractDescription] to [Functor]
*/
class ContractInterpretationDispatcher {
private val constantsInterpreter = ConstantValuesInterpreter()
private val conditionInterpreter = ConditionInterpreter(this)
private val conditionalEffectInterpreter = ConditionalEffectInterpreter(this)
private val effectsInterpreters: List<EffectDeclarationInterpreter> = listOf(
ReturnsEffectInterpreter(this),
CallsEffectInterpreter(this)
)
fun resolveFunctor(functionDescriptor: FunctionDescriptor): Functor? {
val contractDescriptor = functionDescriptor.getUserData(ContractProviderKey)?.getContractDescription() ?: return null
return convertContractDescriptorToFunctor(contractDescriptor)
}
private fun convertContractDescriptorToFunctor(contractDescription: ContractDescription): Functor? {
val resultingClauses = contractDescription.effects.map { effect ->
if (effect is ConditionalEffectDeclaration) {
conditionalEffectInterpreter.interpret(effect) ?: return null
}
else {
effectsInterpreters.mapNotNull { it.tryInterpret(effect) }.singleOrNull() ?: return null
}
}
return SubstitutingFunctor(resultingClauses, contractDescription.ownerFunction)
}
internal fun interpretEffect(effectDeclaration: EffectDeclaration): ESEffect? {
val convertedFunctors = effectsInterpreters.mapNotNull { it.tryInterpret(effectDeclaration) }
return convertedFunctors.singleOrNull()
}
internal fun interpretConstant(constantReference: ConstantReference): ESConstant? =
constantsInterpreter.interpretConstant(constantReference)
internal fun interpretCondition(booleanExpression: BooleanExpression): ESExpression? =
booleanExpression.accept(conditionInterpreter, Unit)
internal fun interpretVariable(variableReference: VariableReference): ESVariable? = ESVariable(variableReference.descriptor)
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.interpretation
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
import org.jetbrains.kotlin.contracts.model.ESEffect
/**
* Interpreter of some effects. For most cases, each particular
* EffectDeclaration, EffectDeclarationInterpreter and ESEffect
* should be in 1-1-1 correspondence to each other and be agnostic
* about other implementations.
*/
internal interface EffectDeclarationInterpreter {
fun tryInterpret(effectDeclaration: EffectDeclaration): ESEffect?
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.contracts.interpretation
import org.jetbrains.kotlin.contracts.description.CallsEffectDeclaration
import org.jetbrains.kotlin.contracts.description.ConditionalEffectDeclaration
import org.jetbrains.kotlin.contracts.description.EffectDeclaration
import org.jetbrains.kotlin.contracts.description.ReturnsEffectDeclaration
import org.jetbrains.kotlin.contracts.model.ConditionalEffect
import org.jetbrains.kotlin.contracts.model.ESEffect
import org.jetbrains.kotlin.contracts.model.SimpleEffect
import org.jetbrains.kotlin.contracts.model.structure.ESCalls
import org.jetbrains.kotlin.contracts.model.structure.ESReturns
internal class CallsEffectInterpreter(private val dispatcher: ContractInterpretationDispatcher) : EffectDeclarationInterpreter {
override fun tryInterpret(effectDeclaration: EffectDeclaration): ESEffect? {
if (effectDeclaration !is CallsEffectDeclaration) return null
val variable = dispatcher.interpretVariable(effectDeclaration.variableReference) ?: return null
val kind = effectDeclaration.kind
return ESCalls(variable, kind)
}
}
internal class ConditionalEffectInterpreter(private val dispatcher: ContractInterpretationDispatcher) {
fun interpret(conditionalEffectDeclaration: ConditionalEffectDeclaration): ConditionalEffect? {
val effect = dispatcher.interpretEffect(conditionalEffectDeclaration.effect) as? SimpleEffect ?: return null
val condition = dispatcher.interpretCondition(conditionalEffectDeclaration.condition) ?: return null
return ConditionalEffect(condition, effect)
}
}
internal class ReturnsEffectInterpreter(private val dispatcher: ContractInterpretationDispatcher) : EffectDeclarationInterpreter {
override fun tryInterpret(effectDeclaration: EffectDeclaration): ESEffect? {
if (effectDeclaration !is ReturnsEffectDeclaration) return null
val returnedValue = dispatcher.interpretConstant(effectDeclaration.value) ?: return null
return ESReturns(returnedValue)
}
}