mirror of
https://github.com/objectionary/eo.git
synced 2024-09-11 12:45:42 +03:00
feat(#3251): Added object to
This commit is contained in:
parent
091f0ed644
commit
0b0d4575c8
@ -25,4 +25,5 @@
|
||||
# package name contains capital letter and such names are conventional.
|
||||
---
|
||||
exclude_paths:
|
||||
- "eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/EOsscanf.java"
|
||||
- "eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/EOregex$EOpattern$EOmatch$EOmatched_from_index.java"
|
||||
- "eo-runtime/src/main/java/EOorg/EOeolang/EOtxt/EOregex$EOcompiled.java"
|
||||
|
@ -27,7 +27,7 @@ SOFTWARE.
|
||||
<xsl:template match="/program/errors">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="node()|@*"/>
|
||||
<xsl:for-each select="//o[count(o[@name and not(@base) and not(@atom) and count(o)=0]) > 4]">
|
||||
<xsl:for-each select="//o[count(o[@name and not(@base) and not(@atom) and count(o)=0]) > 5]">
|
||||
<xsl:element name="error">
|
||||
<xsl:attribute name="check">
|
||||
<xsl:text>too-many-attributes</xsl:text>
|
||||
@ -42,7 +42,7 @@ SOFTWARE.
|
||||
<xsl:text>"</xsl:text>
|
||||
<xsl:value-of select="@name"/>
|
||||
<xsl:text>" </xsl:text>
|
||||
<xsl:text>has more than four free attributes, it's too many</xsl:text>
|
||||
<xsl:text>has more than five free attributes, it's too many</xsl:text>
|
||||
</xsl:element>
|
||||
</xsl:for-each>
|
||||
</xsl:copy>
|
||||
|
109
eo-runtime/src/main/eo/org/eolang/txt/regex.eo
Normal file
109
eo-runtime/src/main/eo/org/eolang/txt/regex.eo
Normal file
@ -0,0 +1,109 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2016-2024 Objectionary.com
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
+architect yegor256@gmail.com
|
||||
+home https://github.com/objectionary/eo
|
||||
+package org.eolang.txt
|
||||
+rt jvm org.eolang:eo-runtime:0.0.0
|
||||
+rt node eo2js-runtime:0.0.0
|
||||
+version 0.0.0
|
||||
|
||||
# Regular expression in Perl format.
|
||||
# Here `pattern` is a string pattern.
|
||||
# It starts and ends with slash (e.g. "/(your-pattern)/"),
|
||||
# Also it can be specified by the flag option,
|
||||
# e.g.
|
||||
# ```
|
||||
# (`QQ.txt.regex "/(word)/i").compiled.matches "WORD"
|
||||
# ```
|
||||
# Supported flags:
|
||||
# /d - Enables Unix lines mode.
|
||||
# /i - Enables case-insensitive matching.
|
||||
# /x - Permits whitespace and comments in pattern.
|
||||
# /m - Enables multiline mode.
|
||||
# /s - Enables dotall mode.
|
||||
# /u - Enables Unicode-aware case folding.
|
||||
[expression] > regex
|
||||
compiled > @
|
||||
|
||||
# Compile regular expression into pattern.
|
||||
[] > compiled /pattern
|
||||
|
||||
# Regular expression compiled into pattern.
|
||||
# Here `serialized` is `bytes` which represents serialized structure in memory
|
||||
# that is built after compilation.
|
||||
[serialized] > pattern
|
||||
(^.match txt).next.exists > [txt] > matches
|
||||
|
||||
# Creates a `matcher` that will match the given input against the pattern.
|
||||
[txt] > match
|
||||
(matched-from-index 1 0).matched > next
|
||||
|
||||
# Get `number`-th block matched from `start` position.
|
||||
# If string subsequence is found - returns `matched` object,
|
||||
# returns `not-matched` otherwise.
|
||||
[number start] > matched-from-index /matched
|
||||
|
||||
# Block matched the pattern.
|
||||
# Here:
|
||||
# - `number` - sequence number of matched block,
|
||||
# - `start` - matched region start index.
|
||||
# If equals to -1 - block was not matched
|
||||
# - `from` - index where matched string sequence starts
|
||||
# - `to` - index where matched string sequence ends
|
||||
# - `groups` - tuple of identified matched groups
|
||||
#
|
||||
# The block provides the next API to work with matched string subsequence:
|
||||
# - `groups-count` - to get amount of matched groups
|
||||
# - `exists` - to check if matched block is not emtpy
|
||||
# - `next` - to get next matched block
|
||||
# - `text` - to get matched subsequence as `string`
|
||||
# - `group {index}` - to get string subsequence captured by `index`-th group.
|
||||
[number start from to groups] > matched
|
||||
$ > matched
|
||||
groups.length > groups-count
|
||||
start.gte 0 > exists
|
||||
if. > next
|
||||
exists
|
||||
matched.
|
||||
^.matched-from-index
|
||||
number.plus 1
|
||||
to
|
||||
error "Matched block does not exist, can't get next"
|
||||
if. > text
|
||||
exists
|
||||
group 0
|
||||
error "Matched block does not exist, can't get text"
|
||||
|
||||
# Returns the string subsequence captured by the group
|
||||
# by `index` during the `match` operation.
|
||||
^.groups.at index > [index] > group
|
||||
|
||||
# Block which does not match the provided pattern.
|
||||
# Decorates `matched` block with corresponding `error`s.
|
||||
[number] > not-matched
|
||||
^.matched > @
|
||||
number
|
||||
-1
|
||||
error "Matched block does not exist, can't get 'from' position"
|
||||
error "Matched block does not exist, can't get 'to' position"
|
||||
error "Matched block does not exist, can't get groups"
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016-2024 Objectionary.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @checkstyle PackageNameCheck (4 lines)
|
||||
*/
|
||||
package EOorg.EOeolang.EOtxt;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import org.eolang.Atom;
|
||||
import org.eolang.Attr;
|
||||
import org.eolang.Data;
|
||||
import org.eolang.ExFailure;
|
||||
import org.eolang.Param;
|
||||
import org.eolang.PhDefault;
|
||||
import org.eolang.Phi;
|
||||
import org.eolang.XmirObject;
|
||||
|
||||
/**
|
||||
* Regex.compiled.
|
||||
* @since 0.39.0
|
||||
* @checkstyle TypeNameCheck (5 lines)
|
||||
*/
|
||||
@XmirObject(oname = "regex.compiled")
|
||||
public final class EOregex$EOcompiled extends PhDefault implements Atom {
|
||||
@Override
|
||||
public Phi lambda() throws Exception {
|
||||
final Phi regex = this.take(Attr.RHO);
|
||||
final String expression = new Param(regex, "expression").strong(String.class);
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
if (!expression.startsWith("/")) {
|
||||
throw new ExFailure("Wrong regex syntax: \"/\" is missing");
|
||||
}
|
||||
final int last = expression.lastIndexOf("/");
|
||||
if (!expression.endsWith("/")) {
|
||||
builder.append("(?").append(expression.substring(last + 1)).append(")");
|
||||
}
|
||||
builder.append(expression, 1, last);
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
final ObjectOutputStream ous = new ObjectOutputStream(baos);
|
||||
final Phi pattern = regex.take("pattern");
|
||||
try {
|
||||
final Pattern compiled = Pattern.compile(builder.toString());
|
||||
ous.writeObject(compiled);
|
||||
pattern.put(0, new Data.ToPhi(baos.toByteArray()));
|
||||
ous.close();
|
||||
return pattern;
|
||||
} catch (final PatternSyntaxException exception) {
|
||||
throw new ExFailure(
|
||||
"Regular expression syntax is invalid",
|
||||
exception
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2016-2024 Objectionary.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @checkstyle PackageNameCheck (4 lines)
|
||||
*/
|
||||
package EOorg.EOeolang.EOtxt;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.eolang.AtVoid;
|
||||
import org.eolang.Atom;
|
||||
import org.eolang.Attr;
|
||||
import org.eolang.Data;
|
||||
import org.eolang.Dataized;
|
||||
import org.eolang.Param;
|
||||
import org.eolang.PhDefault;
|
||||
import org.eolang.Phi;
|
||||
import org.eolang.XmirObject;
|
||||
|
||||
/**
|
||||
* Regex.pattern.match.matched-from-index.
|
||||
* @since 0.39.0
|
||||
* @checkstyle TypeNameCheck (5 lines)
|
||||
*/
|
||||
@XmirObject(oname = "regex.pattern.match.matched-from-index")
|
||||
public final class EOregex$EOpattern$EOmatch$EOmatched_from_index extends PhDefault
|
||||
implements Atom {
|
||||
/**
|
||||
* Ctor.
|
||||
*/
|
||||
public EOregex$EOpattern$EOmatch$EOmatched_from_index() {
|
||||
this.add("number", new AtVoid("number"));
|
||||
this.add("start", new AtVoid("start"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Phi lambda() throws Exception {
|
||||
final Phi match = this.take(Attr.RHO);
|
||||
final InputStream bais = new ByteArrayInputStream(
|
||||
new Dataized(match.take(Attr.RHO).take("serialized")).take()
|
||||
);
|
||||
final Matcher matcher = ((Pattern) new ObjectInputStream(bais).readObject()).matcher(
|
||||
new Param(match, "txt").strong(String.class)
|
||||
);
|
||||
final Phi start = this.take("start");
|
||||
final Long from = new Dataized(this.take("start")).take(Long.class);
|
||||
final boolean found = matcher.find(Math.toIntExact(from));
|
||||
final Phi result;
|
||||
if (found) {
|
||||
result = match.take("matched");
|
||||
result.put("number", this.take("number"));
|
||||
result.put("start", start);
|
||||
result.put("from", new Data.ToPhi((long) matcher.start()));
|
||||
result.put("to", new Data.ToPhi((long) matcher.end()));
|
||||
final Phi[] groups;
|
||||
if (matcher.groupCount() > 0) {
|
||||
groups = new Phi[matcher.groupCount() + 1];
|
||||
for (int idx = 0; idx < groups.length; ++idx) {
|
||||
groups[idx] = new Data.ToPhi(matcher.group(idx));
|
||||
System.out.printf("%d: %s\n", idx, matcher.group(idx));
|
||||
}
|
||||
} else {
|
||||
groups = new Phi[] {new Data.ToPhi(matcher.group())};
|
||||
}
|
||||
result.put("groups", new Data.ToPhi(groups));
|
||||
} else {
|
||||
result = match.take("not-matched");
|
||||
result.put("number", this.take("number"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
174
eo-runtime/src/test/eo/org/eolang/txt/regex-tests.eo
Normal file
174
eo-runtime/src/test/eo/org/eolang/txt/regex-tests.eo
Normal file
@ -0,0 +1,174 @@
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2016-2024 Objectionary.com
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
+alias org.eolang.txt.regex
|
||||
+architect yegor256@gmail.com
|
||||
+home https://github.com/objectionary/eo
|
||||
+tests
|
||||
+package org.eolang.txt
|
||||
+version 0.0.0
|
||||
|
||||
# Test.
|
||||
[] > matches-regex-against-the-pattern
|
||||
(regex "/[a-z]+/").compiled.matches "hello" > @
|
||||
|
||||
# Test.
|
||||
[] > does-not-matches-regex-against-the-pattern
|
||||
((regex "/[a-z]+/").compiled.matches "123").not > @
|
||||
|
||||
# Test.
|
||||
[] > matched-sequence-has-right-border-indexes
|
||||
((regex "/[a-z]+/").match "!hello!").next > n
|
||||
and. > @
|
||||
0.eq n.start
|
||||
and.
|
||||
1.eq n.from
|
||||
6.eq n.to
|
||||
|
||||
# Test.
|
||||
[] > regex-returns-valid-matched-string-sequence
|
||||
((regex "/[a-z]+/").match "!hello!").next.text.eq "hello" > @
|
||||
|
||||
# Test.
|
||||
[] > regex-returns-valid-second-matched-block
|
||||
((regex "/[a-z]+/").match "!hello!world!").next.next > second
|
||||
and. > @
|
||||
and.
|
||||
and.
|
||||
and.
|
||||
second.text.eq "world"
|
||||
second.number.eq 2
|
||||
second.start.eq 6
|
||||
second.from.eq 7
|
||||
second.to.eq 12
|
||||
|
||||
# Test.
|
||||
[] > throws-on-getting-next-on-not-matched-block
|
||||
((regex "/[a-z]+/").match "123").next.next > @
|
||||
|
||||
# Test.
|
||||
[] > throws-on-getting-from-position-on-not-matched-block
|
||||
((regex "/[a-z]+/").match "123").next.from > @
|
||||
|
||||
# Test.
|
||||
[] > throws-on-getting-to-position-on-not-matched-block
|
||||
((regex "/[a-z]+/").match "123").next.to > @
|
||||
|
||||
# Test.
|
||||
[] > throws-on-getting-groups-count-on-not-matched-block
|
||||
((regex "/[a-z]+/").match "123").next.groups-count > @
|
||||
|
||||
# Test.
|
||||
[] > throws-on-getting-groups-on-not-matched-block
|
||||
((regex "/[a-z]+/").match "123").next.groups > @
|
||||
|
||||
# Test.
|
||||
[] > throws-on-getting-specified-group-on-not-matched-block
|
||||
((regex "/[a-z]+/").match "123").next.group 1 > @
|
||||
|
||||
# Test.
|
||||
[] > throws-on-getting-text-on-not-matched-block
|
||||
((regex "/[a-z]+/").match "123").next.text > @
|
||||
|
||||
# Test.
|
||||
[] > regex-matches-dotall-option
|
||||
regex
|
||||
"/(.*)/s"
|
||||
.compiled
|
||||
.matches > @
|
||||
"too \\n many \\n line \\n Feed\\n"
|
||||
|
||||
# Test.
|
||||
[] > regex-matches-with-case-insensitive-option
|
||||
regex
|
||||
"/(string)/i"
|
||||
.compiled
|
||||
.matches > @
|
||||
"StRiNg"
|
||||
|
||||
# Test.
|
||||
[] > regex-matches-with-multiline-option
|
||||
regex
|
||||
"/(^([0-9]+).*)/m"
|
||||
.compiled
|
||||
.matches > @
|
||||
"1 bottle of water on the wall. \\n1 bottle of water."
|
||||
|
||||
# Test.
|
||||
[] > regex-matches-entire-pattern
|
||||
regex
|
||||
"/[0-9]/\\d+/"
|
||||
.compiled
|
||||
.matches > @
|
||||
"2/75"
|
||||
|
||||
# Test.
|
||||
[] > regex-matches-with-regex-unix-lines
|
||||
regex
|
||||
"/(.+)/d"
|
||||
.compiled
|
||||
.matches > @
|
||||
"A\\r\\nB\\rC\\nD"
|
||||
|
||||
# Test.
|
||||
[] > regex-matches-with-regex-case-insensitive-and-caps
|
||||
regex
|
||||
"/(word)/i"
|
||||
.compiled
|
||||
.matches > @
|
||||
"WORD"
|
||||
|
||||
# Test.
|
||||
[] > regex-ignores-comments-in-string
|
||||
regex
|
||||
"/(\\d) #ignore this comment/x"
|
||||
.compiled
|
||||
.matches > @
|
||||
"4"
|
||||
|
||||
# Test.
|
||||
[] > regex-matches-with-unicode-case-and-insensitive
|
||||
regex
|
||||
"/(yildirim)/ui"
|
||||
.compiled
|
||||
.matches > @
|
||||
"Yıldırım"
|
||||
|
||||
# Test.
|
||||
[] > throws-on-missing-first-slash-in-regex
|
||||
(regex "(.)+").compiled > @
|
||||
|
||||
# Test.
|
||||
[] > regex-contains-valid-groups-on-each-matched-block
|
||||
((regex "/([a-z]+)([1-9]{1})/").compiled.match "!hello1!world2").next > first
|
||||
first.next > second
|
||||
and. > @
|
||||
and.
|
||||
and.
|
||||
first.groups-count.eq 3
|
||||
(first.group 1).eq "hello"
|
||||
(first.group 2).eq "1"
|
||||
and.
|
||||
and.
|
||||
second.groups-count.eq 3
|
||||
(second.group 1).eq "world"
|
||||
(second.group 2).eq "2"
|
@ -121,7 +121,7 @@ final class SnippetTestCase {
|
||||
.set("arguments", map.get("args"));
|
||||
f.exec("clean", "test");
|
||||
final String log = f.log();
|
||||
Logger.info(this, log);
|
||||
Logger.debug(this, log);
|
||||
MatcherAssert.assertThat(
|
||||
String.format("'%s' printed something wrong", yml),
|
||||
log,
|
||||
|
Loading…
Reference in New Issue
Block a user