diff --git a/eo-integration-tests/src/test/resources/org/eolang/snippets/auto-phi-with-application-precedence.yaml b/eo-integration-tests/src/test/resources/org/eolang/snippets/auto-phi-with-application-precedence.yaml new file mode 100644 index 00000000000..63cfb302305 --- /dev/null +++ b/eo-integration-tests/src/test/resources/org/eolang/snippets/auto-phi-with-application-precedence.yaml @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +out: [] +file: org/eolang/snippets/foo.eo +args: ["org.eolang.snippets.foo"] +eo: | + +alias org.eolang.io.stdout + +alias org.eolang.txt.text + +alias org.eolang.structs.list + +package org.eolang.snippets + + [] > foo + "abcdefghijk" > origin + origin > @ + [cont-list] > custom-map + mapped. > @ + cont-list + (text orgn).contains x >> [x] + origin > orgn! + + [] +> test-custom-map + eq. > @ + list (* true true) + foo.custom-map (list (* "abc" "ghi")) diff --git a/eo-maven-plugin/src/test/resources/org/eolang/maven/transpile-packs/transpiles-auto-phi-formation-with-application-precedence.yaml b/eo-maven-plugin/src/test/resources/org/eolang/maven/transpile-packs/transpiles-auto-phi-formation-with-application-precedence.yaml new file mode 100644 index 00000000000..81a783d1b05 --- /dev/null +++ b/eo-maven-plugin/src/test/resources/org/eolang/maven/transpile-packs/transpiles-auto-phi-formation-with-application-precedence.yaml @@ -0,0 +1,27 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: + - /org/eolang/maven/transpile/set-locators.xsl + - /org/eolang/maven/transpile/set-original-names.xsl + - /org/eolang/maven/transpile/classes.xsl + - /org/eolang/maven/transpile/tests.xsl + - /org/eolang/maven/transpile/attrs.xsl + - /org/eolang/maven/transpile/data.xsl + - /org/eolang/maven/transpile/to-java.xsl +asserts: + - /object[not(errors)] + - //java[contains(text(), 'Φ.custom-map.ap🌵46.φ')] + - //java[contains(text(), 'Φ.custom-map.ap🌵46.φ.ρ.ρ.α0')] + - //java[contains(text(), 'Phi rrbb = Phi.Φ.take("org").take("eolang").take("text");')] + - //java[contains(text(), 'rrbb1 = new PhMethod(rrbb1, "orgn");')] + - //java[contains(text(), 'Phi rrb = new PhMethod(rrbb, "what");')] + - //java[contains(text(), 'Phi rrb1 = Phi.Φ.take("org").take("eolang").take("b");')] + - //java[contains(text(), 'Phi rr = new PhMethod(rrb, "ttt");')] +input: | + [cont-list] > custom-map + mapped. > @ + cont-list + ((text orgn).what b).ttt >> [y] + origin > orgn! diff --git a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java index cffdb8963b8..7eaf5e8367e 100644 --- a/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java +++ b/eo-parser/src/main/java/org/eolang/parser/XeEoListener.java @@ -10,6 +10,8 @@ import java.util.Iterator; import java.util.List; import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.Token; @@ -35,6 +37,11 @@ "PMD.GodClass" }) final class XeEoListener implements EoListener, Iterable { + /** + * Last application. + */ + private static final Pattern LAST_APPLICATION = Pattern.compile("\\)\\.(\\p{L}[\\p{L}\\p{N}-]*)$"); + /** * Xembly directives we are building (mutable). */ @@ -158,7 +165,9 @@ public void exitObject(final EoParser.ObjectContext ctx) { @Override public void enterBound(final EoParser.BoundContext ctx) { if (ctx.just() != null && ctx.aphi() != null && ctx.just().finisher() != null) { - this.startAutoPhiFormation(ctx, ctx.just().finisher().getText()); + this.startAutoPhiFormation( + ctx, XeEoListener.eoApplicationToXmir(ctx.just().finisher().getText()) + ); } } @@ -367,7 +376,9 @@ public void exitHapplicationExtended(final EoParser.HapplicationExtendedContext @Override public void enterOnlyAphi(final EoParser.OnlyAphiContext ctx) { - this.startAutoPhiFormation(ctx, ctx.happlicationHeadExtended().getText()); + this.startAutoPhiFormation( + ctx, XeEoListener.eoApplicationToXmir(ctx.happlicationHeadExtended().getText()) + ); } @Override @@ -661,7 +672,12 @@ public void enterVapplicationArgUnbound(final EoParser.VapplicationArgUnboundCon final EoParser.VapplicationArgUnboundCurrentContext vertical = ctx.vapplicationArgUnboundCurrent(); if (vertical.just() != null || vertical.method() != null) { - this.startAutoPhiFormation(ctx, XeEoListener.verticalApplicationBase(vertical)); + this.startAutoPhiFormation( + ctx, + XeEoListener.eoApplicationToXmir( + XeEoListener.verticalApplicationBase(vertical) + ) + ); } } else { this.objects.enter(); @@ -699,7 +715,7 @@ public void enterVapplicationArgUnboundNext( ) { if (ctx.aphi() != null) { this.startAutoPhiFormation( - ctx, ctx.vapplicationHead().getText() + ctx, XeEoListener.eoApplicationToXmir(ctx.vapplicationHead().getText()) ); } } @@ -1210,13 +1226,44 @@ private String alphaAttr(final ParserRuleContext ctx, final String msg) { * @param application Application base */ private void startAutoPhiFormation(final ParserRuleContext ctx, final String application) { + final Matcher matcher = XeEoListener.LAST_APPLICATION.matcher(application); + final String abase; + if (matcher.find()) { + abase = String.format(".%s", matcher.group(1)); + } else { + abase = application; + } this.startAbstract(ctx) .enter().prop("name", new AutoName(ctx, "p").asString()) .start(ctx) - .prop("base", String.format("ξ.ρ.%s", application)) + .prop("base", abase) .prop("name", "φ"); } + /** + * EO application to XMIR base. + * @param application Application to transform + * @return Application base in XMIR format + */ + private static String eoApplicationToXmir(final String application) { + final String transformed = application.replace("^.", "ρ."); + final String base; + if (transformed.startsWith("QQ.")) { + base = transformed.replace("QQ", "Φ.org.eolang"); + } else if (transformed.startsWith("Q.")) { + base = transformed.replace("Q.", "Φ."); + } else { + base = transformed; + } + final String result; + if (base.startsWith("ρ.") || base.startsWith("Φ.")) { + result = base; + } else { + result = String.format("ξ.ρ.%s", base); + } + return result; + } + /** * Trim margin from text block. * diff --git a/eo-parser/src/main/resources/org/eolang/parser/parse/auto-phi-formation-restruct.xsl b/eo-parser/src/main/resources/org/eolang/parser/parse/auto-phi-formation-restruct.xsl index 82d13169d74..59ae84e57fb 100644 --- a/eo-parser/src/main/resources/org/eolang/parser/parse/auto-phi-formation-restruct.xsl +++ b/eo-parser/src/main/resources/org/eolang/parser/parse/auto-phi-formation-restruct.xsl @@ -63,5 +63,5 @@ - + diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-application-with-hyphens.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-application-with-hyphens.yaml new file mode 100644 index 00000000000..9732d0129ca --- /dev/null +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-application-with-hyphens.yaml @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: [] +asserts: + - /object[not(errors)] + - //o[not(@base) and @name='ap🌵34' and o[@name='φ' and @base='.as-j']/o[@base='.as-i']/o[@base='Φ.org.eolang.text']/o[@base='ξ.ρ.args']] + - //o[@base='.as-i' and not(@name)]/o[2][@base='Φ.org.eolang.as-bar.b'] +input: | + [args] > foo + bar > i + ((text args).as-i as-bar.b).as-j >> [x] diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-application-with-rho.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-application-with-rho.yaml new file mode 100644 index 00000000000..71a5542995f --- /dev/null +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-application-with-rho.yaml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: [] +asserts: + - /object[not(errors)] + - //o[not(@base) and @name='ap🌵34' and o[@name='φ' and @base='ρ.x.ρ.y.ρ.z']] +input: | + [args] > main + a > x1 + ^.x.^.y.^.z >> [y] diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-fqn-application.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-fqn-application.yaml new file mode 100644 index 00000000000..7000754b4dd --- /dev/null +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-fqn-application.yaml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: [] +asserts: + - /object[not(errors)] + - //o[not(@base) and @name='ap🌵34' and o[2][@name='x' and @base='∅' and not(@as)] and o[3][@name='φ' and @base='Φ.a.bca.eaa.boom']/o[1][@base='Φ.org.eolang.number']] +input: | + [] > foo + start > @ + Q.a.bca.eaa.boom 42 >> [x] diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-fqn-precedence-application.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-fqn-precedence-application.yaml new file mode 100644 index 00000000000..790f553c039 --- /dev/null +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-fqn-precedence-application.yaml @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: [] +asserts: + - /object[not(errors)] + - //o[not(@base) and @name='ap🌵34' and o[@name='φ' and @base='.j']/o[@base='.i']/o[@base='Φ.org.eolang.txt.text']/o[@base='ξ.ρ.args']] + - //o[@base='.i' and not(@name)]/o[2][@base='Φ.org.foo.b'] +input: | + [args] > main + foo > app + ((Q.org.eolang.txt.text args).i Q.org.foo.b).j >> [y] diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-nested-application.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-nested-application.yaml new file mode 100644 index 00000000000..1a96b5df2b2 --- /dev/null +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-nested-application.yaml @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +# @todo #4559:60min Enable the test after auto-phi formations under nested abstracts will be parsed +# correctly. For now, we just appending `ξ.ρ` to the application `@base`. We should not do this, +# instead, we keep it as `@base`, allowing XSL transformations resolve the scope correctly. This +# puzzle depends on this issue: https://github.com/objectionary/eo/issues/4557 +skip: true +sheets: [] +asserts: + - /object[not(errors)] + - //o[not(@base) and @name='ap🌵68' and o[@name='φ' and @base='ξ.ρ.ρ.ρ.ρ.x.some']] +input: | + [] > foo + 5 > x + [] > bar + [] > baz + [] > bus + start > nested + x.some >> [] diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-qq-application.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-qq-application.yaml new file mode 100644 index 00000000000..f4997fef20d --- /dev/null +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-from-qq-application.yaml @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: [] +asserts: + - /object[not(errors)] + - //o[not(@base) and @name='ap🌵34' and o[2][@name='x' and @base='∅' and not(@as)] and o[3][@name='φ' and @base='Φ.org.eolang.foo.bar']/o[1][@base='Φ.org.eolang.number']] +input: | + [] > main + start > @ + QQ.foo.bar 42 >> [x] diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-with-application-precedence.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-with-application-precedence.yaml new file mode 100644 index 00000000000..c77fbfaf78a --- /dev/null +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-with-application-precedence.yaml @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: [] +asserts: + - /object[not(errors)] + - //o[not(@base) and @name='ap🌵34' and o[@name='φ' and @base='.ttt']/o[@base='.what']/o[@base='Φ.org.eolang.text']/o[@base='ξ.ρ.orgn']] + - //o[not(@base) and @name='ap🌵54' and o[@name='φ' and @base='.g']/o[@base='.e']/o[@base='.c']] + - //o[not(@base) and @name='ap🌵86' and o[@name='φ' and @base='.contains']/o[@base='Φ.org.eolang.text']/o[@base='ξ.ρ.orgn']] + - //o[not(@base) and @name='ap🌵86' and o[@name='φ' and @base='.contains']/o[@base='ξ.x']] +input: | + [cont-list] > custom-map + foo > boom + ((text orgn).what b).ttt >> [y] + bar > dummy + (((a b).c d).e f).g >> [v] + mapped. > @ + cont-list + (text orgn).contains x >> [x] + origin > orgn! diff --git a/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-with-nested-vapplication.yaml b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-with-nested-vapplication.yaml index 0d12aeaa677..793f4ac3b23 100644 --- a/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-with-nested-vapplication.yaml +++ b/eo-parser/src/test/resources/org/eolang/parser/eo-syntax/auto-phi-formation-with-nested-vapplication.yaml @@ -5,8 +5,8 @@ sheets: [] asserts: - /object[not(errors)] - - //o[not(@base) and @name='a🌵34' and o[2][@name='i' and @base='∅'] and o[3][@name='φ']] - - //o[@base='Φ.org.eolang.foo' and o[@base='ξ.a🌵34']] + - //o[not(@base) and @name='ap🌵34' and o[2][@name='i' and @base='∅'] and o[3][@name='φ']] + - //o[@base='Φ.org.eolang.foo' and o[@base='ξ.ap🌵34']] input: | [] > main foo > @