All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mthaler.aparser.arithmetic.Parsers.kt Maven / Gradle / Ivy

There is a newer version: 0.4.0
Show newest version
package com.mthaler.aparser.arithmetic

import com.mthaler.aparser.*
import com.mthaler.aparser.tokens.*
import com.mthaler.aparser.tokens.number as tnumber
import kotlin.math.PI
import kotlin.math.E

fun ws(p: Parser): Parser = (optional(whitespaces) and p and optional(whitespaces)).map { it.middle() }

// terminals

val number: Parser = ws(tnumber).map { Expr.Number(it.toDouble()) }

val pi: Parser = (ws(stringLiteral("pi")) or ws(stringLiteral("\u03C0"))).map { Expr.Number(PI) }
val e: Parser = ws(stringLiteral("e")).map { Expr.Number(E) }

val globalVar: Parser = ws(charLiteral('[') and lettersOrDigits and charLiteral(']')).map { Expr.GlobalVar(it.middle()) }

val plus = ws(charLiteral('+'))
val minus = ws(charLiteral('-'))
val times = ws(charLiteral('*'))
val div = ws(charLiteral('/'))
val exp = ws(charLiteral('^'))

// unary -
val neg = ws(charLiteral('-'))

val lpar = ws(charLiteral('('))
val rpar = ws(charLiteral(')'))

val funcname = identifier or charLiteral('\u221A')

object Expression: RecursiveParser() {

    init {

        val func: Parser = (funcname and lpar and this and rpar).map { Expr.UnaryOp(it.first.second, it.first.first.first) }
        val group: Parser = (lpar and this and rpar).map { it.middle() }

        val factor: Parser = (neg and number).map { Expr.UnaryOp(it.second, it.first) as Expr } or number or pi or e

        val operand: Parser = func or factor or globalVar or group

        val power: Parser = (operand and zeroOrMore(exp and operand)).map { p ->
            if (p.second.isEmpty()) {
                p.first
            } else {
                val rest = p.second
                var e = p.first
                val result = arrayListOf>()
                for (item in rest) {
                    result.add(Pair(item.first, e))
                    e = item.second
                }
                result.foldRight(e) { item, expr -> Expr.BinOp(item.second, expr, item.first) }
            }
        }

        val term: Parser = (power and zeroOrMore((times or div) and power)).map { p ->
            p.second.fold(p.first) { expr, item -> Expr.BinOp(expr, item.second, item.first) }
        }

        val expr: Parser = (term and zeroOrMore((plus or minus) and term)).map { p ->
            p.second.fold(p.first) { expr, item -> Expr.BinOp(expr, item.second, item.first) }
        }

        this.parser = expr or number
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy