diff --git a/shared/src/main/scala/org/adridadou/openlaw/parser/template/StructuredDocument.scala b/shared/src/main/scala/org/adridadou/openlaw/parser/template/StructuredDocument.scala index 6ea6f6cc4..410547618 100644 --- a/shared/src/main/scala/org/adridadou/openlaw/parser/template/StructuredDocument.scala +++ b/shared/src/main/scala/org/adridadou/openlaw/parser/template/StructuredDocument.scala @@ -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) diff --git a/shared/src/main/scala/org/adridadou/openlaw/parser/template/VariableDefinition.scala b/shared/src/main/scala/org/adridadou/openlaw/parser/template/VariableDefinition.scala index 36c696cbb..a351e3c5a 100644 --- a/shared/src/main/scala/org/adridadou/openlaw/parser/template/VariableDefinition.scala +++ b/shared/src/main/scala/org/adridadou/openlaw/parser/template/VariableDefinition.scala @@ -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 diff --git a/shared/src/main/scala/org/adridadou/openlaw/parser/template/variableTypes/EthAddressType.scala b/shared/src/main/scala/org/adridadou/openlaw/parser/template/variableTypes/EthAddressType.scala index 1f4803a1e..9c2d31df5 100644 --- a/shared/src/main/scala/org/adridadou/openlaw/parser/template/variableTypes/EthAddressType.scala +++ b/shared/src/main/scala/org/adridadou/openlaw/parser/template/variableTypes/EthAddressType.scala @@ -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)) } diff --git a/shared/src/test/scala/org/adridadou/openlaw/vm/OpenlawExecutionEngineSpec.scala b/shared/src/test/scala/org/adridadou/openlaw/vm/OpenlawExecutionEngineSpec.scala index 1093c2483..64e458b58 100644 --- a/shared/src/test/scala/org/adridadou/openlaw/vm/OpenlawExecutionEngineSpec.scala +++ b/shared/src/test/scala/org/adridadou/openlaw/vm/OpenlawExecutionEngineSpec.scala @@ -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]] + | + |==MOU Parties== + |[[Party Info: Structure( + | Party Name: Text; + | Party Email: Identity + | )]] + |[[#Parties: Collection]] + |%> + | + |\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("""