From 7d5264abbb6d1bf8821ccef6eecccd1a2cddc3f0 Mon Sep 17 00:00:00 2001 From: david roon Date: Sun, 12 Jan 2020 15:33:17 -0500 Subject: [PATCH 1/3] fixing variable type resolution if the definition is in a sub execution --- .../parser/template/VariableDefinition.scala | 6 ++++-- .../openlaw/vm/OpenlawExecutionEngineSpec.scala | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) 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 caf3a2aba..c7f89f610 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 @@ -166,8 +166,10 @@ 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 = + variableTypeDefinition + .flatMap(typeDefinition => (executionResult :: executionResult.subExecutions.values.toList).flatMap(_.findVariableType(typeDefinition)).headOption) + .getOrElse(TextType) def verifyConstructor(executionResult: TemplateExecutionResult): Result[Option[Any]] = { implicit val eqCls:Eq[Class[_]] = Eq.fromUniversalEquals 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 bcefacc3a..e305a6fd2 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,20 @@ 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( + """[[my variable:Number]]""".stripMargin) + + engine.execute(mainTemplate, TemplateParameters(), Map(TemplateSourceIdentifier(TemplateTitle("clause")) -> clauseTemplate,TemplateSourceIdentifier(TemplateTitle("clause")) -> clauseTemplate)) match { + case Right(result) => + val Some(variable) = result.getVariable("my variable") + variable.varType(result) shouldBe NumberType + case Left(ex) => + fail(ex.message, ex) + } + } + it should "fail if it makes a divide by zero error" in { val template = compile(""" From f72822ea0dd26ed39697074d11d2d59e751f52c7 Mon Sep 17 00:00:00 2001 From: david roon Date: Mon, 13 Jan 2020 18:31:56 -0500 Subject: [PATCH 2/3] fixing situation where a parameter is not known, instead of returning TextType, rather return ParameterType error message for EthereumAddress more useful --- .../parser/template/StructuredDocument.scala | 27 ++++---- .../parser/template/VariableDefinition.scala | 7 ++- .../variableTypes/EthAddressType.scala | 2 +- .../vm/OpenlawExecutionEngineSpec.scala | 61 ++++++++++++++++++- 4 files changed, 79 insertions(+), 18 deletions(-) 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 a52e2a86b..5b13ac7b0 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 @@ -305,24 +305,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 c7f89f610..5dc1ae90a 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 @@ -167,9 +167,10 @@ final case class VariableDefinition(name: VariableName, variableTypeDefinition:O def isAnonymous: Boolean = name.isAnonymous def varType(executionResult: TemplateExecutionResult):VariableType = - variableTypeDefinition - .flatMap(typeDefinition => (executionResult :: executionResult.subExecutions.values.toList).flatMap(_.findVariableType(typeDefinition)).headOption) - .getOrElse(TextType) + (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 e305a6fd2..a7ff93dae 100644 --- a/shared/src/test/scala/org/adridadou/openlaw/vm/OpenlawExecutionEngineSpec.scala +++ b/shared/src/test/scala/org/adridadou/openlaw/vm/OpenlawExecutionEngineSpec.scala @@ -731,17 +731,72 @@ 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( - """[[my variable:Number]]""".stripMargin) + """ + |<% + |# 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 Some(variable) = result.getVariable("my variable") - variable.varType(result) shouldBe NumberType + 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 = { + println(variable.variableTypeDefinition) + 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(""" From 5aeb1851e5e1fadc4f5f834da0832f4c2da3cad9 Mon Sep 17 00:00:00 2001 From: david roon Date: Mon, 20 Jan 2020 13:01:46 +0100 Subject: [PATCH 3/3] remove println --- .../org/adridadou/openlaw/vm/OpenlawExecutionEngineSpec.scala | 1 - 1 file changed, 1 deletion(-) 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 52bf2e404..98bbcf753 100644 --- a/shared/src/test/scala/org/adridadou/openlaw/vm/OpenlawExecutionEngineSpec.scala +++ b/shared/src/test/scala/org/adridadou/openlaw/vm/OpenlawExecutionEngineSpec.scala @@ -784,7 +784,6 @@ class OpenlawExecutionEngineSpec extends FlatSpec with Matchers { } def getCollection(variable:VariableDefinition, executionResult: TemplateExecutionResult, value:String):CollectionValue = { - println(variable.variableTypeDefinition) variable.varType(executionResult) match { case collectionType:CollectionType => if(value.isEmpty) {