[orx-expression-evaluator-typed] Add range operators

This commit is contained in:
Edwin Jakobs
2024-08-08 10:01:07 +02:00
parent eaa71a61bd
commit 8529825d34
5 changed files with 167 additions and 7 deletions

View File

@@ -7,6 +7,10 @@ import org.openrndr.collections.pop
import org.openrndr.collections.push
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.expressions.parser.KeyLangLexer
import org.openrndr.extra.expressions.parser.KeyLangLexer.Tokens.RANGE_DOWNTO
import org.openrndr.extra.expressions.parser.KeyLangLexer.Tokens.RANGE_EXCLUSIVE
import org.openrndr.extra.expressions.parser.KeyLangLexer.Tokens.RANGE_EXCLUSIVE_UNTIL
import org.openrndr.extra.expressions.parser.KeyLangLexer.Tokens.RANGE_INCLUSIVE
import org.openrndr.extra.expressions.parser.KeyLangParser
import org.openrndr.extra.expressions.parser.KeyLangParserBaseListener
import org.openrndr.extra.noise.uniform
@@ -94,12 +98,53 @@ abstract class TypedExpressionListenerBase(
s.reset()
}
override fun exitRangeExpression(ctx: KeyLangParser.RangeExpressionContext) {
val s = state
if (s.inFunctionLiteral > 0) {
return
}
val step: Any?
if (ctx.step != null) {
step = s.valueStack.pop()
} else {
step = null
}
val right = s.valueStack.pop()
val left = s.valueStack.pop()
val lower = (left as Double).toInt()
val upper = (right as Double).toInt()
val list = if (step == null) {
when (ctx.operator?.type) {
RANGE_INCLUSIVE -> (lower..upper).toList().map { it.toDouble() }
RANGE_EXCLUSIVE -> (lower..<upper).toList().map { it.toDouble() }
RANGE_EXCLUSIVE_UNTIL -> (lower until upper).toList().map { it.toDouble() }
RANGE_DOWNTO -> (lower downTo upper).toList().map { it.toDouble() }
else -> error("unsupported operator: '${ctx.operator?.text}'")
}
} else {
val stepSize = (step as Double).toInt()
when (ctx.operator?.type) {
RANGE_INCLUSIVE -> (lower..upper step stepSize).toList().map { it.toDouble() }
RANGE_EXCLUSIVE -> (lower..<upper step stepSize).toList().map { it.toDouble() }
RANGE_EXCLUSIVE_UNTIL -> (lower until upper step stepSize).toList().map { it.toDouble() }
RANGE_DOWNTO -> (lower downTo upper step stepSize).toList().map { it.toDouble() }
else -> error("unsupported operator: '${ctx.operator?.text}'")
}
}
s.valueStack.push(list)
}
override fun exitListLiteral(ctx: KeyLangParser.ListLiteralContext) {
val s = state
if (s.inFunctionLiteral > 0) {
return
}
val list = (0 until ctx.expression().size).map { s.valueStack.pop() }
val list = (0 until ctx.expressionRoot().size).map { s.valueStack.pop() }
s.valueStack.push(list.reversed())
}
@@ -545,10 +590,10 @@ abstract class TypedExpressionListenerBase(
if (s.inFunctionLiteral > 0) {
return
}
s.idTypeStack.push(IDType.FUNCTION2)
}
override fun exitFunctionCall2Expression(ctx: KeyLangParser.FunctionCall2ExpressionContext) {
val s = state
if (s.inFunctionLiteral > 0) {
@@ -819,7 +864,11 @@ abstract class TypedExpressionListenerBase(
}
else -> error("receiver for '$name' '${receiver.toString().take(30)}' ${receiver::class} not supported")
else -> error(
"receiver for '$name' '${
receiver.toString().take(30)
}' ${receiver::class} not supported"
)
}
}

View File

@@ -0,0 +1,25 @@
package typed
import org.junit.jupiter.api.Assertions.assertEquals
import org.openrndr.extra.expressions.typed.evaluateTypedExpression
import org.openrndr.math.Vector2
import kotlin.test.Test
import kotlin.test.assertTrue
class TestListLiteralExpression {
@Test
fun testSimpleList() {
val r = evaluateTypedExpression("[0, 1, 2]")
assertTrue(r is List<*>)
assertEquals(3, r.size )
}
@Test
fun testRangesList() {
val r = evaluateTypedExpression("[0..1, 1..2, 2..3]")
assertTrue(r is List<*>)
assertEquals(3, r.size )
}
}

