Skip to content

Commit

Permalink
foreach: map support
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmonkey4eva committed Jul 21, 2020
1 parent 3a9c067 commit f8b65ba
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ public ListTag(ObjectTag... objects) {
this(Arrays.asList(objects));
}

public ListTag(int capacity) {
super(capacity);
objectForms = new ArrayList<>(capacity);
}

public ListTag() {
objectForms = new ArrayList<>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,33 @@

import com.denizenscript.denizencore.exceptions.InvalidArgumentsException;
import com.denizenscript.denizencore.objects.Argument;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.objects.core.MapTag;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.scripts.ScriptEntry;
import com.denizenscript.denizencore.scripts.commands.BracedCommand;
import com.denizenscript.denizencore.utilities.text.StringHolder;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ForeachCommand extends BracedCommand {

public ForeachCommand() {
setName("foreach");
setSyntax("foreach [stop/next/<object>|...] (as:<name>) [<commands>]");
setRequiredArguments(1, 2);
setSyntax("foreach [stop/next/<object>|...] (as:<name>) (key:<name>) [<commands>]");
setRequiredArguments(1, 3);
isProcedural = true;
}

// <--[command]
// @Name Foreach
// @Syntax foreach [stop/next/<object>|...] (as:<name>) [<commands>]
// @Syntax foreach [stop/next/<object>|...] (as:<name>) (key:<name>) [<commands>]
// @Required 1
// @Maximum 2
// @Maximum 3
// @Short Loops through a ListTag, running a set of commands for each item.
// @Group queue
// @Guide https://guide.denizenscript.com/guides/basics/loops.html
Expand All @@ -32,7 +37,10 @@ public ForeachCommand() {
// Loops through a ListTag of any type. For each item in the ListTag, the specified commands will be ran for
// that list entry. To call the value of the entry while in the loop, you can use <[value]>.
//
// Optionally, specify "as:<name>" to change the definition name to something other than "value".
// Alternately, specify a map tag to loop over the set of key/value pairs in the map, where the key will be <[key]> and the value will be <[value]>.
// Optionally, specify "key:<name>" to change the key definition name to something other than "key".
//
// Optionally, specify "as:<name>" to change the value definition name to something other than "value".
//
// To end a foreach loop, do - foreach stop
//
Expand All @@ -58,6 +66,7 @@ public ForeachCommand() {
private class ForeachData {
public int index;
public ListTag list;
public List<String> keys;
}

@Override
Expand All @@ -66,7 +75,6 @@ public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException
boolean handled = false;

for (Argument arg : scriptEntry.getProcessedArgs()) {

if (!handled
&& arg.matches("stop")) {
scriptEntry.addObject("stop", new ElementTag(true));
Expand All @@ -86,8 +94,17 @@ else if (!scriptEntry.hasObject("as_name")
&& arg.matchesPrefix("as")) {
scriptEntry.addObject("as_name", arg.asElement());
}
else if (!scriptEntry.hasObject("key_as")
&& arg.matchesPrefix("key")) {
scriptEntry.addObject("key_as", arg.asElement());
}
else if (!handled) {
scriptEntry.addObject("list", arg.object instanceof ListTag ? (ListTag) arg.object : ListTag.valueOf(arg.raw_value, scriptEntry.getContext()));
if (arg.object instanceof MapTag || arg.object.toString().startsWith("map@")) {
scriptEntry.addObject("map", MapTag.getMapFor(arg.object, scriptEntry.context));
}
else {
scriptEntry.addObject("list", arg.object instanceof ListTag ? (ListTag) arg.object : ListTag.valueOf(arg.raw_value, scriptEntry.getContext()));
}
scriptEntry.addObject("braces", getBracedCommands(scriptEntry));
handled = true;
}
Expand All @@ -97,13 +114,11 @@ else if (arg.matches("{")) {
else {
arg.reportUnhandled();
}

}

if (!handled) {
throw new InvalidArgumentsException("Must specify a valid list or 'stop' or 'next'!");
}

scriptEntry.defaultObject("key_as", new ElementTag("key"));
scriptEntry.defaultObject("as_name", new ElementTag("value"));
}

Expand All @@ -115,10 +130,11 @@ public void execute(ScriptEntry scriptEntry) {
ElementTag next = scriptEntry.getElement("next");
ElementTag callback = scriptEntry.getElement("callback");
ListTag list = scriptEntry.getObjectTag("list");
MapTag map = scriptEntry.getObjectTag("map");
ElementTag as_name = scriptEntry.getElement("as_name");
ElementTag key_as = scriptEntry.getElement("key_as");

if (stop != null && stop.asBoolean()) {

if (scriptEntry.dbCallShouldDebug()) {
Debug.report(scriptEntry, getName(), stop.debug());
}
Expand Down Expand Up @@ -148,7 +164,6 @@ public void execute(ScriptEntry scriptEntry) {
return;
}
else if (next != null && next.asBoolean()) {

if (scriptEntry.dbCallShouldDebug()) {
Debug.report(scriptEntry, getName(), next.debug());
}
Expand Down Expand Up @@ -186,8 +201,11 @@ else if (callback != null && callback.asBoolean()) {
if (scriptEntry.dbCallShouldDebug()) {
Debug.echoDebug(scriptEntry, Debug.DebugElement.Header, "Foreach loop " + data.index);
}
scriptEntry.getResidingQueue().addDefinition("loop_index", String.valueOf(data.index));
scriptEntry.getResidingQueue().addDefinition(as_name.asString(), String.valueOf(data.list.get(data.index - 1)));
scriptEntry.getResidingQueue().addDefinition("loop_index", new ElementTag(data.index));
if (data.keys != null) {
scriptEntry.getResidingQueue().addDefinition(key_as.asString(), new ElementTag(data.keys.get(data.index - 1)));
}
scriptEntry.getResidingQueue().addDefinition(as_name.asString(), data.list.getObject(data.index - 1));
List<ScriptEntry> bracedCommands = BracedCommand.getBracedCommands(scriptEntry.getOwner()).get(0).value;
ScriptEntry callbackEntry = scriptEntry.clone();
callbackEntry.copyFrom(scriptEntry);
Expand Down Expand Up @@ -215,36 +233,46 @@ else if (callback != null && callback.asBoolean()) {
Debug.echoError(scriptEntry.getResidingQueue(), "Empty braces (internal)!");
return;
}

List<ScriptEntry> bracedCommandsList = bdlist.get(0).value;

if (bracedCommandsList == null || bracedCommandsList.isEmpty()) {
Debug.echoError(scriptEntry.getResidingQueue(), "Empty braces!");
return;
}

if (scriptEntry.dbCallShouldDebug()) {
Debug.report(scriptEntry, getName(), list.debug() + as_name.debug());
Debug.report(scriptEntry, getName(), (list == null ? map.debug() + key_as.debug() : list.debug()) + as_name.debug());
}

int target = list.size();
int target = list == null ? map.map.size() : list.size();
if (target <= 0) {
if (scriptEntry.dbCallShouldDebug()) {
Debug.echoDebug(scriptEntry, "Empty list, not looping...");
}
return;
}
ForeachData datum = new ForeachData();
datum.list = list;
if (list == null) {
datum.keys = new ArrayList<>(map.map.size());
datum.list = new ListTag(map.map.size());
for (Map.Entry<StringHolder, ObjectTag> entry : map.map.entrySet()) {
datum.keys.add(entry.getKey().str);
datum.list.addObject(entry.getValue());
}
}
else {
datum.keys = null;
datum.list = list;
}
datum.index = 1;
scriptEntry.setData(datum);
ScriptEntry callbackEntry = new ScriptEntry("FOREACH", new String[]{"\0CALLBACK", "as:" + as_name.asString()},
ScriptEntry callbackEntry = new ScriptEntry("FOREACH", new String[]{"\0CALLBACK", "as:" + as_name.asString(), "key:" + key_as.asString()},
(scriptEntry.getScript() != null ? scriptEntry.getScript().getContainer() : null));
callbackEntry.copyFrom(scriptEntry);
callbackEntry.setOwner(scriptEntry);
bracedCommandsList.add(callbackEntry);
scriptEntry.getResidingQueue().addDefinition(as_name.asString(), list.get(0));
scriptEntry.getResidingQueue().addDefinition("loop_index", "1");
if (datum.keys != null) {
scriptEntry.getResidingQueue().addDefinition(key_as.asString(), datum.keys.get(0));
}
scriptEntry.getResidingQueue().addDefinition(as_name.asString(), datum.list.getObject(0));
scriptEntry.getResidingQueue().addDefinition("loop_index", new ElementTag("1"));
for (int i = 0; i < bracedCommandsList.size(); i++) {
bracedCommandsList.get(i).setInstant(true);
}
Expand Down

0 comments on commit f8b65ba

Please sign in to comment.