Search code examples
scalaparsingfastparse

Return type error while parsing parsing results


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

  • 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)
          }
      }
    }