I'm trying to write a visitor function in Kotlin that adds two integers together. I've been working off of some sample code and I can't figure out what these .value or .visit functions are. It doesn't seem to be declared in the sample code, so I'm unsure how to declare it in my code. Whenever I compile the code, I get an error saying that value is an unresolved reference.
Relevant Kotlin code:
package backend
import org.antlr.v4.runtime.*
import grammar.*
abstract class Data
class IntData(val value: Int): Data() {
override fun toString(): String
= "Int($value)"
}
class Context(): HashMap<String, Data>() {
constructor(parent: Context): this() {
this.putAll(parent)
}
}
abstract class Expr {
abstract fun eval(scope: Context): Data
fun run(program: Expr) {
try {
val data = program.eval(Context())
println("=> ${data}")
} catch(e: Exception) {
println("[err] ${e}")
}
}
}
class IntLiteral(val value: Int): Expr() {
override fun eval(scope:Context): Data
= IntData(value)
}
enum class Op {
Add,
Sub,
Mul,
Div
}
class Arithmetic(
val op: Op,
val left: Expr,
val right: Expr): Expr() {
override fun eval(scope: Context): Data {
val x = (left.eval(scope) as IntData).value
val y = (right.eval(scope) as IntData).value
return IntData(
when(op) {
Op.Add -> x + y
Op.Mul -> x * y
Op.Sub -> x - y
Op.Div -> x / y
}
)
}
}
}
class Compiler: PLBaseVisitor<Expr>() {
val scope = mutableMapOf<String, Expr>()
override fun visitAddExpr(ctx: PLParser.AddExprContext): Expr {
val xValue = this.visit(ctx.x)
val yValue = this.visit(ctx.y)
val result = xValue.value + yValue.value
return IntLiteral(result)
}
}
Relevant Antlr Grammar:
expr : x=expr '+' y=expr # addExpr
| x=expr '-' y=expr # subExpr
| x=expr '*' y=expr # mulExpr
| x=expr '/' y=expr # divExpr
;
Code I'm trying to execute:
val test = """
x=1+2
print(x)
"""
fun parse(source: String): PLParser.ProgramContext {
val input = CharStreams.fromString(source)
val lexer = PLLexer(input)
val tokens = CommonTokenStream(lexer)
val parser = PLParser(tokens)
}
val testTree = parse(source1)
val testTree = parse(source1)
fun execute(program: Expr?) {
if(program == null) {
println("Program is null.")
return
}
try {
val data = program.eval(Context())
println("> ${data}")
} catch(e: Exception) {
println("[err] ${e}")
}
}
execute(testProgram)
Code from sample:
data class NodeValue(val value: Int)
val visitor = object: CalcBaseVisitor<NodeValue>() {
override fun visitAddition(ctx: CalcParser.AdditionContext): NodeValue {
val xValue = this.visit(ctx.x)
val yValue = this.visit(ctx.y)
return NodeValue(xValue.value + yValue.value)
}
override fun visitValue(ctx: CalcParser.ValueContext): NodeValue {
val lexeme = ctx.Number().getText()
return NodeValue(lexeme.toInt())
}
}
You don’t show the code for your program.eval() method.
The eval function would need to create an instance of your Visitor. (You’ve done that and called it visitor).
You also have the root expr node in you program variable.
Now you would have your visitor “visit” that node and save the return value:
val nodeVal = visitor.visit(program)
At that point nodeVal.value will have the result of visiting that expression.
note: since you’re doing the evaluation in your visitor, there’s not really any use for your Arithmetic class (unless you refactor your visitor to use it instead of just doing the math, but I don’t see much value in that as the visitor is already pretty easy to read).
Related
I've created a Kotlin equivalent of TypeReference<T> like so:
abstract class TypeReference<T> : Comparable<T> {
val type: Type get() = getGenericType()
val arguments: List<Type> get() = getTypeArguments()
final override fun compareTo(other: T): Int {
return 0
}
private fun getGenericType(): Type {
val superClass = javaClass.genericSuperclass
check(superClass !is Class<*>) {
"TypeReference constructed without actual type information."
}
return (superClass as ParameterizedType).actualTypeArguments[0]
}
private fun getTypeArguments(): List<Type> {
val type = getGenericType()
return if (type is ParameterizedType) {
type.actualTypeArguments.toList()
} else emptyList()
}
}
In order to obtain Class<*> of the generic type and its arguments, I've also created the following extension function (and this is where I believe the problem lies, since this is where the stack trace fails).
fun Type.toClass(): Class<*> = when (this) {
is ParameterizedType -> rawType.toClass()
is Class<*> -> this
else -> Class.forName(typeName)
}
I'm unit testing this like so:
#Test
fun `TypeReference should correctly identify the List of BigDecimal type`() {
// Arrange
val expected = List::class.java
val expectedParameter1 = BigDecimal::class.java
val typeReference = object : TypeReference<List<BigDecimal>>() {}
// Act
val actual = typeReference.type.toClass()
val actualParameter1 = typeReference.arguments[0].toClass()
// Assert
assertEquals(expected, actual)
assertEquals(expectedParameter1, actualParameter1)
}
The problem I think, lies in the extension function else -> Class.forName(typeName) as it throws:
java.lang.ClassNotFoundException: ? extends java.math.BigDecimal
Is there a better way to obtain the Class<*> of a Type, even when they're generic type parameters?
You need to add is WildcardType -> ... branch to your when-expression to handle types like ? extends java.math.BigDecimal (Kotlin equivalent is out java.math.BigDecimal), ?(Kotlin equivalent is *), ? super Integer(Kotlin equivalent is in java.math.Integer):
fun Type.toClass(): Class<*> = when (this) {
is ParameterizedType -> rawType.toClass()
is Class<*> -> this
is WildcardType -> upperBounds.singleOrNull()?.toClass() ?: Any::class.java
else -> Class.forName(typeName)
}
Note that in this implementation single upper bound types will be resolved as its upper bound, but all other wildcard types (including multiple upper bounds types) will be resolved as Class<Object>
https://github.com/pluses/ktypes
val typeReference = object : TypeReference<List<BigDecimal>>() {}
val superType = typeReference::class.createType().findSuperType(TypeReference::class)!!
println(superType.arguments.first())// List<java.math.BigDecimal>
println(superType.arguments.first().type?.arguments?.first())// java.math.BigDecimal
Here's a code in which I'm having hard time understanding why the first compiles and second doesn't?
class Test11<T : Number> {
lateinit var test: MutableList<out T>.() -> Unit
}
fun main() {
val test: Test11<Int> = Test11<Int>()
val test2: Test11<out Number> = test
test.test.invoke(MutableList(3) { 55 }) // First
test2.test.invoke(MutableList(3) { 55 }) // Second
}
The second says MutableList<Nothing> was expected.
So basically in first case, T => Int so out out T => out Int => out Number maybe. In second case, T => out Number so anything which is subclass of Number, then still out T => out Number right?
I'm not able to understand why doesn't it work by that logic...
The MutableList is a function parameter. You'd have the exact same issue with:
class Test11<T : Number> {
fun test(list: MutableList<out T>) {
}
}
fun main() {
val test: Test11<Number> = Test11<Number>()
val test2: Test11<out Number> = test
test.test(MutableList(3) { 55 }) // First
test2.test(MutableList(3) { 55 }) // Second
}
A covariant type by definition prevents functions where the type is a parameter from being called, but this also logically extends to nested covariance of the same type. If T is covariant (for the class), then it is not any more safe to consume an object that can produce Ts than to consume Ts directly.
Example of how this could create a failure:
class Test11<T : Number> {
var list: MutableList<out T>? = null
fun test(list: MutableList<out T>) {
this.list = list
}
}
fun main() {
val test: Test11<Long> = Test11()
val test2: Test11<out Number> = test
val doubleList: MutableList<out Number> = mutableListOf(1.0)
test2.test(doubleList) // Not allowed
// if it were allowed:
val long: Long? = test.list?.firstOrNull() // ClassCastException casting the Double to a Long
}
How a generic result or error type could be defined in Kotlin? Something like this example from TypeScript
type Errorneous<E, R> =
{ is_error: true, error: E } | { is_error: false, result: R }
function calculate(): Errorneous<String, Number> {
return { is_error: false, result: 2 }
}
The problem is that Kotlin doesn't have generic sealed classes.
It's possible to define something like
data class Errorneous<E, R>(val error: E?, val result: R?)
But it not ideal as it allows wrong usage like
Errorneous<String, Int>(null, null)
Errorneous<String, Int>("", 2)
UPDATE
Possible (not compiling) Kotlin code
sealed class Errorneous
class Success<R>(val result: R) : Errorneous()
class Fail<R>(val error: R) : Errorneous()
fun calculate(): Errorneous {
return Success(2)
}
fun main() {
val result = calculate()
if (result is Success<*>) {
val r: Int = result.result // <= Problem here, no smart cast
}
}
You have to add generic parameters to the base class as well:
sealed class Errorneous<E,R>
class Error<E,R>(val error: E): Errorneous<E,R>()
class Success<E,R>(val result: R): Errorneous<E,R>()
fun calculate(): Errorneous<String, Int> {
return Success(2)
}
fun main() {
val result = calculate()
if (result is Success<*, Int>) {
val r: Int = result.result // <= smart cast
}
}
I'd like to make a function that takes a variable number of arguments of different types, and a closure, and call the closure with the same number of arguments, each corresponding to a type in the original argument list:
fun <A, B, ...>mergeWhenValid(
arg1: Either<Problem, A>,
arg2: Either<Problem, B>,
...,
closure: (A, B, ...) -> T
): Either<Problem, T> {
// do stuff and call closure(a, b, ...)
}
How might I accomplish this?
If your mergeWhenValid just returns closure result if all eithers are right and firstProblem.left() otherwise, you should use Either.fx<Problem, T> instead of your function. Example:
Either.fx<Problem, String> { "${eitherInt.bind()} ${eitherDouble.bind()} ${eitherFloat.bind()}" }
If your logic is more complex and you need somehow handle all eithers, you can do it either by creating special merging DSL:
fun <R> mergeWhenValid(block: MergeWhenValidScope.() -> R): R = MergeWhenValidScope().block()
class EitherProblem<out T>(internal val either: Either<Problem, T>)
class MergeWhenValidScope {
private val eithers = mutableListOf<Either<Problem, *>>()
operator fun <T> Either<Problem, T>.component1(): EitherProblem<T> {
eithers += this
return EitherProblem(this)
}
private fun doStuff(): Option<Problem> {
// you can use `eithers` here and choose one of their problems or create a new one
// if you return None, it will assume that all `eithers` are right,
// otherwise, problem will be wrapped in Either and returned
return eithers.asSequence().mapNotNull { it.swap().getOrElse { null } }.firstOption()
}
fun <R> combine(block: CombinerScope.() -> R): Either<Problem, R> =
doStuff().map { it.left() }.getOrElse { CombinerScope.block().right() }
object CombinerScope {
operator fun <T> EitherProblem<T>.invoke() = either.getOrHandle {
error("Unexpected problem $it")
}
}
}
Use case:
mergeWhenValid {
val (int) = eitherInt
val (double) = eitherDouble
val (float) = eitherFloat
combine { "${int()} ${double()} ${float()}" }
}
Or by pipelining functions which add all your eithers to some object:
fun <T> mergeWhenValid() = MergeWhenValidInit<T>()
class MergeWhenValidInit<T> {
operator fun <A> invoke(either: Either<Problem, A>): MergeWhenValid<A, T, T> =
MergeWhenValid(either, listOf(either)) { it }
}
class MergeWhenValid<A, B, C>(
private val either: Either<Problem, A>,
private val eithers: List<Either<Problem, *>>,
private val previous: (B) -> C // is allowed to be called only if all `eithers` are right
) {
private fun doStuff(): Option<Problem> {
// you can use `eithers` here and choose one of their problems or create a new one
// if you return None, it will assume that all `eithers` are right,
// otherwise, problem will be wrapped in Either and returned
return eithers.asSequence().mapNotNull { it.swap().getOrElse { null } }.firstOption()
}
operator fun invoke(block: (A) -> B): Either<Problem, C> =
doStuff().map { it.left() }.getOrElse { requireC(block).right() }
operator fun <D> invoke(either: Either<Problem, D>): MergeWhenValid<D, (A) -> B, C> =
MergeWhenValid(either, eithers + either) { next -> requireC(next) }
private fun requireC(next: (A) -> B): C = previous(next(either.getOrHandle {
error("Unexpected problem $it")
}))
}
Use case:
mergeWhenValid<String>()(eitherInt)(eitherDouble)(eitherFloat)() { float ->
{ double -> { int -> "$int $double $float" } }
}
Note: the last approach reverses the order of arguments and also forces you to write { c -> { b -> { a -> ... } } } instead of { c, b, a -> ... }.
I have created a helper method buildChain which essentially creates a
chain of objects given that they implement the interface IChain<T>
and set the contracts next member
The Code
interface Chain<T> {
var next: T?
operator fun plus(next: T): T?
}
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T {
var next: T? = null
members.forEachIndexed { i, t ->
if (i == 0) {
next = first + t
} else {
next = next?.run { this + t }
}
}
return first
}
Implementation example
data class Person(val name: String) : Chain<Person> {
override var next: Person? = null
override fun plus(next: Person): Person? {
this.next = next
return next
}
}
fun createPersonChain()
= buildChain(Person("Bob"), Person("Bitzy"), Person("Blitzy"))
Implementaion output example
#JvmStatic fun main(args: Array<String>) {
var first = createPersonChain()
// first.name = "Bob"
// first.next.name = "Bitzy"
// first.next.next.name = "Blitzy"
}
Is there a functional or simpler way for acheiving the code above keeping the implementaion usage the same?
A functional idiom fold suits your needs well: it takes an initial item and then iterates over the other items, maintaining an accumulated value, which is updated on each item being processed with the function you provide.
In Kotlin, it is fold extension function for Iterable, Sequence or Array.
You can use it in the following way:
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T {
members.fold(first as T?) { acc, i -> acc?.let { it + i } }
return first
}
Here first as T? cast is needed for the accumulator type to be inferred as nullable T?, because plus in your Chain<T> returns nullable value (by the way, is it necessary?).
You can also use foldRight, which just iterates in the opposite order:
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T? =
(listOf(first) + members)
.foldRight(null as T?) { i, acc -> acc?.let { i + acc }; i }
And there are reduce and reduceRight with similar semantics but using the first and the last item respectively for the accumulator's initial value. Here's the example with reduceRight:
fun <T : Chain<T>> buildChain(first: T, vararg members: T): T? =
(listOf(first) + members).reduceRight { i, acc -> i.apply { plus(acc) } }
Try apply{}. In the {} block pass your methods separated with ';'
Object().apply{ method1(); signUp(user) }