I am parsing the results of parsing python code to get the result.
Project Structure:
PythonParseProject
build.sbt
src
main
scala
pyparse
Ast.scala
Lexical.scala
Expressions.scala
Statements.scala
Main.scala
I use the fastparse library.
build.sbt:
name := "PythonParser"
version := "0.1"
scalaVersion := "2.13.1"
libraryDependencies += "com.lihaoyi" %% "fastparse" % "2.1.3"
Main.scala:
import pyparse._
object Main extends App {
import fastparse._
var CODE =
"""
|a = 5
|b = "7"
|def my_func(a):
| r = a * 2
| return r
|if a > b:
| print(a)
|else:
| print(b)
|print(my_func(a))
|print(my_func(a), a)
|print(a)
|print("qwewqeqwe")
|print(123 + 3)
|""".stripMargin
CODE = CODE.replaceAll("\r", "")
import fastparse.NoWhitespace._
def parseIt[_: P] = Statements.file_input(P.current) ~ End
val parsed = parse(CODE, parseIt(_))
val stringResult = parsed match {
case f: Parsed.Failure => throw new Exception(f.trace().longTerminalsMsg)
case s: Parsed.Success[Seq[parsed]] => {
val result = s.value
import pyparse.Ast._
var globalVars = Map("None" -> "None", "for" -> 0)
class StringOrInt[T]
object StringOrInt {
implicit object IntWitness extends StringOrInt[Int]
implicit object StringWitness extends StringOrInt[String]
}
def BinOp(left: expr, op: operator, right: expr) = {
val l = left match {
case expr.Num(n) => n
case expr.Str(s) => s
case expr.BinOp(left, op, right) => BinOp(left, op, right)
case _ => println("BinOp. left match: что это: " + left + "?"); 0
}
val r = right match {
case expr.Num(n) => n
case expr.Str(s) => s
case expr.BinOp(left, op, right) => BinOp(left, op, right)
case _ => println("BinOp. right match: что это: " + right + "?")
}
val result = op match {
/*
Error: type mismatch;
found : Any
required: String
case operator.Add => l + r
*/
case operator.Add => l + r
case _ => println("BinOp. op match: что это: " + op + "?")
}
result
}
def Print(dest: Option[expr], values: Seq[expr], nl: bool): Unit = {
values(0) match {
// case expr.Num(n) => println(n)
// case expr.Str(s) => println(s)
// case expr.Name(id, ctx) => println(globalVars(id.name)) // а если не globalVars? Передавать сюда localVars?
// case expr.Tuple(elts, ctx) => Nil
case expr.BinOp(left, op, right) => println(BinOp(left, op, right))
case _ => println("Print. values(0): что это: " + values(0) + "?")
}
}
for (x <- result) {
var res: Any = x match {
case stmt.Print(dest, values, nl) => Print(dest, values, nl)
case _ => 0
}
}
}
}
}
I am disassembling the BinOp operation. This class sample takes 3 parameters: left, op, right.
The result of the operation can be either an integer or a string.
When describing the addition operator (and any other operator), I get an error
val result = op match {
/*
Error: type mismatch;
found : Any
required: String
case operator.Add => l + r
*/
case operator.Add => l + r
case _ => println("BinOp. op match: что это: " + op + "?")
}
How to fix it?
Declared a mixed type "StringOrInt[T]", but that didn't help.
Solution to my problem
def BinOpInt(left: Int, op: operator, right: Int): Int = {
op match {
case operator.Add => left + right
case operator.Sub => left - right
case operator.Mult => left * right
case operator.Div => left / right
case operator.Mod => left % right
case operator.Pow => math.pow(left, right).toInt
}
}
def BinOpString(left: String, op: operator, right: String): String = {
op match {
case operator.Add => left + right
}
}
def BinOpStringInt(left: String, op: operator, right: Int): String = {
op match {
case operator.Mult => left * right
}
}
def BinOp(left: expr, op: operator, right: expr): Any = {
val l = left match {
case expr.Num(n) => n.toString.toInt
case expr.Str(s) => s
case expr.BinOp(left, op, right) => BinOp(left, op, right)
}
val r = right match {
case expr.Num(n) => n.toString.toInt
case expr.Str(s) => s
case expr.BinOp(left, op, right) => BinOp(left, op, right)
}
l match {
case n_left: Int =>
r match {
case n_right: Int => BinOpInt(n_left, op, n_right)
case s_right: String => BinOpStringInt(s_right, op, n_left) // first String!
}
case s_left: String =>
r match {
case n_right: Int => BinOpStringInt(s_left, op, n_right)
case s_right: String => BinOpString(s_left, op, s_right)
}
}
}