This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch ic in repository https://gitbox.apache.org/repos/asf/camel.git
commit 802e2d1e0ecb174e9fd5a0ed7110d5e544d5a400 Author: Claus Ibsen <[email protected]> AuthorDate: Fri Jan 30 09:45:14 2026 +0100 CAMEL-22899: camel-core - Simple language - Add custom function in init block via chains --- .../language/simple/SimpleInitBlockParser.java | 16 +++++++--- .../language/simple/SimpleInitBlockTokenizer.java | 28 +++++++++++++--- .../camel/language/simple/SimpleTokenizer.java | 6 ++++ .../language/simple/ast/InitBlockExpression.java | 4 ++- .../language/simple/types/InitOperatorType.java | 7 +++- .../language/simple/types/SimpleTokenType.java | 7 ++++ .../language/simple/SimpleInitBlockChainTest.java} | 37 ++++++++++------------ 7 files changed, 75 insertions(+), 30 deletions(-) diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleInitBlockParser.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleInitBlockParser.java index 6e34eeb0b181..ec686f0e5dd9 100644 --- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleInitBlockParser.java +++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleInitBlockParser.java @@ -92,6 +92,7 @@ class SimpleInitBlockParser extends SimpleExpressionParser { functionText(); unaryOperator(); otherOperator(); + chainOperator(); nextToken(); } @@ -107,12 +108,14 @@ class SimpleInitBlockParser extends SimpleExpressionParser { parseAndCreateAstModel(); // compact and stack blocks (eg function start/end) prepareBlocks(); - // compact and stack init blocks - prepareInitBlocks(); + // compact and stack chain expressions + prepareChainExpression(); // compact and stack unary operators prepareUnaryExpressions(); // compact and stack other expressions prepareOtherExpressions(); + // compact and stack init blocks + prepareInitBlocks(); return nodes; } @@ -121,8 +124,13 @@ class SimpleInitBlockParser extends SimpleExpressionParser { // $$name := <function> // $$name2 := <function> protected boolean initText() { + // has there been a new line since last (which reset and allow to look for new init variable) + if (!getTokenizer().hasNewLine()) { + return false; + } + // turn on init mode so the parser can find the beginning of the init variable - getTokenizer().setAcceptInitTokens(true); + getTokenizer().setAcceptInitTokens(true, index); while (!token.getType().isInitVariable() && !token.getType().isEol()) { // skip until we find init variable/function (this skips code comments) nextToken(TokenType.functionStart, TokenType.unaryOperator, TokenType.chainOperator, TokenType.otherOperator, @@ -140,7 +148,7 @@ class SimpleInitBlockParser extends SimpleExpressionParser { expectAndAcceptMore(TokenType.whiteSpace); // turn off init mode so the parser does not detect init variables inside functions or literal text // because they may also use := or $$ symbols - getTokenizer().setAcceptInitTokens(false); + getTokenizer().setAcceptInitTokens(false, index); return true; } diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleInitBlockTokenizer.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleInitBlockTokenizer.java index 65339cd2b562..285c10688924 100644 --- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleInitBlockTokenizer.java +++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleInitBlockTokenizer.java @@ -28,7 +28,7 @@ import org.apache.camel.language.simple.types.TokenType; public class SimpleInitBlockTokenizer extends SimpleTokenizer { // keep this number in sync with tokens list - private static final int NUMBER_OF_TOKENS = 2; + private static final int NUMBER_OF_TOKENS = 3; private static final SimpleTokenType[] INIT_TOKENS = new SimpleTokenType[NUMBER_OF_TOKENS]; @@ -39,11 +39,13 @@ public class SimpleInitBlockTokenizer extends SimpleTokenizer { static { // init - INIT_TOKENS[0] = new SimpleTokenType(TokenType.initOperator, ":="); - INIT_TOKENS[1] = new SimpleTokenType(TokenType.initVariable, "$"); + INIT_TOKENS[0] = new SimpleTokenType(TokenType.initVariable, "$"); + INIT_TOKENS[1] = new SimpleTokenType(TokenType.initOperator, ":="); + INIT_TOKENS[2] = new SimpleTokenType(TokenType.initOperator, "~:="); } private boolean acceptInitTokens = true; // flag to turn on|off + private boolean newLine = true; /** * Does the expression include a simple init block. @@ -58,15 +60,33 @@ public class SimpleInitBlockTokenizer extends SimpleTokenizer { return false; } - protected void setAcceptInitTokens(boolean accept) { + protected void setAcceptInitTokens(boolean accept, int index) { this.acceptInitTokens = accept; + if (!accept) { + this.newLine = false; + } + } + + protected boolean hasNewLine() { + return newLine; + } + + @Override + protected void onToken(SimpleTokenType token, int index) { + if (token.isNewLine()) { + this.newLine = true; + } } @Override protected SimpleToken customToken(String expression, int index, boolean allowEscape, TokenType... filters) { + // when discovering init tokens we must have seen a new-line prior if (!acceptInitTokens) { return null; } + if (!newLine) { + return null; + } // it could be any of the known tokens String text = expression.substring(index); diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java index 0335a87a5464..650bb72b90ec 100644 --- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java +++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleTokenizer.java @@ -188,12 +188,14 @@ public class SimpleTokenizer { SimpleTokenType token = KNOWN_TOKENS[i]; if (acceptType(token.getType(), filters) && acceptToken(token, text, expression, index)) { + onToken(token, index); return new SimpleToken(token, index); } } SimpleToken custom = customToken(expression, index, allowEscape, filters); if (custom != null) { + onToken(custom.getType(), index); return custom; } @@ -206,6 +208,10 @@ public class SimpleTokenizer { return null; } + protected void onToken(SimpleTokenType token, int index) { + // noop + } + private static int repositionIndex(String expression, int index, StringBuilder sb) { boolean digit = true; while (digit && index < expression.length()) { diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/InitBlockExpression.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/InitBlockExpression.java index 07812ccd961a..684e78f50c85 100644 --- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/InitBlockExpression.java +++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/InitBlockExpression.java @@ -86,9 +86,11 @@ public class InitBlockExpression extends BaseSimpleNode { if (operator == InitOperatorType.ASSIGNMENT) { return createAssignmentExpression(camelContext, leftExp, rightExp); + } else if (operator == InitOperatorType.CHAIN_ASSIGNMENT) { + throw new UnsupportedOperationException("TODO: Implement ~:="); } - throw new SimpleParserException("Unknown other operator " + operator, token.getIndex()); + throw new SimpleParserException("Unknown init operator " + operator, token.getIndex()); } private Expression createAssignmentExpression( diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/InitOperatorType.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/InitOperatorType.java index 1ebccdd6a799..ba0edb4d8226 100644 --- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/InitOperatorType.java +++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/InitOperatorType.java @@ -21,11 +21,14 @@ package org.apache.camel.language.simple.types; */ public enum InitOperatorType { - ASSIGNMENT; + ASSIGNMENT, + CHAIN_ASSIGNMENT; public static InitOperatorType asOperator(String text) { if (":=".equals(text)) { return ASSIGNMENT; + } else if ("~:=".equals(text)) { + return CHAIN_ASSIGNMENT; } throw new IllegalArgumentException("Operator not supported: " + text); } @@ -33,6 +36,8 @@ public enum InitOperatorType { public static String getOperatorText(InitOperatorType operator) { if (operator == ASSIGNMENT) { return ":="; + } else if (operator == CHAIN_ASSIGNMENT) { + return "~:="; } return ""; } diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/SimpleTokenType.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/SimpleTokenType.java index f4f6ff780954..9a2d1dfa4772 100644 --- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/SimpleTokenType.java +++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/SimpleTokenType.java @@ -61,6 +61,13 @@ public final class SimpleTokenType { return type == TokenType.whiteSpace; } + /** + * Whether the type is a new-line character + */ + public boolean isNewLine() { + return isWhitespace() && "\n".equals(value); + } + /** * Whether the type is eol */ diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/InitOperatorType.java b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleInitBlockChainTest.java similarity index 55% copy from core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/InitOperatorType.java copy to core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleInitBlockChainTest.java index 1ebccdd6a799..a6a1c974ec25 100644 --- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/types/InitOperatorType.java +++ b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleInitBlockChainTest.java @@ -14,32 +14,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.language.simple.types; +package org.apache.camel.language.simple; -/** - * Types of init operators supported - */ -public enum InitOperatorType { +import org.apache.camel.LanguageTestSupport; +import org.junit.jupiter.api.Test; - ASSIGNMENT; +public class SimpleInitBlockChainTest extends LanguageTestSupport { - public static InitOperatorType asOperator(String text) { - if (":=".equals(text)) { - return ASSIGNMENT; - } - throw new IllegalArgumentException("Operator not supported: " + text); - } + private static final String INIT = """ + $init{ + $clean ~:= ${trim()} ~> ${normalizeWhitespace()} ~> ${uppercase()} + }init$ + You said: $clean() + """; - public static String getOperatorText(InitOperatorType operator) { - if (operator == ASSIGNMENT) { - return ":="; - } - return ""; + @Test + public void testInitBlockChain() throws Exception { + exchange.getMessage().setBody(" Hello big World "); + + assertExpression(exchange, INIT, "You said: HELLO BIG WORLD"); } @Override - public String toString() { - return getOperatorText(this); + protected String getLanguageName() { + return "simple"; } - }
