diff --git a/.github/styles/config/vocabularies/Custom/accept.txt b/.github/styles/config/vocabularies/Custom/accept.txt index 3497dd330..4557773a0 100644 --- a/.github/styles/config/vocabularies/Custom/accept.txt +++ b/.github/styles/config/vocabularies/Custom/accept.txt @@ -21,5 +21,7 @@ inlined [Ff]orma(e)? [Tt]ranspile(d|s|r)? [Uu]noptimizable +[Dd]ataiz(e|es|ed|ation) +[Ss]yscall(s)? [Cc]yclomatic [Bb]oolean(s)? diff --git a/src/main/resources/org/eolang/lints/design/misplaced-dataization.xsl b/src/main/resources/org/eolang/lints/design/misplaced-dataization.xsl new file mode 100644 index 000000000..a4c6c6b07 --- /dev/null +++ b/src/main/resources/org/eolang/lints/design/misplaced-dataization.xsl @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + warning + true + The dataization in + + reads only objects outside of it and runs again in every copy, move it up into + + + + + + + diff --git a/src/main/resources/org/eolang/motives/design/misplaced-dataization.md b/src/main/resources/org/eolang/motives/design/misplaced-dataization.md new file mode 100644 index 000000000..1861f8e00 --- /dev/null +++ b/src/main/resources/org/eolang/motives/design/misplaced-dataization.md @@ -0,0 +1,46 @@ +# Misplaced dataization + +The cache of a `!` lives in the formation that holds it. When a nested +formation dataizes an object of the formation around it, every copy of the +nested formation starts with an empty cache and dataizes the same object +again. A recursive formation makes a new copy on every step, so the +delimiter below is dataized once per step, though it never changes: + +```eo +[^ items] > joined + [^ acc tup] >> with-delimiter + if. > @ + tup.length.eq 0 + acc + ^.with-delimiter + concat. + concat. (dataized tup.head) ^.^! + acc + tup.tail +``` + +The lint warns when two things hold. First, the target of a `!` or of a +`dataized` is a plain chain of attribute reads that goes through `^`. +Second, the formation that holds it sits inside another formation of the +same file. Move the dataization up into the enclosing formation, where it +runs once per call: + +```eo +[^ items] > joined + ^ >> delimiter! + [^ acc tup] >> with-delimiter + if. > @ + tup.length.eq 0 + acc + ^.with-delimiter + concat. + concat. (dataized tup.head) ^.delimiter + acc + tup.tail +``` + +The lint stays silent on an application, such as `^.sys.accept >>!` with +its arguments, because a syscall must run on every call, and moving it up +would run it only once. It also stays silent on a global, such as `eol!`, +on a top-level formation, whose enclosing object lives in another file, +and inside a test. diff --git a/src/test/java/matchers/GrammarMatcher.java b/src/test/java/matchers/GrammarMatcher.java index bcc5c57a6..7f810f32b 100644 --- a/src/test/java/matchers/GrammarMatcher.java +++ b/src/test/java/matchers/GrammarMatcher.java @@ -53,7 +53,8 @@ public boolean matches(final Object obj) { if (rule instanceof SpellingCheckRule) { ((SpellingCheckRule) rule).addIgnoreTokens( Arrays.asList( - "decoratee", "eolang", "spdx", "SPDX-compliant", "Unlinting", "cyclomatic" + "dataization", "decoratee", "eolang", "spdx", "SPDX-compliant", + "Unlinting", "cyclomatic" ) ); } diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-a-syscall-on-outer-objects.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-a-syscall-on-outer-objects.yaml new file mode 100644 index 000000000..612c466ef --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-a-syscall-on-outer-objects.yaml @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +defects: 0 +input: | + [] > server + [^ scope] > accept + as-number. > client + ^.sys.accept >>! + ^.sd + ^.sockaddr diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-an-application-with-literal-arguments.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-an-application-with-literal-arguments.yaml new file mode 100644 index 000000000..0a8a647cb --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-an-application-with-literal-arguments.yaml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +defects: 0 +input: | + [] > counter + [^ n] > bump + ^.n.plus 1 > next! diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-test.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-test.yaml new file mode 100644 index 000000000..c8b5e067f --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-test.yaml @@ -0,0 +1,14 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +defects: 0 +input: | + [] > foo + 42 > bar + + [] +> reads-bar-once + eq. > @ + ^.bar! + 42 diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-top-level-formation.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-top-level-formation.yaml new file mode 100644 index 000000000..06f8bf446 --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-in-a-top-level-formation.yaml @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +defects: 0 +input: | + [^ substring] > contains + ^ >> txt! + ^.as-bytes >> mine! + txt.eq substring > @ diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-moved-up-into-the-outer-formation.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-moved-up-into-the-outer-formation.yaml new file mode 100644 index 000000000..1482c88dd --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-moved-up-into-the-outer-formation.yaml @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +defects: 0 +input: | + [^ items] > joined + ^ >> delimiter! + [^ acc tup] >> with-delimiter + if. > @ + tup.length.eq 0 + acc + ^.with-delimiter + concat. + concat. (dataized tup.head) ^.delimiter + acc + tup.tail diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-a-global.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-a-global.yaml new file mode 100644 index 000000000..16e2a14ae --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-a-global.yaml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +defects: 0 +input: | + [] > reader + [^ buffer] >> rec + buffer.concat eol! > @ diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-its-own-void.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-its-own-void.yaml new file mode 100644 index 000000000..33675cc95 --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/allows-dataization-of-its-own-void.yaml @@ -0,0 +1,10 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +defects: 0 +input: | + [] > list + [^ head tail] >> walk + head.eq tail.length! > @ diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataization-in-an-anonymous-formation.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataization-in-an-anonymous-formation.yaml new file mode 100644 index 000000000..744954f7b --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataization-in-an-anonymous-formation.yaml @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +asserts: + - /defects[count(defect)=1]/defect[@line='6' and normalize-space()='The dataization in the formation at line 5 reads only objects outside of it and runs again in every copy, move it up into the formation at line 2'] +input: | + [] > outer + [^] >> + reduced > @ + items + [acc x] + acc.plus ^.weight! > @ diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataized-keyword-on-an-outer-attribute.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataized-keyword-on-an-outer-attribute.yaml new file mode 100644 index 000000000..d0c2e9677 --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-dataized-keyword-on-an-outer-attribute.yaml @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +asserts: + - /defects[count(defect)=1]/defect[@line='4' and normalize-space()='The dataization in "step" reads only objects outside of it and runs again in every copy, move it up into "box"'] +input: | + [] > box + 42 > size + [^ i] > step + i.lt (dataized ^.size) > @ diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-parent-dataized-in-a-recursive-formation.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-parent-dataized-in-a-recursive-formation.yaml new file mode 100644 index 000000000..b66be17e9 --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-parent-dataized-in-a-recursive-formation.yaml @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +asserts: + - /defects[count(defect)=1]/defect[@line='8' and @severity='warning' and normalize-space()='The dataization in "with-delimiter" reads only objects outside of it and runs again in every copy, move it up into "joined"'] +input: | + [^ items] > joined + [^ acc tup] >> with-delimiter + if. > @ + tup.length.eq 0 + acc + ^.with-delimiter + concat. + concat. (dataized tup.head) ^.^! + acc + tup.tail diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-plain-name-of-an-outer-attribute.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-plain-name-of-an-outer-attribute.yaml new file mode 100644 index 000000000..ef7a836aa --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/catches-plain-name-of-an-outer-attribute.yaml @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +asserts: + - /defects[count(defect)=1]/defect[@line='4' and normalize-space()='The dataization in "rolled" reads only objects outside of it and runs again in every copy, move it up into "digest"'] +input: | + [^] > digest + ^.as-bytes >> raw! + [^ acc index] >> rolled + index.eq raw.size! > @ diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/names-the-nearest-enclosing-formation.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/names-the-nearest-enclosing-formation.yaml new file mode 100644 index 000000000..f6feaa441 --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/names-the-nearest-enclosing-formation.yaml @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +# yamllint disable rule:line-length +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +asserts: + - /defects/defect[normalize-space()='The dataization in "climb" reads only objects outside of it and runs again in every copy, move it up into "node"'] +input: | + [] > tree + [^ left] > node + [^ depth] >> climb + depth.lt ^.^.height! > @ diff --git a/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/prints-context-when-lines-empty.yaml b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/prints-context-when-lines-empty.yaml new file mode 100644 index 000000000..12647e82d --- /dev/null +++ b/src/test/resources/org/eolang/lints/packs/single/misplaced-dataization/prints-context-when-lines-empty.yaml @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com +# SPDX-License-Identifier: MIT +--- +sheets: + - /org/eolang/lints/design/misplaced-dataization.xsl +asserts: + - /defects[count(defect[@context and @line='0'])=1] +xml-reason: "parser always emits @line; unreachable via valid parse" +document: | + + + + + + + + +