From 2132b0c64236375fc34748cc98caddc6ffb88018 Mon Sep 17 00:00:00 2001 From: dours Date: Tue, 21 Jun 2022 23:16:56 +0300 Subject: [PATCH 1/5] Update README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 2066f50cb..01be945e3 100644 --- a/README.md +++ b/README.md @@ -613,3 +613,15 @@ print(x) ### 8.8 Coroutines No plans to support this. + +### Print +`print(x)` is translated to `stdout (sprintf "%s" (xx.as-string))` + You may use this example: + ``` + x = 1 + print(x) + ``` + or this + ``` + print("Hello, world!") + ``` From 404abb8f2eb88e0ece8348f879c09599e6fb88be Mon Sep 17 00:00:00 2001 From: dours Date: Tue, 21 Jun 2022 23:36:51 +0300 Subject: [PATCH 2/5] Update README.md --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/README.md b/README.md index 01be945e3..69bd0e400 100644 --- a/README.md +++ b/README.md @@ -92,8 +92,61 @@ For all `.py` files (every `.py` is considered as particular test) from Django r ## 2.1 Comments, Identation, Explicit and Implicit line joining, Whitespace between tokens These things are supported by the parser. No additional support is needed, because these are just pecularities of the syntax. +## 4. Execution model +### 4.2.1 4.2.2 Names +Dynamically adding/removing names is not supported. All the statically known names are implemented as a `cage` object of EO. This allows to implement assignments. EO objects are also visibility scopes for identifiers, so several variables with the same name in different scopes are implemented directly. + +### 4.3 Exceptions +Exceptions, `break`, `continue`, `return` are currently all implemented with the help of the `goto` object. + +Consider this python code +``` +while True: break +``` +We can translate it this way +``` +goto + [doBreak] + TRUE.while + doBreak.forward 0 +``` +Now consider this: +``` +flag = 5 +while True: + try: + break + finally: flag = 10 +``` +From [this section](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement) we know that "When a [return](https://docs.python.org/3/reference/simple_stmts.html#return), [break](https://docs.python.org/3/reference/simple_stmts.html#break) or [continue](https://docs.python.org/3/reference/simple_stmts.html#continue) statement is executed in the [try](https://docs.python.org/3/reference/compound_stmts.html#try) suite of a try…[finally](https://docs.python.org/3/reference/compound_stmts.html#finally) statement, the finally clause is also executed ‘on the way out.’". +So, our implementation of `try` by means of `goto` must catch both exceptions and the `break`. It then must execute `finally` and rethrow everything that was not processed by the `except` clause (including `break`). The `break` then will be caught again up the stack by the implementation of `while`. +Like so: +``` +flag.write 5 +goto + [stackUp] + TRUE.while + write. + resultOfTry + goto + [stackUp] + stackUp.forward breakConstant // this is the break + if. + is-exception resultOfTry + // here goes the implementation of except clause, which is BTW empty in our example + 0 + flag.write 10 // here goes the implementation of finally, so it is executed for exceptions and for the break + if. + is-break resultOfTry + stackUp.forward resultOfTry // redirect the break further up the stack + 0 +``` + +We may also imagine a `return` that happens somewhere deep in the hierarchy of whiles and trys. This is a kind of semi-manual stack unwinding, IMHO. + + ## 6. Expressions ### 6.1 Arithmetic conversion From 33696229af1315b768546178673d8a77da1509dc Mon Sep 17 00:00:00 2001 From: dours Date: Wed, 22 Jun 2022 00:54:11 +0300 Subject: [PATCH 3/5] add a number of hacks to make the django test pass again --- transpiler/src/main/eo/preface/newUID.eo | 2 +- transpiler/src/main/eo/preface/xTypeError.eo | 13 +++++++++++++ transpiler/src/main/eo/preface/xiter.eo | 4 ++++ .../org/polystat/py2eo/transpiler/Main.scala | 2 +- .../PrintLinearizedMutableEOWithCage.scala | 4 ++++ .../polystat/py2eo/transpiler/Transpile.scala | 4 ++-- .../org/polystat/py2eo/transpiler/Commons.scala | 8 +++++++- .../org/polystat/py2eo/transpiler/Tests.scala | 16 +++++++++++----- 8 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 transpiler/src/main/eo/preface/xTypeError.eo create mode 100644 transpiler/src/main/eo/preface/xiter.eo diff --git a/transpiler/src/main/eo/preface/newUID.eo b/transpiler/src/main/eo/preface/newUID.eo index b0d9168c7..59739c5af 100644 --- a/transpiler/src/main/eo/preface/newUID.eo +++ b/transpiler/src/main/eo/preface/newUID.eo @@ -2,7 +2,7 @@ +alias pyint preface.pyint [] > newUID - memory 11 > cur + memory 12 > cur [unused] > apply seq > @ cur.write (cur.plus (1)) diff --git a/transpiler/src/main/eo/preface/xTypeError.eo b/transpiler/src/main/eo/preface/xTypeError.eo new file mode 100644 index 000000000..5e0f7082b --- /dev/null +++ b/transpiler/src/main/eo/preface/xTypeError.eo @@ -0,0 +1,13 @@ ++package preface ++alias pyint preface.pyint ++alias return preface.return ++alias cage org.eolang.cage + +[] > xTypeError + pyint 11 > x__id__ + [] > apply + [stackUp] > @ + cage result > pResult + [] > result + xTypeError > x__class__ + stackUp.forward (return pResult) > @ diff --git a/transpiler/src/main/eo/preface/xiter.eo b/transpiler/src/main/eo/preface/xiter.eo new file mode 100644 index 000000000..f7f1162e6 --- /dev/null +++ b/transpiler/src/main/eo/preface/xiter.eo @@ -0,0 +1,4 @@ ++package preface + +[] > xiter + diff --git a/transpiler/src/main/scala/org/polystat/py2eo/transpiler/Main.scala b/transpiler/src/main/scala/org/polystat/py2eo/transpiler/Main.scala index ddd82cc4f..e02d5f6e3 100644 --- a/transpiler/src/main/scala/org/polystat/py2eo/transpiler/Main.scala +++ b/transpiler/src/main/scala/org/polystat/py2eo/transpiler/Main.scala @@ -74,7 +74,7 @@ object Main { } Transpile(input.stripExtension, input.slurp) match { - case None => println("Not Supported: input file syntax is not python 3.8") + case None => println("\"Not Supported: input file syntax is not python 3.8\" > error") case Some(transpiled) => output.createFile().writeAll(transpiled) } } diff --git a/transpiler/src/main/scala/org/polystat/py2eo/transpiler/PrintLinearizedMutableEOWithCage.scala b/transpiler/src/main/scala/org/polystat/py2eo/transpiler/PrintLinearizedMutableEOWithCage.scala index ef06028e0..ef821022a 100644 --- a/transpiler/src/main/scala/org/polystat/py2eo/transpiler/PrintLinearizedMutableEOWithCage.scala +++ b/transpiler/src/main/scala/org/polystat/py2eo/transpiler/PrintLinearizedMutableEOWithCage.scala @@ -38,7 +38,9 @@ object PrintLinearizedMutableEOWithCage { "+alias raiseEmpty preface.raiseEmpty", "+alias xmyArray preface.xmyArray", "+alias xlen preface.xlen", + "+alias xiter preface.xiter", "+alias xStopIteration preface.xStopIteration", + "+alias xTypeError preface.xTypeError", "+alias xZeroDivisionError preface.xZeroDivisionError", "+alias xrange preface.xrange", // "+alias sprintf org.eolang.txt.sprintf", @@ -340,6 +342,8 @@ object PrintLinearizedMutableEOWithCage { "xlen > dummy-xlen", "xStopIteration > dummy-stop-iteration", "xZeroDivisionError > dummy-xZeroDivisionError", + "xTypeError > dummy-xTypeError", + "xiter > dummy-xiter", "xrange > dummy-xrange", ) } diff --git a/transpiler/src/main/scala/org/polystat/py2eo/transpiler/Transpile.scala b/transpiler/src/main/scala/org/polystat/py2eo/transpiler/Transpile.scala index ebec87ba6..c1453890c 100644 --- a/transpiler/src/main/scala/org/polystat/py2eo/transpiler/Transpile.scala +++ b/transpiler/src/main/scala/org/polystat/py2eo/transpiler/Transpile.scala @@ -20,7 +20,7 @@ object Transpile { } def transpile(debugPrinter: (Statement.T, String) => Unit)(moduleName: String, opt : Parameters, pythonCode: String): String = { - transpileOption(debugPrinter)(moduleName, opt, pythonCode).getOrElse("Not Supported: input file syntax is not python 3.8") + transpileOption(debugPrinter)(moduleName, opt, pythonCode).getOrElse("\"Not Supported: input file syntax is not python 3.8\" > error") } def applyStyle(pythonCode: String): Option[String] = { @@ -120,7 +120,7 @@ object Transpile { })(immutable.HashSet(), hacked) PrintEO.printSt( - moduleName, hacked, + ("y" + moduleName).replaceAll("[^0-9a-zA-Z]", ""), hacked, "+package org.eolang" :: "+alias pyint preface.pyint" :: "+alias pyfloat preface.pyfloat" :: diff --git a/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Commons.scala b/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Commons.scala index 4b2cb06cd..0c7a11a03 100644 --- a/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Commons.scala +++ b/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Commons.scala @@ -92,7 +92,13 @@ trait Commons { } def writeFile(test: File, dirSuffix: String, fileSuffix: String, what: String, otherLocation: Boolean = false): File = { - val moduleName = test.getName.substring(0, test.getName.lastIndexOf(".")) + val moduleName0 = test.getName.substring(0, test.getName.lastIndexOf(".")) + // do something with hidden files, because current EO fails them + val moduleName = if (moduleName0.startsWith(".")) { + "p" + moduleName0.substring(1, moduleName0.length) + } else { + moduleName0 + } val outPath = if (!otherLocation) test.getAbsoluteFile.getParentFile.getPath + "/" + dirSuffix else dirSuffix val d = new File(outPath) if (!d.exists()) d.mkdir() diff --git a/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala b/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala index 0afb489f9..8bfc51d14 100644 --- a/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala +++ b/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala @@ -5,21 +5,23 @@ import org.polystat.py2eo.parser.Statement import org.polystat.py2eo.transpiler.Common.dfsFiles import java.io.File +import java.nio.file.{Files, StandardCopyOption} import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration.Duration import scala.concurrent.{Await, Future} +import scala.jdk.javaapi.CollectionConverters.asScala import scala.language.postfixOps -import scala.sys.process.Process +import scala.sys.process.{Process, ProcessLogger} class Tests extends Commons { @Ignore @Test def genUnsupportedDjango() : Unit = { - val root = new File(testsPrefix) - val django = new File(testsPrefix + "/django") + val root = new File("/tmp") + val django = new File("/tmp/django") if (!django.exists()) { // assert(0 == Process("git clone file:///home/bogus/pythonProjects/django", root).!) - assert(0 == Process("git clone https://github.com/django/django", root).!) + assert(0 == Process("git clone -b 4.0 https://github.com/django/django", root).!) } val test = dfsFiles(django).filter(f => f.getName.endsWith(".py")) val futures = test.map(test => @@ -28,7 +30,11 @@ class Tests extends Commons { val name = test.getName println(s"parsing $name") val eoText = try { - Transpile.transpile(db)(chopExtension(name), Transpile.Parameters(wrapInAFunction = false), readFile(test)) + Transpile.transpile(db)( + chopExtension(name), + Transpile.Parameters(wrapInAFunction = false), + readFile(test) + ) } catch { case e : Throwable => println(s"failed to transpile $name: ${e.toString}") From 90418d35e12bfcd9a0a437b6abaf61c9a05fc312 Mon Sep 17 00:00:00 2001 From: dours Date: Wed, 22 Jun 2022 00:54:34 +0300 Subject: [PATCH 4/5] add the django syntax check test in scala --- .../org/polystat/py2eo/transpiler/Tests.scala | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala b/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala index 8bfc51d14..ebc7e16db 100644 --- a/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala +++ b/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala @@ -45,4 +45,33 @@ class Tests extends Commons { ) for (f <- futures) Await.result(f, Duration.Inf) } + + @Ignore + @Test def checkSyntaxForDjango() : Unit = { + val django = new File("/tmp/django") + val eopaths = asScala(Files.walk(django.toPath).filter(f => f.endsWith("genUnsupportedEO")).toList) + val futures = eopaths.map(path => + Future { + val from = new File(testsPrefix + "/django-pom.xml").toPath + val to = new File(path.toString + "/pom.xml").toPath + println(s"$from -> $to") + Files.copy(from, to, StandardCopyOption.REPLACE_EXISTING) + assert(0 == Process( + s"cp -a '$testsPrefix/../../../../../../main/eo/preface/' ${path.toString}" + ).! + ) + assert(0 == Process("mvn clean test", path.toFile).!) + assert(0 == Process(s"rm -rf ${path.toString}").!) +// val stdout = new StringBuilder +// val stderr = new StringBuilder +// val exitCode = Process("mvn clean test", path.toFile) ! ProcessLogger(stdout append _, stderr append _) +// if (0 != exitCode) { +// println(s"for path $to stdout is \n $stdout\n stderr is \n $stderr\n") +// } else { +// assert(0 == Process(s"rm -rf ${path.toString}").!) +// } + } + ) + for (f <- futures) Await.result(f, Duration.Inf) + } } From 45363e8ddd5bb53c1393b913567ddf4c31d99e9a Mon Sep 17 00:00:00 2001 From: dours Date: Wed, 22 Jun 2022 11:54:06 +0300 Subject: [PATCH 5/5] fix for a missing '.toList' --- .../test/scala/org/polystat/py2eo/transpiler/Tests.scala | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala b/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala index ebc7e16db..098d42df5 100644 --- a/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala +++ b/transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala @@ -6,6 +6,8 @@ import org.polystat.py2eo.transpiler.Common.dfsFiles import java.io.File import java.nio.file.{Files, StandardCopyOption} +import java.util.stream.Collectors +import scala.:: import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration.Duration import scala.concurrent.{Await, Future} @@ -49,7 +51,7 @@ class Tests extends Commons { @Ignore @Test def checkSyntaxForDjango() : Unit = { val django = new File("/tmp/django") - val eopaths = asScala(Files.walk(django.toPath).filter(f => f.endsWith("genUnsupportedEO")).toList) + val eopaths = Files.walk(django.toPath).filter(f => f.endsWith("genUnsupportedEO")) val futures = eopaths.map(path => Future { val from = new File(testsPrefix + "/django-pom.xml").toPath @@ -72,6 +74,6 @@ class Tests extends Commons { // } } ) - for (f <- futures) Await.result(f, Duration.Inf) + futures.forEach(f => Await.result(f, Duration.Inf)) } }