[orx-expression-evaluator-typed] Add list and lambda support
This commit is contained in:
@@ -11,9 +11,9 @@ fun <T0, R> compileFunction1(
|
|||||||
constants: (String) -> Any? = { null },
|
constants: (String) -> Any? = { null },
|
||||||
functions: TypedFunctionExtensions = TypedFunctionExtensions.EMPTY
|
functions: TypedFunctionExtensions = TypedFunctionExtensions.EMPTY
|
||||||
): ((T0) -> R) {
|
): ((T0) -> R) {
|
||||||
require(constants(parameter0) == null) {
|
// require(constants(parameter0) == null) {
|
||||||
"${parameter0} is in constants with value '${constants(parameter0)}"
|
// "${parameter0} is in constants with value '${constants(parameter0)}"
|
||||||
}
|
// }
|
||||||
val root = expressionRoot(expression)
|
val root = expressionRoot(expression)
|
||||||
|
|
||||||
var varP0: T0? = null
|
var varP0: T0? = null
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package org.openrndr.extra.expressions.typed
|
package org.openrndr.extra.expressions.typed
|
||||||
|
|
||||||
fun String.memberFunctions(n: String): ((Array<Any>) -> Any)? {
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
internal fun String.memberFunctions(n: String): ((Array<Any>) -> Any)? {
|
||||||
return when (n) {
|
return when (n) {
|
||||||
"take" -> { n -> this.take((n[0] as Number).toInt()) }
|
"take" -> { n -> this.take((n[0] as Number).toInt()) }
|
||||||
"drop" -> { n -> this.drop((n[0] as Number).toInt()) }
|
"drop" -> { n -> this.drop((n[0] as Number).toInt()) }
|
||||||
@@ -8,4 +10,16 @@ fun String.memberFunctions(n: String): ((Array<Any>) -> Any)? {
|
|||||||
"dropLast" -> { n -> this.takeLast((n[0] as Number).toInt()) }
|
"dropLast" -> { n -> this.takeLast((n[0] as Number).toInt()) }
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun List<*>.memberFunctions(n: String): ((Array<Any>) -> Any)? {
|
||||||
|
return when (n) {
|
||||||
|
"take" -> { n -> this.take((n[0] as Number).toInt()) }
|
||||||
|
"drop" -> { n -> this.drop((n[0] as Number).toInt()) }
|
||||||
|
"takeLast" -> { n -> this.takeLast((n[0] as Number).toInt()) }
|
||||||
|
"dropLast" -> { n -> this.takeLast((n[0] as Number).toInt()) }
|
||||||
|
"map" -> { n -> val lambda = (n[0] as (Any)->Any); this.map { lambda(it!!) } }
|
||||||
|
"filter" -> { n -> val lambda = (n[0] as (Any)->Any); this.filter { (lambda(it!!) as Double).roundToInt() != 0 } }
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,8 @@ enum class IDType {
|
|||||||
FUNCTION2,
|
FUNCTION2,
|
||||||
FUNCTION3,
|
FUNCTION3,
|
||||||
FUNCTION4,
|
FUNCTION4,
|
||||||
FUNCTION5
|
FUNCTION5,
|
||||||
|
FUNCTION_ARGUMENT
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class TypedExpressionListenerBase(
|
abstract class TypedExpressionListenerBase(
|
||||||
@@ -74,22 +75,71 @@ abstract class TypedExpressionListenerBase(
|
|||||||
var lastExpressionResult: Any? = null
|
var lastExpressionResult: Any? = null
|
||||||
|
|
||||||
val exceptionStack = ArrayDeque<ExpressionException>()
|
val exceptionStack = ArrayDeque<ExpressionException>()
|
||||||
|
|
||||||
|
var inFunctionLiteral = 0
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
valueStack.clear()
|
||||||
|
functionStack.clear()
|
||||||
|
propertyStack.clear()
|
||||||
|
idTypeStack.clear()
|
||||||
|
lastExpressionResult = null
|
||||||
|
exceptionStack.clear()
|
||||||
|
inFunctionLiteral = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract val state: State
|
abstract val state: State
|
||||||
|
override fun enterLine(ctx: KeyLangParser.LineContext) {
|
||||||
|
val s = state
|
||||||
|
s.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun exitListLiteral(ctx: KeyLangParser.ListLiteralContext) {
|
||||||
|
val s = state
|
||||||
|
val list = (0 until ctx.getExpression().size).map { s.valueStack.pop() }
|
||||||
|
s.valueStack.push(list.reversed())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun enterFunctionLiteral(ctx: KeyLangParser.FunctionLiteralContext) {
|
||||||
|
val s = state
|
||||||
|
s.inFunctionLiteral++
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun exitFunctionLiteral(ctx: KeyLangParser.FunctionLiteralContext) {
|
||||||
|
val s = state
|
||||||
|
s.inFunctionLiteral--
|
||||||
|
val functionExpr = ctx.getExpression().text
|
||||||
|
|
||||||
|
val ids = ctx.ID()
|
||||||
|
val f = when (ids.size) {
|
||||||
|
0 -> compileFunction1<Any, Any>(functionExpr, "it", constants, functions)
|
||||||
|
1 -> compileFunction1<Any, Any>(functionExpr, ids[0].text, constants, functions)
|
||||||
|
2 -> compileFunction2<Any, Any, Any>(functionExpr, ids[0].text, ids[1].text, constants, functions)
|
||||||
|
else -> error("functions with ${ids.size} parameters are not supported")
|
||||||
|
|
||||||
|
}
|
||||||
|
s.valueStack.push(f)
|
||||||
|
}
|
||||||
|
|
||||||
override fun exitExpressionStatement(ctx: KeyLangParser.ExpressionStatementContext) {
|
override fun exitExpressionStatement(ctx: KeyLangParser.ExpressionStatementContext) {
|
||||||
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
throw ExpressionException("error in evaluation of '${ctx.text}': ${it.message ?: ""}")
|
throw ExpressionException("error in evaluation of '${ctx.text}': ${it.message ?: ""}")
|
||||||
}
|
}
|
||||||
val result = state.valueStack.pop()
|
val result = state.valueStack.pop()
|
||||||
state.lastExpressionResult = result
|
s.lastExpressionResult = result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitMinusExpression(ctx: KeyLangParser.MinusExpressionContext) {
|
override fun exitMinusExpression(ctx: KeyLangParser.MinusExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
val op = s.valueStack.pop()
|
val op = s.valueStack.pop()
|
||||||
s.valueStack.pushChecked(
|
s.valueStack.pushChecked(
|
||||||
when (op) {
|
when (op) {
|
||||||
@@ -105,6 +155,9 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun exitBinaryOperation1(ctx: KeyLangParser.BinaryOperation1Context) {
|
override fun exitBinaryOperation1(ctx: KeyLangParser.BinaryOperation1Context) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
@@ -128,6 +181,7 @@ abstract class TypedExpressionListenerBase(
|
|||||||
left is Matrix44 && right is Double -> left * right
|
left is Matrix44 && right is Double -> left * right
|
||||||
left is ColorRGBa && right is Double -> left * right
|
left is ColorRGBa && right is Double -> left * right
|
||||||
left is String && right is Double -> left.repeat(right.roundToInt())
|
left is String && right is Double -> left.repeat(right.roundToInt())
|
||||||
|
left is List<*> && right is Double -> (0 until right.roundToInt()).flatMap { left }
|
||||||
else -> error("unsupported operands for * operator left:${left::class} right:${right::class}")
|
else -> error("unsupported operands for * operator left:${left::class} right:${right::class}")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,6 +213,11 @@ abstract class TypedExpressionListenerBase(
|
|||||||
@Suppress("IMPLICIT_CAST_TO_ANY")
|
@Suppress("IMPLICIT_CAST_TO_ANY")
|
||||||
override fun exitBinaryOperation2(ctx: KeyLangParser.BinaryOperation2Context) {
|
override fun exitBinaryOperation2(ctx: KeyLangParser.BinaryOperation2Context) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -176,6 +235,7 @@ abstract class TypedExpressionListenerBase(
|
|||||||
left is Matrix44 && right is Matrix44 -> left + right
|
left is Matrix44 && right is Matrix44 -> left + right
|
||||||
left is ColorRGBa && right is ColorRGBa -> left + right
|
left is ColorRGBa && right is ColorRGBa -> left + right
|
||||||
left is String && right is String -> left + right
|
left is String && right is String -> left + right
|
||||||
|
left is List<*> && right is List<*> -> left + right
|
||||||
else -> error("unsupported operands for + operator left:${left::class} right:${right::class}")
|
else -> error("unsupported operands for + operator left:${left::class} right:${right::class}")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,6 +256,10 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun exitJoinOperation(ctx: KeyLangParser.JoinOperationContext) {
|
override fun exitJoinOperation(ctx: KeyLangParser.JoinOperationContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val right = (s.valueStack.pop() as Double).roundToInt()
|
val right = (s.valueStack.pop() as Double).roundToInt()
|
||||||
val left = (s.valueStack.pop() as Double).roundToInt()
|
val left = (s.valueStack.pop() as Double).roundToInt()
|
||||||
|
|
||||||
@@ -209,6 +273,9 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun exitComparisonOperation(ctx: KeyLangParser.ComparisonOperationContext) {
|
override fun exitComparisonOperation(ctx: KeyLangParser.ComparisonOperationContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val right = s.valueStack.pop()
|
val right = s.valueStack.pop()
|
||||||
val left = s.valueStack.pop()
|
val left = s.valueStack.pop()
|
||||||
@@ -251,12 +318,20 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun exitNegateExpression(ctx: KeyLangParser.NegateExpressionContext) {
|
override fun exitNegateExpression(ctx: KeyLangParser.NegateExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val operand = (s.valueStack.pop() as Double).roundToInt()
|
val operand = (s.valueStack.pop() as Double).roundToInt()
|
||||||
s.valueStack.pushChecked(if (operand == 0) 1.0 else 0.0)
|
s.valueStack.pushChecked(if (operand == 0) 1.0 else 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitTernaryExpression(ctx: KeyLangParser.TernaryExpressionContext) {
|
override fun exitTernaryExpression(ctx: KeyLangParser.TernaryExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val right = s.valueStack.pop()
|
val right = s.valueStack.pop()
|
||||||
val left = s.valueStack.pop()
|
val left = s.valueStack.pop()
|
||||||
val comp = s.valueStack.pop()
|
val comp = s.valueStack.pop()
|
||||||
@@ -270,16 +345,28 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun enterValueReference(ctx: KeyLangParser.ValueReferenceContext) {
|
override fun enterValueReference(ctx: KeyLangParser.ValueReferenceContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.VARIABLE)
|
s.idTypeStack.push(IDType.VARIABLE)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun enterMemberFunctionCall0Expression(ctx: KeyLangParser.MemberFunctionCall0ExpressionContext) {
|
override fun enterMemberFunctionCall0Expression(ctx: KeyLangParser.MemberFunctionCall0ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.MEMBER_FUNCTION1)
|
s.idTypeStack.push(IDType.MEMBER_FUNCTION1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitMemberFunctionCall0Expression(ctx: KeyLangParser.MemberFunctionCall0ExpressionContext) {
|
override fun exitMemberFunctionCall0Expression(ctx: KeyLangParser.MemberFunctionCall0ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -289,11 +376,19 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun enterMemberFunctionCall1Expression(ctx: KeyLangParser.MemberFunctionCall1ExpressionContext) {
|
override fun enterMemberFunctionCall1Expression(ctx: KeyLangParser.MemberFunctionCall1ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.MEMBER_FUNCTION1)
|
s.idTypeStack.push(IDType.MEMBER_FUNCTION1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitMemberFunctionCall1Expression(ctx: KeyLangParser.MemberFunctionCall1ExpressionContext) {
|
override fun exitMemberFunctionCall1Expression(ctx: KeyLangParser.MemberFunctionCall1ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -303,11 +398,19 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun enterMemberFunctionCall2Expression(ctx: KeyLangParser.MemberFunctionCall2ExpressionContext) {
|
override fun enterMemberFunctionCall2Expression(ctx: KeyLangParser.MemberFunctionCall2ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.MEMBER_FUNCTION2)
|
s.idTypeStack.push(IDType.MEMBER_FUNCTION2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitMemberFunctionCall2Expression(ctx: KeyLangParser.MemberFunctionCall2ExpressionContext) {
|
override fun exitMemberFunctionCall2Expression(ctx: KeyLangParser.MemberFunctionCall2ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -320,11 +423,19 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun enterMemberFunctionCall3Expression(ctx: KeyLangParser.MemberFunctionCall3ExpressionContext) {
|
override fun enterMemberFunctionCall3Expression(ctx: KeyLangParser.MemberFunctionCall3ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.MEMBER_FUNCTION3)
|
s.idTypeStack.push(IDType.MEMBER_FUNCTION3)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitMemberFunctionCall3Expression(ctx: KeyLangParser.MemberFunctionCall3ExpressionContext) {
|
override fun exitMemberFunctionCall3Expression(ctx: KeyLangParser.MemberFunctionCall3ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -336,14 +447,44 @@ abstract class TypedExpressionListenerBase(
|
|||||||
s.valueStack.pushChecked(s.functionStack.pop().invoke(arrayOf(argument0, argument1, argument2)))
|
s.valueStack.pushChecked(s.functionStack.pop().invoke(arrayOf(argument0, argument1, argument2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun enterMemberFunctionCall0LambdaExpression(ctx: KeyLangParser.MemberFunctionCall0LambdaExpressionContext) {
|
||||||
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.idTypeStack.push(IDType.MEMBER_FUNCTION1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun exitMemberFunctionCall0LambdaExpression(ctx: KeyLangParser.MemberFunctionCall0LambdaExpressionContext) {
|
||||||
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ifError {
|
||||||
|
pushError(it.message ?: "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.valueStack.pushChecked(s.functionStack.pop().invoke(arrayOf(s.valueStack.pop())))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun enterFunctionCall0Expression(ctx: KeyLangParser.FunctionCall0ExpressionContext) {
|
override fun enterFunctionCall0Expression(ctx: KeyLangParser.FunctionCall0ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.FUNCTION0)
|
s.idTypeStack.push(IDType.FUNCTION0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitFunctionCall0Expression(ctx: KeyLangParser.FunctionCall0ExpressionContext) {
|
override fun exitFunctionCall0Expression(ctx: KeyLangParser.FunctionCall0ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -356,11 +497,19 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun enterFunctionCall1Expression(ctx: KeyLangParser.FunctionCall1ExpressionContext) {
|
override fun enterFunctionCall1Expression(ctx: KeyLangParser.FunctionCall1ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.FUNCTION1)
|
s.idTypeStack.push(IDType.FUNCTION1)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitFunctionCall1Expression(ctx: KeyLangParser.FunctionCall1ExpressionContext) {
|
override fun exitFunctionCall1Expression(ctx: KeyLangParser.FunctionCall1ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -375,11 +524,19 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun enterFunctionCall2Expression(ctx: KeyLangParser.FunctionCall2ExpressionContext) {
|
override fun enterFunctionCall2Expression(ctx: KeyLangParser.FunctionCall2ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.FUNCTION2)
|
s.idTypeStack.push(IDType.FUNCTION2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitFunctionCall2Expression(ctx: KeyLangParser.FunctionCall2ExpressionContext) {
|
override fun exitFunctionCall2Expression(ctx: KeyLangParser.FunctionCall2ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -395,11 +552,19 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun enterFunctionCall3Expression(ctx: KeyLangParser.FunctionCall3ExpressionContext) {
|
override fun enterFunctionCall3Expression(ctx: KeyLangParser.FunctionCall3ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.FUNCTION3)
|
s.idTypeStack.push(IDType.FUNCTION3)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitFunctionCall3Expression(ctx: KeyLangParser.FunctionCall3ExpressionContext) {
|
override fun exitFunctionCall3Expression(ctx: KeyLangParser.FunctionCall3ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -416,11 +581,19 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun enterFunctionCall4Expression(ctx: KeyLangParser.FunctionCall4ExpressionContext) {
|
override fun enterFunctionCall4Expression(ctx: KeyLangParser.FunctionCall4ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.FUNCTION4)
|
s.idTypeStack.push(IDType.FUNCTION4)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitFunctionCall4Expression(ctx: KeyLangParser.FunctionCall4ExpressionContext) {
|
override fun exitFunctionCall4Expression(ctx: KeyLangParser.FunctionCall4ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -439,11 +612,19 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun enterFunctionCall5Expression(ctx: KeyLangParser.FunctionCall5ExpressionContext) {
|
override fun enterFunctionCall5Expression(ctx: KeyLangParser.FunctionCall5ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.FUNCTION5)
|
s.idTypeStack.push(IDType.FUNCTION5)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitFunctionCall5Expression(ctx: KeyLangParser.FunctionCall5ExpressionContext) {
|
override fun exitFunctionCall5Expression(ctx: KeyLangParser.FunctionCall5ExpressionContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ifError {
|
ifError {
|
||||||
pushError(it.message ?: "")
|
pushError(it.message ?: "")
|
||||||
return
|
return
|
||||||
@@ -467,6 +648,7 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
private fun pushError(message: String) {
|
private fun pushError(message: String) {
|
||||||
val s = state
|
val s = state
|
||||||
|
|
||||||
s.exceptionStack.push(ExpressionException(message))
|
s.exceptionStack.push(ExpressionException(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,11 +662,19 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun enterPropReference(ctx: KeyLangParser.PropReferenceContext) {
|
override fun enterPropReference(ctx: KeyLangParser.PropReferenceContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
s.idTypeStack.push(IDType.PROPERTY)
|
s.idTypeStack.push(IDType.PROPERTY)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun exitPropReference(ctx: KeyLangParser.PropReferenceContext) {
|
override fun exitPropReference(ctx: KeyLangParser.PropReferenceContext) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val root = s.valueStack.pop()
|
val root = s.valueStack.pop()
|
||||||
var current = root
|
var current = root
|
||||||
val property = s.propertyStack.pop()
|
val property = s.propertyStack.pop()
|
||||||
@@ -507,6 +697,10 @@ abstract class TypedExpressionListenerBase(
|
|||||||
|
|
||||||
override fun visitTerminal(node: TerminalNode) {
|
override fun visitTerminal(node: TerminalNode) {
|
||||||
val s = state
|
val s = state
|
||||||
|
if (s.inFunctionLiteral > 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val type = node.symbol.type
|
val type = node.symbol.type
|
||||||
if (type == KeyLangParser.Tokens.INTLIT) {
|
if (type == KeyLangParser.Tokens.INTLIT) {
|
||||||
s.valueStack.pushChecked(node.text.toDouble())
|
s.valueStack.pushChecked(node.text.toDouble())
|
||||||
@@ -552,6 +746,13 @@ abstract class TypedExpressionListenerBase(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is List<*> -> {
|
||||||
|
s.functionStack.push(
|
||||||
|
receiver.memberFunctions(name)
|
||||||
|
?: error("no member function '$receiver.$name()'")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
is ColorRGBa -> {
|
is ColorRGBa -> {
|
||||||
when (idType) {
|
when (idType) {
|
||||||
IDType.MEMBER_FUNCTION1 -> {
|
IDType.MEMBER_FUNCTION1 -> {
|
||||||
@@ -598,6 +799,7 @@ abstract class TypedExpressionListenerBase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
else -> error("receiver '${receiver}' not supported")
|
else -> error("receiver '${receiver}' not supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -639,6 +841,10 @@ abstract class TypedExpressionListenerBase(
|
|||||||
s.functionStack.push(function)
|
s.functionStack.push(function)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IDType.FUNCTION_ARGUMENT -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
else -> error("unsupported id-type $idType")
|
else -> error("unsupported id-type $idType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.openrndr.extra.expressions.typed
|
||||||
|
|
||||||
|
actual class TypedExpressionListener actual constructor(
|
||||||
|
functions: TypedFunctionExtensions,
|
||||||
|
constants: (String) -> Any?
|
||||||
|
) : TypedExpressionListenerBase(functions, constants) {
|
||||||
|
actual override val state: State = State()
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.openrndr.extra.expressions.typed
|
||||||
|
|
||||||
|
import kotlin.concurrent.getOrSet
|
||||||
|
|
||||||
|
/*
|
||||||
|
Thread safe TypeExpressionListener
|
||||||
|
*/
|
||||||
|
actual class TypedExpressionListener actual constructor(
|
||||||
|
functions: TypedFunctionExtensions,
|
||||||
|
constants: (String) -> Any?
|
||||||
|
) : TypedExpressionListenerBase(functions, constants) {
|
||||||
|
private val threadLocalState = ThreadLocal<State>()
|
||||||
|
actual override val state: State
|
||||||
|
get() = threadLocalState.getOrSet { State() }
|
||||||
|
}
|
||||||
@@ -7,6 +7,53 @@ import kotlin.test.Test
|
|||||||
|
|
||||||
class TestTypedExpression {
|
class TestTypedExpression {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun funTestFunction() {
|
||||||
|
run {
|
||||||
|
val r = evaluateTypedExpression("{ x -> 2.0 + x }")
|
||||||
|
val f = r as (Double) -> Double
|
||||||
|
println(f(3.0))
|
||||||
|
}
|
||||||
|
run {
|
||||||
|
val r = evaluateTypedExpression("{ { 2.0 + it } }")
|
||||||
|
val f0 = r as (Any) -> ((Any) -> Any)
|
||||||
|
val f1 = f0(0.0)
|
||||||
|
println(f1(3.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun funTestLambdaArg() {
|
||||||
|
run {
|
||||||
|
val r = evaluateTypedExpression("[0.0, 1.0].map { x -> 2.0 + x }")
|
||||||
|
assertEquals(listOf(2.0, 3.0), r)
|
||||||
|
}
|
||||||
|
|
||||||
|
run {
|
||||||
|
val r = evaluateTypedExpression("[0.0, 1.0].map { x -> vec2(2.0 + x, 2.0 + x) }")
|
||||||
|
assertEquals(listOf(Vector2(2.0, 2.0), Vector2(3.0, 3.0)), r)
|
||||||
|
}
|
||||||
|
|
||||||
|
run {
|
||||||
|
val r = evaluateTypedExpression("[0.0, 1.0, 2.0].filter { x -> x >= 1.0 }")
|
||||||
|
assertEquals(listOf(1.0, 2.0), r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testList() {
|
||||||
|
println("result is: ${evaluateTypedExpression("[]")}")
|
||||||
|
println("result is: ${evaluateTypedExpression("[1.0, 2.0]")}")
|
||||||
|
println("result is: ${evaluateTypedExpression("[1.0, 2.0].take(1)")}")
|
||||||
|
println("result is: ${evaluateTypedExpression("[1.0 + 2.0, 2.0 * 3.0].take(1 + 1)")}")
|
||||||
|
|
||||||
|
println("result is: ${evaluateTypedExpression("[] + []")}")
|
||||||
|
println("result is: ${evaluateTypedExpression("([1] * 2 + [2] * 1)*5")}" )
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testTernary() {
|
fun testTernary() {
|
||||||
println("result is: ${evaluateTypedExpression("2.0 > 0.5 ? 1.3 : 0.7")}")
|
println("result is: ${evaluateTypedExpression("2.0 > 0.5 ? 1.3 : 0.7")}")
|
||||||
|
|||||||
@@ -25,18 +25,24 @@ DIVISION : '/' ;
|
|||||||
ASSIGN : '=' ;
|
ASSIGN : '=' ;
|
||||||
LPAREN : '(' ;
|
LPAREN : '(' ;
|
||||||
RPAREN : ')' ;
|
RPAREN : ')' ;
|
||||||
|
LBRACKET : '[' ;
|
||||||
|
RBRACKET : ']' ;
|
||||||
|
LCURLY : '{' ;
|
||||||
|
RCURLY : '}' ;
|
||||||
|
|
||||||
QUESTION_MARK : '?' ;
|
QUESTION_MARK : '?' ;
|
||||||
COLON : ':' ;
|
COLON : ':' ;
|
||||||
|
|
||||||
|
ARROW : '->' ;
|
||||||
|
|
||||||
COMMA : ',' ;
|
COMMA : ',' ;
|
||||||
DOT : '.' ;
|
DOT : '.' ;
|
||||||
|
|
||||||
EQ : '==' ;
|
EQ : '==' ;
|
||||||
LT : '<' ;
|
LT : '<' ;
|
||||||
LTEQ : '<=' ;
|
LTEQ : '<=' ;
|
||||||
GT : '>=' ;
|
GT : '>' ;
|
||||||
GTEQ : '>' ;
|
GTEQ : '>=' ;
|
||||||
|
|
||||||
AND : '&&' ;
|
AND : '&&' ;
|
||||||
OR : '||' ;
|
OR : '||' ;
|
||||||
|
|||||||
@@ -10,8 +10,13 @@ line : statement (NEWLINE | EOF) ;
|
|||||||
statement :
|
statement :
|
||||||
expression # expressionStatement ;
|
expression # expressionStatement ;
|
||||||
|
|
||||||
|
lambda: LCURLY (ID ( COMMA ID )* ARROW )? expression RCURLY # functionLiteral;
|
||||||
|
|
||||||
expression : INTLIT # intLiteral
|
expression : INTLIT # intLiteral
|
||||||
| DECLIT # decimalLiteral
|
| DECLIT # decimalLiteral
|
||||||
|
| LBRACKET (expression ( COMMA expression )*)? RBRACKET # listLiteral
|
||||||
|
| expression DOT ID lambda # memberFunctionCall0LambdaExpression
|
||||||
|
| lambda # lambdaExpression
|
||||||
| expression DOT ID LPAREN RPAREN # memberFunctionCall0Expression
|
| expression DOT ID LPAREN RPAREN # memberFunctionCall0Expression
|
||||||
| expression DOT ID LPAREN expression RPAREN # memberFunctionCall1Expression
|
| expression DOT ID LPAREN expression RPAREN # memberFunctionCall1Expression
|
||||||
| expression DOT ID LPAREN expression COMMA expression RPAREN # memberFunctionCall2Expression
|
| expression DOT ID LPAREN expression COMMA expression RPAREN # memberFunctionCall2Expression
|
||||||
|
|||||||
Reference in New Issue
Block a user