View File

@@ -0,0 +1,72 @@
package typed
import org.junit.jupiter.api.Assertions.assertEquals
import org.openrndr.extra.expressions.typed.evaluateTypedExpression
import kotlin.test.Test
import kotlin.test.assertTrue
class TestRangeExpression {
@Test
fun testRangeInclusive() {
val r = evaluateTypedExpression("(0..10)")
assertTrue(r is List<*>)
assertEquals(11, r.size)
}
@Test
fun testRangeDownTo() {
val r = evaluateTypedExpression("(10 downTo 0)")
assertTrue(r is List<*>)
assertEquals(11, r.size)
assertEquals(0.0, r.last())
}
@Test
fun testRangeExclusive() {
val r = evaluateTypedExpression("(0..<10)")
assertTrue(r is List<*>)
assertEquals(10, r.size)
}
@Test
fun testRangeInclusivePrecedenceRight() {
val r = evaluateTypedExpression("(0..10+2)")
assertTrue(r is List<*>)
assertEquals(13, r.size)
}
@Test
fun testRangeInclusivePrecedenceLeft() {
val r = evaluateTypedExpression("1+2..10")
assertTrue(r is List<*>)
assertEquals(8, r.size)
}
@Test
fun testRangeInclusivePrecedenceLeftRight() {
val r = evaluateTypedExpression("1+2..10+2")
assertTrue(r is List<*>)
assertEquals(10, r.size)
}
@Test
fun testRangeUntilPrecedenceLeftRight() {
val r = evaluateTypedExpression("1+2 until 10+2")
assertTrue(r is List<*>)
assertEquals(9, r.size)
}
@Test
fun testRangeUntilPrecedenceLeftRightMap() {
val r = evaluateTypedExpression("(1+2 until 10+2).map { x -> x * 2 }")
assertTrue(r is List<*>)
assertEquals(9, r.size)
}
@Test
fun testRangeExclusiveStep() {
val r = evaluateTypedExpression("(0..10 step 2)")
assertTrue(r is List<*>)
assertEquals(6, r.size)
}
}

View File

@@ -7,6 +7,14 @@ NEWLINE : '\r\n' | '\r' | '\n' ;
WS : [\t ]+ -> channel(WHITESPACE) ;
RANGE_INCLUSIVE : '..' ;
RANGE_EXCLUSIVE_UNTIL : 'until' ;
RANGE_EXCLUSIVE : '..<' ;
RANGE_DOWNTO : 'downTo' ;
STEP : 'step' ;
// Identifiers
ID : [$_]*[a-zA-Z][A-Za-z0-9_]* | '`'[$_]*[A-Za-z0-9_-]*'`';
FUNCTION_ID : [$_]*[a-z][A-Za-z0-9_]* ;

View File

@@ -8,13 +8,19 @@ keyLangFile : lines=line+ ;
line : statement (NEWLINE | EOF) ;
statement :
expression # expressionStatement ;
expressionRoot # expressionStatement ;
rangeExpression: expression operator=(RANGE_INCLUSIVE|RANGE_EXCLUSIVE|RANGE_EXCLUSIVE_UNTIL|RANGE_DOWNTO) expression (step=STEP expression)?;
expressionRoot: rangeExpression
| expression
;
lambda: LCURLY (ID ( COMMA ID )* ARROW )? expression RCURLY # functionLiteral;
expression : INTLIT # intLiteral
| DECLIT # decimalLiteral
| LBRACKET (expression ( COMMA expression )*)? RBRACKET # listLiteral
| LBRACKET (expressionRoot ( COMMA expressionRoot )*)? RBRACKET # listLiteral
| expression DOT ID lambda # memberFunctionCall0LambdaExpression
| lambda # lambdaExpression
| expression DOT ID LPAREN RPAREN # memberFunctionCall0Expression
@@ -32,7 +38,7 @@ expression : INTLIT # int
| ID # valueReference
| STRING_OPEN (parts+=stringLiteralContent)* STRING_CLOSE # stringLiteral
| expression DOT ID # propReference
| LPAREN expression RPAREN # parenExpression
| LPAREN expressionRoot RPAREN # parenExpression
| MINUS expression # minusExpression
| NOT expression # negateExpression
| expression operator=(DIVISION|ASTERISK|PERCENTAGE) expression # binaryOperation1