Skip to content

Commit

Permalink
Fix type resolution in sub execution (#209)
Browse files Browse the repository at this point in the history
* fixing variable type resolution if the definition is in a sub execution

* fixing situation where a parameter is not known, instead of returning TextType, rather return ParameterType<Text>

error message for EthereumAddress more useful

* remove println
  • Loading branch information
adridadou authored Jan 20, 2020
1 parent c5556d2 commit 20cd570
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -302,24 +302,29 @@ trait TemplateExecutionResult {
}}).variables.map(_.name)

def findVariableType(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] = {
val mainType = findVariableTypeInternal(variableTypeDefinition)
val parameterType = variableTypeDefinition.typeParameter.flatMap(findVariableTypeInternal)
val mainType = findVariableTypeAllDirection(variableTypeDefinition)
val parameterType = variableTypeDefinition.typeParameter.flatMap(findVariableTypeAllDirection)
mainType match {
case Some(varType:ParameterTypeProvider) =>
parameterType.map(varType.createParameterInstance)
Some(varType.createParameterInstance(parameterType.getOrElse(TextType)))
case other =>
other
}
}

private def findVariableTypeInternal(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] =
variableTypes.find(_.checkTypeName(variableTypeDefinition.name)) match {
case Some(variableType) =>
Some(variableType)
case None =>
parentExecution
.flatMap(_.findVariableType(variableTypeDefinition))
}
private def findVariableTypeAllDirection(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] =
findVariableTypeInternalCurrent(variableTypeDefinition) orElse
findVariableTypeInternalParent(variableTypeDefinition) orElse
findVariableTypeInternalEmbedded(variableTypeDefinition)

def findVariableTypeInternalCurrent(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] =
variableTypes.find(_.checkTypeName(variableTypeDefinition.name))

def findVariableTypeInternalParent(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] =
parentExecution.flatMap(parent => parent.findVariableTypeInternalCurrent(variableTypeDefinition) orElse parent.findVariableTypeInternalParent(variableTypeDefinition))

def findVariableTypeInternalEmbedded(variableTypeDefinition: VariableTypeDefinition):Option[VariableType] =
subExecutions.values.filter(_.embedded).flatMap(subExecution => subExecution.findVariableTypeInternalCurrent(variableTypeDefinition) orElse subExecution.findVariableType(variableTypeDefinition)).headOption

def getSignatureProof(identity: Identity):Option[SignatureProof] = signatureProofs.get(identity.email) match {
case Some(value) => Some(value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,11 @@ final case class VariableDefinition(name: VariableName, variableTypeDefinition:O

def isAnonymous: Boolean = name.isAnonymous

def varType(executionResult: TemplateExecutionResult):VariableType = variableTypeDefinition
.flatMap(typeDefinition => executionResult.findVariableType(typeDefinition)).getOrElse(TextType)
def varType(executionResult: TemplateExecutionResult):VariableType =
(for {
typeDefinition <- variableTypeDefinition
variableType <- executionResult.findVariableType(typeDefinition)
} yield variableType).getOrElse(TextType)

def verifyConstructor(executionResult: TemplateExecutionResult): Result[Option[Any]] = {
implicit val eqCls:Eq[Class[_]] = Eq.fromUniversalEquals
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ object EthereumAddress {
def apply(a: String): Result[EthereumAddress] = Option(a) match {
case None => empty
case Some(address) if address.startsWith("0x") => apply(address.substring(2))
case Some(address) if address.length =!= 40 => Failure("the address string should be 40 or 42 with '0x' prefix")
case Some(address) if address.length =!= 40 => Failure(s"the address string should be 40 or 42 with '0x' prefix. value(${address})")
case Some(address) => apply(hex2bytes(address))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,74 @@ class OpenlawExecutionEngineSpec extends FlatSpec with Matchers {
}
}

it should "look at sub execution results for variable type" in {
val mainTemplate = compile("""[[c:Clause("clause")]]""")
val clauseTemplate = compile(
"""
|<%
|# Arranged Variables by Header
|==MOU Terms==
|[[Terms: Collection<Text>]]
|
|==MOU Parties==
|[[Party Info: Structure(
| Party Name: Text;
| Party Email: Identity
| )]]
|[[#Parties: Collection<Party Info>]]
|%>
|
|\centered **__MEMORANDUM OF UNDERSTANDING__**
|
|**NOW, THEREFORE,** the undersigned parties (the "***Parties***") see mutual benefit in entering into a partnership and formalizing their cooperation over the matters and under the terms sufficiently described in this Memorandum of Understanding ("***MOU***"):
|
|{{#for each Term: Terms =>
|
| ^^[[Term]]
|}}
|
|The Parties shall keep confidential and shall not divulge to any other party, without the other's prior written consent, any non-public information concerning this MOU and the cooperation contemplated hereby, treating such confidential information with the same due care as their own proprietary information.
|
|The Parties shall jointly operate and exchange information with the intention of completing the transactions contemplated hereby and within determined timeframes and reasonable best efforts.
|
|After a preliminary review period, not to exceed two (2) months from the date of mutual execution below, the Parties may enter into a legally-binding agreement regarding these matters and shall make reasonable best efforts to conduct a meeting regarding the same following such MOU review period.
|
|This MOU is not a legally-binding agreement.
|
|***__SIGNATORIES__***
|
|{{#for each Party: Parties =>
|
|**[[Party.Party Name | Uppercase]]**
|
|*__[[Party.Party Email | Signature]]__*
|Authorized Representative
|
|}}
|""".stripMargin)

engine.execute(mainTemplate, TemplateParameters(), Map(TemplateSourceIdentifier(TemplateTitle("clause")) -> clauseTemplate,TemplateSourceIdentifier(TemplateTitle("clause")) -> clauseTemplate)) match {
case Right(result) =>
val variable = VariableDefinition(VariableName("Parties"), Some(VariableTypeDefinition("Collection",Some(VariableTypeDefinition("Parefhuzegfty Info",None)))))
getCollection(variable, result, "")
case Left(ex) =>
fail(ex.message, ex)
}
}

def getCollection(variable:VariableDefinition, executionResult: TemplateExecutionResult, value:String):CollectionValue = {
variable.varType(executionResult) match {
case collectionType:CollectionType =>
if(value.isEmpty) {
CollectionValue(collectionType = collectionType)
} else {
VariableType.convert[CollectionValue](collectionType.cast(value, executionResult).getOrThrow()).getOrThrow()
}
case other =>
throw new RuntimeException(s"add element to collection only works for a variable of type Collection, not '${other.name}'")
}
}

it should "fail if it makes a divide by zero error" in {
val template =
compile("""
Expand Down

0 comments on commit 20cd570

Please sign in to comment.