Skip to content

Commit

Permalink
Merge branch 'master' into django
Browse files Browse the repository at this point in the history
# Conflicts:
#	transpiler/src/test/scala/org/polystat/py2eo/transpiler/Tests.scala
  • Loading branch information
bugdea1er committed Jun 22, 2022
2 parents dc24d18 + 45363e8 commit a1fa896
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 5 deletions.
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -613,3 +666,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!")
```
2 changes: 1 addition & 1 deletion transpiler/src/main/eo/preface/newUID.eo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
+alias pyint preface.pyint

[] > newUID
memory 11 > cur
memory 12 > cur
[unused] > apply
seq > @
cur.write (cur.plus (1))
Expand Down
13 changes: 13 additions & 0 deletions transpiler/src/main/eo/preface/xTypeError.eo
Original file line number Diff line number Diff line change
@@ -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) > @
4 changes: 4 additions & 0 deletions transpiler/src/main/eo/preface/xiter.eo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
+package preface

[] > xiter

Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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] = {
Expand Down Expand Up @@ -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" ::
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,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()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.polystat.py2eo.transpiler

import org.junit.{Ignore, Test}
import org.polystat.py2eo.parser.Statement
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}
import scala.jdk.javaapi.CollectionConverters.asScala
import scala.language.postfixOps
import scala.sys.process.{Process, ProcessLogger}


class Tests extends Commons {
@Ignore
@Test def genUnsupportedDjango() : Unit = {
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 -b 4.0 https://github.com/django/django", root).!)
}
val test = dfsFiles(django).filter(f => f.getName.endsWith(".py"))
val futures = test.map(test =>
Future {
def db(s : Statement.T, str : String) = () // debugPrinter(test)(_, _)
val name = test.getName
println(s"parsing $name")
val eoText = try {
Transpile.transpile(db)(
chopExtension(name),
Transpile.Parameters(wrapInAFunction = false),
readFile(test)
)
} catch {
case e : Throwable =>
println(s"failed to transpile $name: ${e.toString}")
throw e
}
writeFile(test, "genUnsupportedEO", ".eo", eoText)
}
)
for (f <- futures) Await.result(f, Duration.Inf)
}

@Ignore
@Test def checkSyntaxForDjango() : Unit = {
val django = new File("/tmp/django")
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
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}").!)
// }
}
)
futures.forEach(f => Await.result(f, Duration.Inf))
}
}

0 comments on commit a1fa896

Please sign in to comment.