Skip to content

Commit

Permalink
feat(objectionary#226): calculate supported opcodes
Browse files Browse the repository at this point in the history
  • Loading branch information
volodya-lombrozo committed May 16, 2024
1 parent 4fed95e commit 9a98dd4
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 11 deletions.
48 changes: 47 additions & 1 deletion src/main/java/org/eolang/opeo/SelectiveDecompiler.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
package org.eolang.opeo;


import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.eolang.opeo.ast.OpcodeName;
import org.eolang.opeo.decompilation.Decompiler;
import org.eolang.opeo.decompilation.handlers.RouterHandler;
import org.eolang.opeo.jeo.JeoDecompiler;
import org.eolang.opeo.storage.Storage;
import org.eolang.opeo.storage.XmirEntry;

/**
* Selective decompiler.
Expand All @@ -14,18 +21,57 @@
*/
public final class SelectiveDecompiler implements Decompiler {


/**
* The storage where the XMIRs are stored.
*/
private final Storage storage;

/**
* Where to save the copy of each decompiled file.
*/
private final Storage copy;


private final String[] supported;

public SelectiveDecompiler(final Storage storage) {
this(storage, new RouterHandler(true).supportedOpcodes());
}

public SelectiveDecompiler(final Storage storage, String... supported) {
this(storage, storage, supported);
}

public SelectiveDecompiler(
final Storage storage, final Storage copy, final String... supported
) {
this.storage = storage;
this.copy = copy;
this.supported = supported;
}

@Override
public void decompile() {
this.storage.all().forEach(
entry -> {
final XmirEntry res;
final List<String> xpath = entry.xpath(this.xpath());
final boolean empty = xpath.isEmpty();
if (empty) {
res = entry.transform(xml -> new JeoDecompiler(xml).decompile());
} else {
res = entry;
}
this.copy.save(res);
this.storage.save(res);
}
);
}

private String xpath() {
return String.format(
"//o[@base='opcode'][not(contains(' %s ', concat(' ', @name, ' '))) ]/@name",
Arrays.stream(this.supported).collect(Collectors.joining(" "))
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.cactoos.map.MapEntry;
import org.cactoos.map.MapOf;
import org.eolang.opeo.ast.Opcode;
import org.eolang.opeo.ast.OpcodeName;
import org.eolang.opeo.decompilation.DecompilerState;
import org.eolang.opeo.decompilation.InstructionHandler;
import org.eolang.opeo.jeo.JeoLabel;
Expand Down Expand Up @@ -141,6 +142,18 @@ public void handle(final DecompilerState state) {
this.handler(state.instruction().opcode()).handle(state);
}

/**
* Get supported opcodes.
* @return Supported opcodes.
*/
public String[] supportedOpcodes() {
return this.handlers.keySet()
.stream()
.map(OpcodeName::new)
.map(OpcodeName::simplified)
.toArray(String[]::new);
}

/**
* Get instruction handler.
* @param opcode Instruction opcode.
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/org/eolang/opeo/storage/XmirEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.jcabi.xml.XMLDocument;
import java.io.FileNotFoundException;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Function;
import lombok.EqualsAndHashCode;
import lombok.ToString;
Expand Down Expand Up @@ -89,6 +90,15 @@ public XmirEntry transform(final Function<? super XML, ? extends XML> transforme
return new XmirEntry(transformer.apply(this.xml.value()), this.pckg);
}

/**
* Apply XPath query.
* @param query XPath query.
* @return List of strings returned by query.
*/
public List<String> xpath(final String query) {
return this.xml.value().xpath(query);
}

/**
* To XML.
* @return XML representation of XMIR.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@
*/
package org.eolang.opeo.decompilation;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.stream.Stream;
import org.cactoos.bytes.BytesOf;
import org.cactoos.io.ResourceOf;
import org.eolang.opeo.SelectiveDecompiler;
import org.eolang.opeo.decompilation.handlers.RouterHandler;
import org.eolang.opeo.storage.FileStorage;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
Expand All @@ -42,6 +44,12 @@
*/
final class SelectiveDecompilerTest {

private final String[] supported =
Stream.concat(
Arrays.stream(new RouterHandler(false).supportedOpcodes()),
Stream.of("IRETURN", "IFLE")
).toArray(String[]::new);

@Test
void decompiles(@TempDir final Path temp) throws Exception {
final byte[] known = new BytesOf(new ResourceOf("xmir/Bar.xmir")).asBytes();
Expand All @@ -50,16 +58,16 @@ void decompiles(@TempDir final Path temp) throws Exception {
Files.createDirectories(input);
Files.createDirectories(output);
Files.write(input.resolve("Bar.xmir"), known);
new SelectiveDecompiler(new FileStorage(input, output)).decompile();
new SelectiveDecompiler(new FileStorage(input, output), this.supported).decompile();
MatcherAssert.assertThat(
"We expect that decompiler will decompile the input file and store the result into the output folder.",
output.resolve("Bar.xmir").toFile(),
FileMatchers.anExistingFile()
);
MatcherAssert.assertThat(
"We expect that the decompiled file won't be the same as the input file. Since the decompiler should change the file.",
new BytesOf(output.resolve("Bar.xmir")),
Matchers.not(Matchers.equalTo(new BytesOf(known)))
new BytesOf(output.resolve("Bar.xmir")).asBytes(),
Matchers.not(Matchers.equalTo(known))
);
}

Expand All @@ -79,8 +87,8 @@ void decompilesNothing(@TempDir final Path temp) throws Exception {
);
MatcherAssert.assertThat(
"We expect that the decompiled file will be the same as the input file. Since the decompiler doesn't know some instructions.",
new BytesOf(output.resolve("Bar.xmir")),
Matchers.equalTo(new BytesOf(known))
new BytesOf(output.resolve("Bar.xmir")).asBytes(),
Matchers.equalTo(known)
);
}

Expand All @@ -97,13 +105,13 @@ void decompilesOnlySomeFiles(@TempDir final Path temp) throws Exception {
new SelectiveDecompiler(new FileStorage(input, output)).decompile();
MatcherAssert.assertThat(
"We expect that the decompiled file will be changed since the decompiler knows all instructions.",
new BytesOf(output.resolve("Known.xmir")),
Matchers.not(Matchers.equalTo(new BytesOf(known)))
new BytesOf(output.resolve("Known.xmir")).asBytes(),
Matchers.not(Matchers.equalTo(known))
);
MatcherAssert.assertThat(
"We expect that the decompiled file won't be changed since the decompiler doesn't know some instructions.",
new BytesOf(output.resolve("Unknown.xmir")),
Matchers.equalTo(new BytesOf(unknown))
new BytesOf(output.resolve("Unknown.xmir")).asBytes(),
Matchers.equalTo(unknown)
);
}

Expand Down

0 comments on commit 9a98dd4

Please sign in to comment.