mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-01 02:46:41 +00:00
Switch to Gradle. Use git log --follow for history.
This converts the project into a multi-module Gradle build. By default, Git does not show history past a rename, so use git log --follow to see further history.
This commit is contained in:
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public final class Constants {
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
|
||||
/**
|
||||
* List of top level NBT fields that should not be copied to a world,
|
||||
* such as UUIDLeast and UUIDMost.
|
||||
*/
|
||||
public static final List<String> NO_COPY_ENTITY_NBT_FIELDS;
|
||||
|
||||
static {
|
||||
NO_COPY_ENTITY_NBT_FIELDS = Collections.unmodifiableList(Arrays.asList(
|
||||
"UUIDLeast", "UUIDMost", // Bukkit and Vanilla
|
||||
"WorldUUIDLeast", "WorldUUIDMost", // Bukkit and Vanilla
|
||||
"PersistentIDMSB", "PersistentIDLSB" // Forge
|
||||
));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal;
|
||||
|
||||
import com.sk89q.worldedit.BlockVector2D;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.LocalWorld;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Wraps {@link World}s into {@link LocalWorld}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class LocalWorldAdapter extends LocalWorld {
|
||||
|
||||
private final World world;
|
||||
|
||||
private LocalWorldAdapter(World world) {
|
||||
checkNotNull(world);
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return world.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return world.getMaxY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidBlockType(int id) {
|
||||
return world.isValidBlockType(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesBlockData(int id) {
|
||||
return world.usesBlockData(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mask createLiquidMask() {
|
||||
return world.createLiquidMask();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getBlockType(Vector pt) {
|
||||
return world.getBlockType(pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getBlockData(Vector pt) {
|
||||
return world.getBlockData(pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBlock(Vector position, BaseBlock block, boolean notifyAndLight) throws WorldEditException {
|
||||
return world.setBlock(position, block, notifyAndLight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockLightLevel(Vector position) {
|
||||
return world.getBlockLightLevel(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clearContainerBlockContents(Vector position) {
|
||||
return world.clearContainerBlockContents(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBiome getBiome(Vector2D position) {
|
||||
return world.getBiome(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setBiome(Vector2D position, BaseBiome biome) {
|
||||
return world.setBiome(position, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropItem(Vector position, BaseItemStack item, int count) {
|
||||
world.dropItem(position, item, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropItem(Vector position, BaseItemStack item) {
|
||||
world.dropItem(position, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simulateBlockMine(Vector position) {
|
||||
world.simulateBlockMine(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(Region region, EditSession editSession) {
|
||||
return world.regenerate(region, editSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateTree(TreeType type, EditSession editSession, Vector position) throws MaxChangedBlocksException {
|
||||
return world.generateTree(type, editSession, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean generateTree(EditSession editSession, Vector position) throws MaxChangedBlocksException {
|
||||
return world.generateTree(editSession, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean generateBigTree(EditSession editSession, Vector position) throws MaxChangedBlocksException {
|
||||
return world.generateBigTree(editSession, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean generateBirchTree(EditSession editSession, Vector position) throws MaxChangedBlocksException {
|
||||
return world.generateBirchTree(editSession, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean generateRedwoodTree(EditSession editSession, Vector position) throws MaxChangedBlocksException {
|
||||
return world.generateRedwoodTree(editSession, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean generateTallRedwoodTree(EditSession editSession, Vector position) throws MaxChangedBlocksException {
|
||||
return world.generateTallRedwoodTree(editSession, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkLoadedChunk(Vector position) {
|
||||
world.checkLoadedChunk(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixAfterFastMode(Iterable<BlockVector2D> chunks) {
|
||||
world.fixAfterFastMode(chunks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fixLighting(Iterable<BlockVector2D> chunks) {
|
||||
world.fixLighting(chunks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playEffect(Vector position, int type, int data) {
|
||||
return world.playEffect(position, type, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean queueBlockBreakEffect(Platform server, Vector position, int blockId, double priority) {
|
||||
return world.queueBlockBreakEffect(server, position, blockId, priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldData getWorldData() {
|
||||
return world.getWorldData();
|
||||
}
|
||||
|
||||
@SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return world.equals(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return world.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMinimumPoint() {
|
||||
return world.getMinimumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector getMaximumPoint() {
|
||||
return world.getMaximumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities(Region region) {
|
||||
return world.getEntities(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getBlock(Vector position) {
|
||||
return world.getBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getLazyBlock(Vector position) {
|
||||
return world.getLazyBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Operation commit() {
|
||||
return world.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) {
|
||||
return world.createEntity(location, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends Entity> getEntities() {
|
||||
return world.getEntities();
|
||||
}
|
||||
|
||||
public static LocalWorldAdapter adapt(World world) {
|
||||
return new LocalWorldAdapter(world);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal;
|
||||
|
||||
import com.sk89q.worldedit.LocalConfiguration;
|
||||
import com.sk89q.worldedit.ServerInterface;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extension.platform.Preference;
|
||||
import com.sk89q.worldedit.util.command.Dispatcher;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Adapts {@link Platform}s into the legacy {@link ServerInterface}.
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
public class ServerInterfaceAdapter extends ServerInterface {
|
||||
|
||||
private final Platform platform;
|
||||
|
||||
/**
|
||||
* Create a new adapter.
|
||||
*
|
||||
* @param platform the platform
|
||||
*/
|
||||
private ServerInterfaceAdapter(Platform platform) {
|
||||
checkNotNull(platform);
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int resolveItem(String name) {
|
||||
return platform.resolveItem(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidMobType(String type) {
|
||||
return platform.isValidMobType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
platform.reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int schedule(long delay, long period, Runnable task) {
|
||||
return platform.schedule(delay, period, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends World> getWorlds() {
|
||||
return platform.getWorlds();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Player matchPlayer(Player player) {
|
||||
return platform.matchPlayer(player);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public World matchWorld(World world) {
|
||||
return platform.matchWorld(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCommands(Dispatcher dispatcher) {
|
||||
platform.registerCommands(dispatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGameHooks() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalConfiguration getConfiguration() {
|
||||
return platform.getConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return platform.getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformName() {
|
||||
return platform.getPlatformName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformVersion() {
|
||||
return platform.getPlatformVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Capability, Preference> getCapabilities() {
|
||||
return platform.getCapabilities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapt an {@link Platform} instance into a {@link ServerInterface}.
|
||||
*
|
||||
* @param platform the platform
|
||||
* @return the server interface
|
||||
*/
|
||||
public static ServerInterface adapt(Platform platform) {
|
||||
return new ServerInterfaceAdapter(platform);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package com.sk89q.worldedit.internal.annotation;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotates a {@link Vector} parameter to inject a direction.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface Direction {
|
||||
|
||||
public static final String AIM = "me";
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Marks features that should be replaced with Google Guava but cannot
|
||||
* yet because Bukkit uses such an old version of Guava.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Documented
|
||||
public @interface RequiresNewerGuava {
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates that this value should come from the current selection.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
public @interface Selection {
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.command;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandLocals;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.util.auth.Authorizer;
|
||||
|
||||
/**
|
||||
* Implementation of an authorizer that uses {@link Actor#hasPermission(String)}.
|
||||
*/
|
||||
public class ActorAuthorizer implements Authorizer {
|
||||
|
||||
@Override
|
||||
public boolean testPermission(CommandLocals locals, String permission) {
|
||||
Actor sender = locals.get(Actor.class);
|
||||
if (sender == null) {
|
||||
throw new RuntimeException("Uh oh! No 'Actor' specified so that we can check permissions");
|
||||
} else {
|
||||
return sender.hasPermission(permission);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.command;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.Logging;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.util.command.parametric.AbstractInvokeListener;
|
||||
import com.sk89q.worldedit.util.command.parametric.InvokeHandler;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterData;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterException;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Logs called commands to a logger.
|
||||
*/
|
||||
public class CommandLoggingHandler extends AbstractInvokeListener implements InvokeHandler, Closeable {
|
||||
|
||||
private final WorldEdit worldEdit;
|
||||
private final Logger logger;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param worldEdit an instance of WorldEdit
|
||||
* @param logger the logger to send messages to
|
||||
*/
|
||||
public CommandLoggingHandler(WorldEdit worldEdit, Logger logger) {
|
||||
checkNotNull(worldEdit);
|
||||
checkNotNull(logger);
|
||||
this.worldEdit = worldEdit;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preProcess(Object object, Method method, ParameterData[] parameters, CommandContext context) throws CommandException, ParameterException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preInvoke(Object object, Method method, ParameterData[] parameters, Object[] args, CommandContext context) throws CommandException {
|
||||
Logging loggingAnnotation = method.getAnnotation(Logging.class);
|
||||
Logging.LogMode logMode;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (loggingAnnotation == null) {
|
||||
logMode = null;
|
||||
} else {
|
||||
logMode = loggingAnnotation.value();
|
||||
}
|
||||
|
||||
Actor sender = context.getLocals().get(Actor.class);
|
||||
Player player;
|
||||
|
||||
if (sender == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender instanceof Player) {
|
||||
player = (Player) sender;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
builder.append("WorldEdit: ").append(sender.getName());
|
||||
if (sender.isPlayer()) {
|
||||
builder.append(" (in \"").append(player.getWorld().getName()).append("\")");
|
||||
}
|
||||
|
||||
builder.append(": ").append(context.getCommand());
|
||||
|
||||
if (context.argsLength() > 0) {
|
||||
builder.append(" ").append(context.getJoinedStrings(0));
|
||||
}
|
||||
|
||||
if (logMode != null && sender.isPlayer()) {
|
||||
Vector position = player.getPosition();
|
||||
LocalSession session = worldEdit.getSessionManager().get(player);
|
||||
|
||||
switch (logMode) {
|
||||
case PLACEMENT:
|
||||
try {
|
||||
position = session.getPlacementPosition(player);
|
||||
} catch (IncompleteRegionException e) {
|
||||
break;
|
||||
}
|
||||
/* FALL-THROUGH */
|
||||
|
||||
case POSITION:
|
||||
builder.append(" - Position: ").append(position);
|
||||
break;
|
||||
|
||||
case ALL:
|
||||
builder.append(" - Position: ").append(position);
|
||||
/* FALL-THROUGH */
|
||||
|
||||
case ORIENTATION_REGION:
|
||||
builder.append(" - Orientation: ").append(player.getCardinalDirection().name());
|
||||
/* FALL-THROUGH */
|
||||
|
||||
case REGION:
|
||||
try {
|
||||
builder.append(" - Region: ")
|
||||
.append(session.getSelection(player.getWorld()));
|
||||
} catch (IncompleteRegionException e) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(builder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInvoke(Object object, Method method, ParameterData[] parameters, Object[] args, CommandContext context) throws CommandException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvokeHandler createInvokeHandler() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for (Handler h : logger.getHandlers()) {
|
||||
h.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.command;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.minecraft.util.commands.CommandLocals;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
import com.sk89q.worldedit.extension.platform.MultiUserPlatform;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extension.platform.PlatformManager;
|
||||
import com.sk89q.worldedit.util.command.CommandCompleter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Provides the names of connected users as suggestions.
|
||||
*/
|
||||
public class UserCommandCompleter implements CommandCompleter {
|
||||
|
||||
private final PlatformManager platformManager;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param platformManager the platform manager
|
||||
*/
|
||||
public UserCommandCompleter(PlatformManager platformManager) {
|
||||
checkNotNull(platformManager);
|
||||
this.platformManager = platformManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(String arguments, CommandLocals locals) throws CommandException {
|
||||
Platform platform = platformManager.queryCapability(Capability.USER_COMMANDS);
|
||||
if (platform instanceof MultiUserPlatform) {
|
||||
List<String> suggestions = new ArrayList<String>();
|
||||
Collection<Actor> users = ((MultiUserPlatform) platform).getConnectedUsers();
|
||||
for (Actor user : users) {
|
||||
if (user.getName().toLowerCase().startsWith(arguments.toLowerCase().trim())) {
|
||||
suggestions.add(user.getName());
|
||||
}
|
||||
}
|
||||
return suggestions;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,336 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.command;
|
||||
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.UnknownDirectionException;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.input.NoMatchException;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.internal.annotation.Direction;
|
||||
import com.sk89q.worldedit.internal.annotation.Selection;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.TreeGenerator;
|
||||
import com.sk89q.worldedit.util.TreeGenerator.TreeType;
|
||||
import com.sk89q.worldedit.util.command.parametric.ArgumentStack;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingBehavior;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingHelper;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingMatch;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterException;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Binds standard WorldEdit classes such as {@link Player} and {@link LocalSession}.
|
||||
*/
|
||||
public class WorldEditBinding extends BindingHelper {
|
||||
|
||||
private final WorldEdit worldEdit;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param worldEdit the WorldEdit instance to bind to
|
||||
*/
|
||||
public WorldEditBinding(WorldEdit worldEdit) {
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a selection from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @param selection the annotation
|
||||
* @return a selection
|
||||
* @throws IncompleteRegionException if no selection is available
|
||||
* @throws ParameterException on other error
|
||||
*/
|
||||
@BindingMatch(classifier = Selection.class,
|
||||
type = Region.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public Object getSelection(ArgumentStack context, Selection selection) throws IncompleteRegionException, ParameterException {
|
||||
Player sender = getPlayer(context);
|
||||
LocalSession session = worldEdit.getSessionManager().get(sender);
|
||||
return session.getSelection(sender.getWorld());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link EditSession} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return an edit session
|
||||
* @throws ParameterException on other error
|
||||
*/
|
||||
@BindingMatch(type = EditSession.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public EditSession getEditSession(ArgumentStack context) throws ParameterException {
|
||||
Player sender = getPlayer(context);
|
||||
LocalSession session = worldEdit.getSessionManager().get(sender);
|
||||
EditSession editSession = session.createEditSession(sender);
|
||||
editSession.enableQueue();
|
||||
context.getContext().getLocals().put(EditSession.class, editSession);
|
||||
session.tellVersion(sender);
|
||||
return editSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link LocalSession} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a local session
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = LocalSession.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public LocalSession getLocalSession(ArgumentStack context) throws ParameterException {
|
||||
Player sender = getPlayer(context);
|
||||
return worldEdit.getSessionManager().get(sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link Actor} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a local player
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = Actor.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public Actor getActor(ArgumentStack context) throws ParameterException {
|
||||
Actor sender = context.getContext().getLocals().get(Actor.class);
|
||||
if (sender == null) {
|
||||
throw new ParameterException("Missing 'Actor'");
|
||||
} else {
|
||||
return sender;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link Player} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a local player
|
||||
* @throws ParameterException on error
|
||||
*/
|
||||
@BindingMatch(type = Player.class,
|
||||
behavior = BindingBehavior.PROVIDES)
|
||||
public Player getPlayer(ArgumentStack context) throws ParameterException {
|
||||
Actor sender = context.getContext().getLocals().get(Actor.class);
|
||||
if (sender == null) {
|
||||
throw new ParameterException("No player to get a session for");
|
||||
} else if (sender instanceof Player) {
|
||||
return (Player) sender;
|
||||
} else {
|
||||
throw new ParameterException("Caller is not a player");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link BaseBlock} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a pattern
|
||||
* @throws ParameterException on error
|
||||
* @throws WorldEditException on error
|
||||
*/
|
||||
@BindingMatch(type = BaseBlock.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1)
|
||||
public BaseBlock getBaseBlock(ArgumentStack context) throws ParameterException, WorldEditException {
|
||||
Actor actor = context.getContext().getLocals().get(Actor.class);
|
||||
ParserContext parserContext = new ParserContext();
|
||||
parserContext.setActor(context.getContext().getLocals().get(Actor.class));
|
||||
if (actor instanceof Entity) {
|
||||
Extent extent = ((Entity) actor).getExtent();
|
||||
if (extent instanceof World) {
|
||||
parserContext.setWorld((World) extent);
|
||||
}
|
||||
}
|
||||
parserContext.setSession(worldEdit.getSessionManager().get(actor));
|
||||
try {
|
||||
return worldEdit.getBlockFactory().parseFromInput(context.next(), parserContext);
|
||||
} catch (NoMatchException e) {
|
||||
throw new ParameterException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link Pattern} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a pattern
|
||||
* @throws ParameterException on error
|
||||
* @throws WorldEditException on error
|
||||
*/
|
||||
@BindingMatch(type = Pattern.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1)
|
||||
public Pattern getPattern(ArgumentStack context) throws ParameterException, WorldEditException {
|
||||
Actor actor = context.getContext().getLocals().get(Actor.class);
|
||||
ParserContext parserContext = new ParserContext();
|
||||
parserContext.setActor(context.getContext().getLocals().get(Actor.class));
|
||||
if (actor instanceof Entity) {
|
||||
Extent extent = ((Entity) actor).getExtent();
|
||||
if (extent instanceof World) {
|
||||
parserContext.setWorld((World) extent);
|
||||
}
|
||||
}
|
||||
parserContext.setSession(worldEdit.getSessionManager().get(actor));
|
||||
try {
|
||||
return worldEdit.getPatternFactory().parseFromInput(context.next(), parserContext);
|
||||
} catch (NoMatchException e) {
|
||||
throw new ParameterException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link Mask} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a pattern
|
||||
* @throws ParameterException on error
|
||||
* @throws WorldEditException on error
|
||||
*/
|
||||
@BindingMatch(type = Mask.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1)
|
||||
public Mask getMask(ArgumentStack context) throws ParameterException, WorldEditException {
|
||||
Actor actor = context.getContext().getLocals().get(Actor.class);
|
||||
ParserContext parserContext = new ParserContext();
|
||||
parserContext.setActor(context.getContext().getLocals().get(Actor.class));
|
||||
if (actor instanceof Entity) {
|
||||
Extent extent = ((Entity) actor).getExtent();
|
||||
if (extent instanceof World) {
|
||||
parserContext.setWorld((World) extent);
|
||||
}
|
||||
}
|
||||
parserContext.setSession(worldEdit.getSessionManager().get(actor));
|
||||
try {
|
||||
return worldEdit.getMaskFactory().parseFromInput(context.next(), parserContext);
|
||||
} catch (NoMatchException e) {
|
||||
throw new ParameterException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a direction from the player.
|
||||
*
|
||||
* @param context the context
|
||||
* @param direction the direction annotation
|
||||
* @return a pattern
|
||||
* @throws ParameterException on error
|
||||
* @throws UnknownDirectionException on an unknown direction
|
||||
*/
|
||||
@BindingMatch(classifier = Direction.class,
|
||||
type = Vector.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1)
|
||||
public Vector getDirection(ArgumentStack context, Direction direction)
|
||||
throws ParameterException, UnknownDirectionException {
|
||||
Player sender = getPlayer(context);
|
||||
return worldEdit.getDirection(sender, context.next());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link TreeType} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a pattern
|
||||
* @throws ParameterException on error
|
||||
* @throws WorldEditException on error
|
||||
*/
|
||||
@BindingMatch(type = TreeType.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1)
|
||||
public TreeType getTreeType(ArgumentStack context) throws ParameterException, WorldEditException {
|
||||
String input = context.next();
|
||||
if (input != null) {
|
||||
TreeType type = TreeGenerator.lookup(input);
|
||||
if (type != null) {
|
||||
return type;
|
||||
} else {
|
||||
throw new ParameterException(
|
||||
String.format("Can't recognize tree type '%s' -- choose from: %s", input, Arrays.toString(TreeType.values())));
|
||||
}
|
||||
} else {
|
||||
return TreeType.TREE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an {@link BaseBiome} from a {@link ArgumentStack}.
|
||||
*
|
||||
* @param context the context
|
||||
* @return a pattern
|
||||
* @throws ParameterException on error
|
||||
* @throws WorldEditException on error
|
||||
*/
|
||||
@BindingMatch(type = BaseBiome.class,
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1)
|
||||
public BaseBiome getBiomeType(ArgumentStack context) throws ParameterException, WorldEditException {
|
||||
String input = context.next();
|
||||
if (input != null) {
|
||||
Actor actor = context.getContext().getLocals().get(Actor.class);
|
||||
World world;
|
||||
if (actor instanceof Entity) {
|
||||
Extent extent = ((Entity) actor).getExtent();
|
||||
if (extent instanceof World) {
|
||||
world = (World) extent;
|
||||
} else {
|
||||
throw new ParameterException("A world is required.");
|
||||
}
|
||||
} else {
|
||||
throw new ParameterException("An entity is required.");
|
||||
}
|
||||
|
||||
BiomeRegistry biomeRegistry = world.getWorldData().getBiomeRegistry();
|
||||
List<BaseBiome> knownBiomes = biomeRegistry.getBiomes();
|
||||
BaseBiome biome = Biomes.findBiomeByName(knownBiomes, input, biomeRegistry);
|
||||
if (biome != null) {
|
||||
return biome;
|
||||
} else {
|
||||
throw new ParameterException(
|
||||
String.format("Can't recognize biome type '%s' -- use /biomelist to list available types", input));
|
||||
}
|
||||
} else {
|
||||
throw new ParameterException(
|
||||
"This command takes a 'default' biome if one is not set, except there is no particular " +
|
||||
"biome that should be 'default', so the command should not be taking a default biome");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.command;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.CommandException;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.blocks.ItemType;
|
||||
import com.sk89q.worldedit.command.InsufficientArgumentsException;
|
||||
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
import com.sk89q.worldedit.regions.RegionOperationException;
|
||||
import com.sk89q.worldedit.util.command.parametric.ExceptionConverterHelper;
|
||||
import com.sk89q.worldedit.util.command.parametric.ExceptionMatch;
|
||||
import com.sk89q.worldedit.util.io.file.FileSelectionAbortedException;
|
||||
import com.sk89q.worldedit.util.io.file.FilenameResolutionException;
|
||||
import com.sk89q.worldedit.util.io.file.InvalidFilenameException;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* converts WorldEdit exceptions and converts them into {@link CommandException}s.
|
||||
*/
|
||||
public class WorldEditExceptionConverter extends ExceptionConverterHelper {
|
||||
|
||||
private static final Pattern numberFormat = Pattern.compile("^For input string: \"(.*)\"$");
|
||||
private final WorldEdit worldEdit;
|
||||
|
||||
public WorldEditExceptionConverter(WorldEdit worldEdit) {
|
||||
checkNotNull(worldEdit);
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(NumberFormatException e) throws CommandException {
|
||||
final Matcher matcher = numberFormat.matcher(e.getMessage());
|
||||
|
||||
if (matcher.matches()) {
|
||||
throw new CommandException("Number expected; string \"" + matcher.group(1)
|
||||
+ "\" given.");
|
||||
} else {
|
||||
throw new CommandException("Number expected; string given.");
|
||||
}
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(IncompleteRegionException e) throws CommandException {
|
||||
throw new CommandException("Make a region selection first.");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(UnknownItemException e) throws CommandException {
|
||||
throw new CommandException("Block name '" + e.getID() + "' was not recognized.");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(InvalidItemException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(DisallowedItemException e) throws CommandException {
|
||||
throw new CommandException("Block '" + e.getID()
|
||||
+ "' not allowed (see WorldEdit configuration).");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(MaxChangedBlocksException e) throws CommandException {
|
||||
throw new CommandException("Max blocks changed in an operation reached ("
|
||||
+ e.getBlockLimit() + ").");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(MaxBrushRadiusException e) throws CommandException {
|
||||
throw new CommandException("Maximum brush radius (in configuration): " + worldEdit.getConfiguration().maxBrushRadius);
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(MaxRadiusException e) throws CommandException {
|
||||
throw new CommandException("Maximum radius (in configuration): " + worldEdit.getConfiguration().maxRadius);
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(UnknownDirectionException e) throws CommandException {
|
||||
throw new CommandException("Unknown direction: " + e.getDirection());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(InsufficientArgumentsException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(RegionOperationException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(ExpressionException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(EmptyClipboardException e) throws CommandException {
|
||||
throw new CommandException("Your clipboard is empty. Use //copy first.");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(InvalidFilenameException e) throws CommandException {
|
||||
throw new CommandException("Filename '" + e.getFilename() + "' invalid: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(FilenameResolutionException e) throws CommandException {
|
||||
throw new CommandException(
|
||||
"File '" + e.getFilename() + "' resolution error: " + e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(InvalidToolBindException e) throws CommandException {
|
||||
throw new CommandException("Can't bind tool to "
|
||||
+ ItemType.toHeldName(e.getItemId()) + ": " + e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(FileSelectionAbortedException e) throws CommandException {
|
||||
throw new CommandException("File selection aborted.");
|
||||
}
|
||||
|
||||
@ExceptionMatch
|
||||
public void convert(WorldEditException e) throws CommandException {
|
||||
throw new CommandException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.cui;
|
||||
|
||||
public interface CUIEvent {
|
||||
|
||||
public String getTypeId();
|
||||
|
||||
public String[] getParameters();
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.cui;
|
||||
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
|
||||
public interface CUIRegion {
|
||||
|
||||
/**
|
||||
* Sends CUI events describing the region for
|
||||
* versions of CUI equal to or greater than the
|
||||
* value supplied by getProtocolVersion().
|
||||
*
|
||||
*/
|
||||
public void describeCUI(LocalSession session, Actor player);
|
||||
|
||||
/**
|
||||
* Sends CUI events describing the region for
|
||||
* versions of CUI smaller than the value
|
||||
* supplied by getProtocolVersion().
|
||||
*
|
||||
*/
|
||||
public void describeLegacyCUI(LocalSession session, Actor player);
|
||||
|
||||
/**
|
||||
* Returns the CUI version that is required to send
|
||||
* up-to-date data. If the CUI version is smaller than
|
||||
* this value, the legacy methods will be called.
|
||||
*
|
||||
* @return the protocol version
|
||||
*/
|
||||
public int getProtocolVersion();
|
||||
|
||||
/**
|
||||
* Returns the type ID to send to CUI in the selection event.
|
||||
*
|
||||
* @return the type ID
|
||||
*/
|
||||
public String getTypeID();
|
||||
|
||||
/**
|
||||
* Returns the type ID to send to CUI in the selection
|
||||
* event if the CUI is in legacy mode.
|
||||
*
|
||||
* @return the legacy type ID
|
||||
*/
|
||||
public String getLegacyTypeID();
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// $Id$
|
||||
|
||||
package com.sk89q.worldedit.internal.cui;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
|
||||
public class SelectionCylinderEvent implements CUIEvent {
|
||||
|
||||
protected final Vector pos;
|
||||
protected final Vector2D radius;
|
||||
|
||||
public SelectionCylinderEvent(Vector pos, Vector2D radius) {
|
||||
this.pos = pos;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeId() {
|
||||
return "cyl";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameters() {
|
||||
return new String[] {
|
||||
String.valueOf(pos.getBlockX()),
|
||||
String.valueOf(pos.getBlockY()),
|
||||
String.valueOf(pos.getBlockZ()),
|
||||
String.valueOf(radius.getX()),
|
||||
String.valueOf(radius.getZ())
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.cui;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
public class SelectionEllipsoidPointEvent implements CUIEvent {
|
||||
|
||||
protected final int id;
|
||||
protected final Vector pos;
|
||||
|
||||
public SelectionEllipsoidPointEvent(int id, Vector pos) {
|
||||
this.id = id;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeId() {
|
||||
return "e";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameters() {
|
||||
return new String[] {
|
||||
String.valueOf(id),
|
||||
String.valueOf(pos.getBlockX()),
|
||||
String.valueOf(pos.getBlockY()),
|
||||
String.valueOf(pos.getBlockZ())
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.cui;
|
||||
|
||||
public class SelectionMinMaxEvent implements CUIEvent {
|
||||
|
||||
protected final int min;
|
||||
protected final int max;
|
||||
|
||||
public SelectionMinMaxEvent(int min, int max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeId() {
|
||||
return "mm";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameters() {
|
||||
return new String[] {
|
||||
String.valueOf(min),
|
||||
String.valueOf(max),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.cui;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.Vector2D;
|
||||
|
||||
public class SelectionPoint2DEvent implements CUIEvent {
|
||||
|
||||
protected final int id;
|
||||
protected final int blockx;
|
||||
protected final int blockz;
|
||||
protected final int area;
|
||||
|
||||
public SelectionPoint2DEvent(int id, Vector2D pos, int area) {
|
||||
this.id = id;
|
||||
this.blockx = pos.getBlockX();
|
||||
this.blockz = pos.getBlockZ();
|
||||
this.area = area;
|
||||
}
|
||||
|
||||
public SelectionPoint2DEvent(int id, Vector pos, int area) {
|
||||
this.id = id;
|
||||
this.blockx = pos.getBlockX();
|
||||
this.blockz = pos.getBlockZ();
|
||||
this.area = area;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeId() {
|
||||
return "p2";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameters() {
|
||||
return new String[] {
|
||||
String.valueOf(id),
|
||||
String.valueOf(blockx),
|
||||
String.valueOf(blockz),
|
||||
String.valueOf(area)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.cui;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
|
||||
public class SelectionPointEvent implements CUIEvent {
|
||||
|
||||
protected final int id;
|
||||
protected final Vector pos;
|
||||
protected final int area;
|
||||
|
||||
public SelectionPointEvent(int id, Vector pos, int area) {
|
||||
this.id = id;
|
||||
this.pos = pos;
|
||||
this.area = area;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeId() {
|
||||
return "p";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameters() {
|
||||
return new String[] {
|
||||
String.valueOf(id),
|
||||
String.valueOf(pos.getBlockX()),
|
||||
String.valueOf(pos.getBlockY()),
|
||||
String.valueOf(pos.getBlockZ()),
|
||||
String.valueOf(area)
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// $Id$
|
||||
|
||||
package com.sk89q.worldedit.internal.cui;
|
||||
|
||||
public class SelectionPolygonEvent implements CUIEvent {
|
||||
|
||||
protected final int[] vertices;
|
||||
|
||||
public SelectionPolygonEvent(int... vertices) {
|
||||
this.vertices = vertices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeId() {
|
||||
return "poly";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameters() {
|
||||
final String[] ret = new String[vertices.length];
|
||||
|
||||
int i = 0;
|
||||
for (int vertex : vertices) {
|
||||
ret[i++] = String.valueOf(vertex);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.cui;
|
||||
|
||||
public class SelectionShapeEvent implements CUIEvent {
|
||||
|
||||
protected final String shapeName;
|
||||
|
||||
public SelectionShapeEvent(String shapeName) {
|
||||
this.shapeName = shapeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeId() {
|
||||
return "s";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getParameters() {
|
||||
return new String[] { shapeName };
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.lexer.Lexer;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.Token;
|
||||
import com.sk89q.worldedit.internal.expression.parser.Parser;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Constant;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Functions;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.RValue;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.ReturnException;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Variable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Compiles and evaluates expressions.
|
||||
*
|
||||
* <p>Supported operators:</p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>Logical: &&, ||, ! (unary)</li>
|
||||
* <li>Bitwise: ~ (unary), >>, <<</li>
|
||||
* <li>Arithmetic: +, -, *, /, % (modulo), ^ (power), - (unary), --, ++ (prefix only)</li>
|
||||
* <li>Comparison: <=, >=, >, <, ==, !=, ~= (near)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Supported functions: abs, acos, asin, atan, atan2, cbrt, ceil, cos, cosh,
|
||||
* exp, floor, ln, log, log10, max, max, min, min, rint, round, sin, sinh,
|
||||
* sqrt, tan, tanh and more. (See the Functions class or the wiki)</p>
|
||||
*
|
||||
* <p>Constants: e, pi</p>
|
||||
*
|
||||
* <p>To compile an equation, run
|
||||
* {@code Expression.compile("expression here", "var1", "var2"...)}.
|
||||
* If you wish to run the equation multiple times, you can then optimize it,
|
||||
* by calling {@link #optimize()}. You can then run the equation as many times
|
||||
* as you want by calling {@link #evaluate(double...)}. You do not need to
|
||||
* pass values for all variables specified while compiling.
|
||||
* To query variables after evaluation, you can use
|
||||
* {@link #getVariable(String, boolean)}. To get a value out of these, use
|
||||
* {@link Variable#getValue()}.</p>
|
||||
*
|
||||
* <p>Variables are also supported and can be set either by passing values
|
||||
* to {@link #evaluate(double...)}.</p>
|
||||
*/
|
||||
public class Expression {
|
||||
|
||||
private static final ThreadLocal<Stack<Expression>> instance = new ThreadLocal<Stack<Expression>>();
|
||||
|
||||
private final Map<String, RValue> variables = new HashMap<String, RValue>();
|
||||
private final String[] variableNames;
|
||||
private RValue root;
|
||||
private final Functions functions = new Functions();
|
||||
private ExpressionEnvironment environment;
|
||||
|
||||
public static Expression compile(String expression, String... variableNames) throws ExpressionException {
|
||||
return new Expression(expression, variableNames);
|
||||
}
|
||||
|
||||
private Expression(String expression, String... variableNames) throws ExpressionException {
|
||||
this(Lexer.tokenize(expression), variableNames);
|
||||
}
|
||||
|
||||
private Expression(List<Token> tokens, String... variableNames) throws ExpressionException {
|
||||
this.variableNames = variableNames;
|
||||
|
||||
variables.put("e", new Constant(-1, Math.E));
|
||||
variables.put("pi", new Constant(-1, Math.PI));
|
||||
variables.put("true", new Constant(-1, 1));
|
||||
variables.put("false", new Constant(-1, 0));
|
||||
|
||||
for (String variableName : variableNames) {
|
||||
if (variables.containsKey(variableName)) {
|
||||
throw new ExpressionException(-1, "Tried to overwrite identifier '" + variableName + "'");
|
||||
}
|
||||
variables.put(variableName, new Variable(0));
|
||||
}
|
||||
|
||||
root = Parser.parse(tokens, this);
|
||||
}
|
||||
|
||||
public double evaluate(double... values) throws EvaluationException {
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
final String variableName = variableNames[i];
|
||||
final RValue invokable = variables.get(variableName);
|
||||
if (!(invokable instanceof Variable)) {
|
||||
throw new EvaluationException(invokable.getPosition(), "Tried to assign constant " + variableName + ".");
|
||||
}
|
||||
|
||||
((Variable) invokable).value = values[i];
|
||||
}
|
||||
|
||||
pushInstance();
|
||||
try {
|
||||
return root.getValue();
|
||||
} catch (ReturnException e) {
|
||||
return e.getValue();
|
||||
} finally {
|
||||
popInstance();
|
||||
}
|
||||
}
|
||||
|
||||
public void optimize() throws EvaluationException {
|
||||
root = root.optimize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return root.toString();
|
||||
}
|
||||
|
||||
public RValue getVariable(String name, boolean create) {
|
||||
RValue variable = variables.get(name);
|
||||
if (variable == null && create) {
|
||||
variables.put(name, variable = new Variable(0));
|
||||
}
|
||||
|
||||
return variable;
|
||||
}
|
||||
|
||||
public static Expression getInstance() {
|
||||
return instance.get().peek();
|
||||
}
|
||||
|
||||
private void pushInstance() {
|
||||
Stack<Expression> foo = instance.get();
|
||||
if (foo == null) {
|
||||
instance.set(foo = new Stack<Expression>());
|
||||
}
|
||||
|
||||
foo.push(this);
|
||||
}
|
||||
|
||||
private void popInstance() {
|
||||
Stack<Expression> foo = instance.get();
|
||||
|
||||
foo.pop();
|
||||
|
||||
if (foo.isEmpty()) {
|
||||
instance.set(null);
|
||||
}
|
||||
}
|
||||
|
||||
public Functions getFunctions() {
|
||||
return functions;
|
||||
}
|
||||
|
||||
public ExpressionEnvironment getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
|
||||
public void setEnvironment(ExpressionEnvironment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression;
|
||||
|
||||
/**
|
||||
* Thrown when there's a problem during any stage of the expression
|
||||
* compilation or evaluation.
|
||||
*/
|
||||
public class ExpressionException extends Exception {
|
||||
|
||||
private final int position;
|
||||
|
||||
public ExpressionException(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public ExpressionException(int position, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public ExpressionException(int position, String message) {
|
||||
super(message);
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public ExpressionException(int position, Throwable cause) {
|
||||
super(cause);
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression;
|
||||
|
||||
/**
|
||||
* A common superinterface for everything passed to parser processors.
|
||||
*/
|
||||
public interface Identifiable {
|
||||
|
||||
/**
|
||||
* Returns a character that helps identify the token, pseudo-token or invokable in question.
|
||||
*
|
||||
* <pre>
|
||||
* Tokens:
|
||||
* i - IdentifierToken
|
||||
* 0 - NumberToken
|
||||
* o - OperatorToken
|
||||
* \0 - NullToken
|
||||
* CharacterTokens are returned literally
|
||||
*
|
||||
* PseudoTokens:
|
||||
* p - UnaryOperator
|
||||
* V - UnboundVariable
|
||||
*
|
||||
* Nodes:
|
||||
* c - Constant
|
||||
* v - Variable
|
||||
* f - Function
|
||||
* l - LValueFunction
|
||||
* s - Sequence
|
||||
* I - Conditional
|
||||
* w - While
|
||||
* F - For
|
||||
* r - Return
|
||||
* b - Break (includes continue)
|
||||
* S - SimpleFor
|
||||
* C - Switch
|
||||
* </pre>
|
||||
*/
|
||||
public abstract char id();
|
||||
|
||||
public int getPosition();
|
||||
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.lexer;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.CharacterToken;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.IdentifierToken;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.KeywordToken;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.NumberToken;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.Token;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Processes a string into a list of tokens.
|
||||
*
|
||||
* <p>Tokens can be numbers, identifiers, operators and assorted other
|
||||
* characters.</p>
|
||||
*/
|
||||
public class Lexer {
|
||||
|
||||
private final String expression;
|
||||
private int position = 0;
|
||||
|
||||
private Lexer(String expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public static List<Token> tokenize(String expression) throws LexerException {
|
||||
return new Lexer(expression).tokenize();
|
||||
}
|
||||
|
||||
private final DecisionTree operatorTree = new DecisionTree(null,
|
||||
'+', new DecisionTree("+",
|
||||
'=', new DecisionTree("+="),
|
||||
'+', new DecisionTree("++")
|
||||
),
|
||||
'-', new DecisionTree("-",
|
||||
'=', new DecisionTree("-="),
|
||||
'-', new DecisionTree("--")
|
||||
),
|
||||
'*', new DecisionTree("*",
|
||||
'=', new DecisionTree("*="),
|
||||
'*', new DecisionTree("**")
|
||||
),
|
||||
'/', new DecisionTree("/",
|
||||
'=', new DecisionTree("/=")
|
||||
),
|
||||
'%', new DecisionTree("%",
|
||||
'=', new DecisionTree("%=")
|
||||
),
|
||||
'^', new DecisionTree("^",
|
||||
'=', new DecisionTree("^=")
|
||||
),
|
||||
'=', new DecisionTree("=",
|
||||
'=', new DecisionTree("==")
|
||||
),
|
||||
'!', new DecisionTree("!",
|
||||
'=', new DecisionTree("!=")
|
||||
),
|
||||
'<', new DecisionTree("<",
|
||||
'<', new DecisionTree("<<"),
|
||||
'=', new DecisionTree("<=")
|
||||
),
|
||||
'>', new DecisionTree(">",
|
||||
'>', new DecisionTree(">>"),
|
||||
'=', new DecisionTree(">=")
|
||||
),
|
||||
'&', new DecisionTree(null, // not implemented
|
||||
'&', new DecisionTree("&&")
|
||||
),
|
||||
'|', new DecisionTree(null, // not implemented
|
||||
'|', new DecisionTree("||")
|
||||
),
|
||||
'~', new DecisionTree("~",
|
||||
'=', new DecisionTree("~=")
|
||||
)
|
||||
);
|
||||
|
||||
private static final Set<Character> characterTokens = new HashSet<Character>();
|
||||
static {
|
||||
characterTokens.add(',');
|
||||
characterTokens.add('(');
|
||||
characterTokens.add(')');
|
||||
characterTokens.add('{');
|
||||
characterTokens.add('}');
|
||||
characterTokens.add(';');
|
||||
characterTokens.add('?');
|
||||
characterTokens.add(':');
|
||||
}
|
||||
|
||||
private static final Set<String> keywords = new HashSet<String>(Arrays.asList("if", "else", "while", "do", "for", "break", "continue", "return", "switch", "case", "default"));
|
||||
|
||||
private static final Pattern numberPattern = Pattern.compile("^([0-9]*(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?)");
|
||||
private static final Pattern identifierPattern = Pattern.compile("^([A-Za-z][0-9A-Za-z_]*)");
|
||||
|
||||
private List<Token> tokenize() throws LexerException {
|
||||
List<Token> tokens = new ArrayList<Token>();
|
||||
|
||||
do {
|
||||
skipWhitespace();
|
||||
if (position >= expression.length()) {
|
||||
break;
|
||||
}
|
||||
|
||||
Token token = operatorTree.evaluate(position);
|
||||
if (token != null) {
|
||||
tokens.add(token);
|
||||
continue;
|
||||
}
|
||||
|
||||
final char ch = peek();
|
||||
|
||||
if (characterTokens.contains(ch)) {
|
||||
tokens.add(new CharacterToken(position++, ch));
|
||||
continue;
|
||||
}
|
||||
|
||||
final Matcher numberMatcher = numberPattern.matcher(expression.substring(position));
|
||||
if (numberMatcher.lookingAt()) {
|
||||
String numberPart = numberMatcher.group(1);
|
||||
if (!numberPart.isEmpty()) {
|
||||
try {
|
||||
tokens.add(new NumberToken(position, Double.parseDouble(numberPart)));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new LexerException(position, "Number parsing failed", e);
|
||||
}
|
||||
|
||||
position += numberPart.length();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
final Matcher identifierMatcher = identifierPattern.matcher(expression.substring(position));
|
||||
if (identifierMatcher.lookingAt()) {
|
||||
String identifierPart = identifierMatcher.group(1);
|
||||
if (!identifierPart.isEmpty()) {
|
||||
if (keywords.contains(identifierPart)) {
|
||||
tokens.add(new KeywordToken(position, identifierPart));
|
||||
} else {
|
||||
tokens.add(new IdentifierToken(position, identifierPart));
|
||||
}
|
||||
|
||||
position += identifierPart.length();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
throw new LexerException(position, "Unknown character '" + ch + "'");
|
||||
} while (position < expression.length());
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
private char peek() {
|
||||
return expression.charAt(position);
|
||||
}
|
||||
|
||||
private void skipWhitespace() {
|
||||
while (position < expression.length() && Character.isWhitespace(peek())) {
|
||||
++position;
|
||||
}
|
||||
}
|
||||
|
||||
public class DecisionTree {
|
||||
private final String tokenName;
|
||||
private final Map<Character, DecisionTree> subTrees = new HashMap<Character, Lexer.DecisionTree>();
|
||||
|
||||
private DecisionTree(String tokenName, Object... args) {
|
||||
this.tokenName = tokenName;
|
||||
|
||||
if (args.length % 2 != 0) {
|
||||
throw new UnsupportedOperationException("You need to pass an even number of arguments.");
|
||||
}
|
||||
|
||||
for (int i = 0; i < args.length; i += 2) {
|
||||
if (!(args[i] instanceof Character)) {
|
||||
throw new UnsupportedOperationException("Argument #" + i + " expected to be 'Character', not '" + args[i].getClass().getName() + "'.");
|
||||
}
|
||||
if (!(args[i + 1] instanceof DecisionTree)) {
|
||||
throw new UnsupportedOperationException("Argument #" + (i + 1) + " expected to be 'DecisionTree', not '" + args[i + 1].getClass().getName() + "'.");
|
||||
}
|
||||
|
||||
Character next = (Character) args[i];
|
||||
DecisionTree subTree = (DecisionTree) args[i + 1];
|
||||
|
||||
subTrees.put(next, subTree);
|
||||
}
|
||||
}
|
||||
|
||||
private Token evaluate(int startPosition) throws LexerException {
|
||||
if (position < expression.length()) {
|
||||
final char next = peek();
|
||||
|
||||
final DecisionTree subTree = subTrees.get(next);
|
||||
if (subTree != null) {
|
||||
++position;
|
||||
final Token subTreeResult = subTree.evaluate(startPosition);
|
||||
if (subTreeResult != null) {
|
||||
return subTreeResult;
|
||||
}
|
||||
--position;
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new OperatorToken(startPosition, tokenName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.lexer;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
|
||||
/**
|
||||
* Thrown when the lexer encounters a problem.
|
||||
*/
|
||||
public class LexerException extends ExpressionException {
|
||||
|
||||
public LexerException(int position) {
|
||||
super(position, getPrefix(position));
|
||||
}
|
||||
|
||||
public LexerException(int position, String message, Throwable cause) {
|
||||
super(position, getPrefix(position) + ": " + message, cause);
|
||||
}
|
||||
|
||||
public LexerException(int position, String message) {
|
||||
super(position, getPrefix(position) + ": " + message);
|
||||
}
|
||||
|
||||
public LexerException(int position, Throwable cause) {
|
||||
super(position, getPrefix(position), cause);
|
||||
}
|
||||
|
||||
private static String getPrefix(int position) {
|
||||
return position < 0 ? "Lexer error" : ("Lexer error at " + (position + 1));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.lexer.tokens;
|
||||
|
||||
/**
|
||||
* A single character that doesn't fit any of the other token categories.
|
||||
*/
|
||||
public class CharacterToken extends Token {
|
||||
|
||||
public final char character;
|
||||
|
||||
public CharacterToken(int position, char character) {
|
||||
super(position);
|
||||
this.character = character;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return character;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CharacterToken(" + character + ")";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.lexer.tokens;
|
||||
|
||||
/**
|
||||
* An identifier.
|
||||
*/
|
||||
public class IdentifierToken extends Token {
|
||||
|
||||
public final String value;
|
||||
|
||||
public IdentifierToken(int position, String value) {
|
||||
super(position);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'i';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IdentifierToken(" + value + ")";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.lexer.tokens;
|
||||
|
||||
/**
|
||||
* A keyword.
|
||||
*/
|
||||
public class KeywordToken extends Token {
|
||||
|
||||
public final String value;
|
||||
|
||||
public KeywordToken(int position, String value) {
|
||||
super(position);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'k';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KeywordToken(" + value + ")";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.lexer.tokens;
|
||||
|
||||
/**
|
||||
* A number.
|
||||
*/
|
||||
public class NumberToken extends Token {
|
||||
|
||||
public final double value;
|
||||
|
||||
public NumberToken(int position, double value) {
|
||||
super(position);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return '0';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NumberToken(" + value + ")";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.lexer.tokens;
|
||||
|
||||
/**
|
||||
* A unary or binary operator.
|
||||
*/
|
||||
public class OperatorToken extends Token {
|
||||
|
||||
public final String operator;
|
||||
|
||||
public OperatorToken(int position, String operator) {
|
||||
super(position);
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'o';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OperatorToken(" + operator + ")";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.lexer.tokens;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Identifiable;
|
||||
|
||||
/**
|
||||
* A token. The lexer generates these to make the parser's job easier.
|
||||
*/
|
||||
public abstract class Token implements Identifiable {
|
||||
|
||||
private final int position;
|
||||
|
||||
public Token(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,464 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.parser;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.Identifiable;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.IdentifierToken;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.KeywordToken;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.NumberToken;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.Token;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Break;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Conditional;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Constant;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.For;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Function;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Functions;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.LValue;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.RValue;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Return;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Sequence;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.SimpleFor;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Switch;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.While;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Processes a list of tokens into an executable tree.
|
||||
*
|
||||
* <p>Tokens can be numbers, identifiers, operators and assorted other characters.</p>
|
||||
*/
|
||||
public class Parser {
|
||||
private final class NullToken extends Token {
|
||||
private NullToken(int position) {
|
||||
super(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return '\0';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NullToken";
|
||||
}
|
||||
}
|
||||
|
||||
private final List<Token> tokens;
|
||||
private int position = 0;
|
||||
private Expression expression;
|
||||
|
||||
private Parser(List<Token> tokens, Expression expression) {
|
||||
this.tokens = tokens;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public static RValue parse(List<Token> tokens, Expression expression) throws ParserException {
|
||||
return new Parser(tokens, expression).parse();
|
||||
}
|
||||
|
||||
private RValue parse() throws ParserException {
|
||||
final RValue ret = parseStatements(false);
|
||||
if (position < tokens.size()) {
|
||||
final Token token = peek();
|
||||
throw new ParserException(token.getPosition(), "Extra token at the end of the input: " + token);
|
||||
}
|
||||
|
||||
ret.bindVariables(expression, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private RValue parseStatements(boolean singleStatement) throws ParserException {
|
||||
List<RValue> statements = new ArrayList<RValue>();
|
||||
loop: while (position < tokens.size()) {
|
||||
boolean expectSemicolon = false;
|
||||
|
||||
final Token current = peek();
|
||||
switch (current.id()) {
|
||||
case '{':
|
||||
consumeCharacter('{');
|
||||
|
||||
statements.add(parseStatements(false));
|
||||
|
||||
consumeCharacter('}');
|
||||
|
||||
break;
|
||||
|
||||
case '}':
|
||||
break loop;
|
||||
|
||||
case 'k':
|
||||
final String keyword = ((KeywordToken) current).value;
|
||||
switch (keyword.charAt(0)) {
|
||||
case 'i': { // if
|
||||
++position;
|
||||
final RValue condition = parseBracket();
|
||||
final RValue truePart = parseStatements(true);
|
||||
final RValue falsePart;
|
||||
|
||||
if (hasKeyword("else")) {
|
||||
++position;
|
||||
falsePart = parseStatements(true);
|
||||
} else {
|
||||
falsePart = null;
|
||||
}
|
||||
|
||||
statements.add(new Conditional(current.getPosition(), condition, truePart, falsePart));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'w': { // while
|
||||
++position;
|
||||
final RValue condition = parseBracket();
|
||||
final RValue body = parseStatements(true);
|
||||
|
||||
statements.add(new While(current.getPosition(), condition, body, false));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd': { // do/default
|
||||
if (hasKeyword("default")) {
|
||||
break loop;
|
||||
}
|
||||
|
||||
++position;
|
||||
final RValue body = parseStatements(true);
|
||||
|
||||
consumeKeyword("while");
|
||||
|
||||
final RValue condition = parseBracket();
|
||||
|
||||
statements.add(new While(current.getPosition(), condition, body, true));
|
||||
|
||||
expectSemicolon = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'f': { // for
|
||||
++position;
|
||||
consumeCharacter('(');
|
||||
int oldPosition = position;
|
||||
final RValue init = parseExpression(true);
|
||||
//if ((init instanceof LValue) && )
|
||||
if (peek().id() == ';') {
|
||||
++position;
|
||||
final RValue condition = parseExpression(true);
|
||||
consumeCharacter(';');
|
||||
final RValue increment = parseExpression(true);
|
||||
consumeCharacter(')');
|
||||
final RValue body = parseStatements(true);
|
||||
|
||||
statements.add(new For(current.getPosition(), init, condition, increment, body));
|
||||
} else {
|
||||
position = oldPosition;
|
||||
|
||||
final Token variableToken = peek();
|
||||
if (!(variableToken instanceof IdentifierToken)) {
|
||||
throw new ParserException(variableToken.getPosition(), "Expected identifier");
|
||||
}
|
||||
|
||||
RValue variable = expression.getVariable(((IdentifierToken) variableToken).value, true);
|
||||
if (!(variable instanceof LValue)) {
|
||||
throw new ParserException(variableToken.getPosition(), "Expected variable");
|
||||
}
|
||||
++position;
|
||||
|
||||
final Token equalsToken = peek();
|
||||
if (!(equalsToken instanceof OperatorToken) || !((OperatorToken) equalsToken).operator.equals("=")) {
|
||||
throw new ParserException(variableToken.getPosition(), "Expected '=' or a term and ';'");
|
||||
}
|
||||
++position;
|
||||
|
||||
final RValue first = parseExpression(true);
|
||||
consumeCharacter(',');
|
||||
final RValue last = parseExpression(true);
|
||||
consumeCharacter(')');
|
||||
final RValue body = parseStatements(true);
|
||||
|
||||
statements.add(new SimpleFor(current.getPosition(), (LValue) variable, first, last, body));
|
||||
} // switch (keyword.charAt(0))
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b': // break
|
||||
++position;
|
||||
statements.add(new Break(current.getPosition(), false));
|
||||
break;
|
||||
|
||||
case 'c': // continue/case
|
||||
if (hasKeyword("case")) {
|
||||
break loop;
|
||||
}
|
||||
|
||||
++position;
|
||||
statements.add(new Break(current.getPosition(), true));
|
||||
break;
|
||||
|
||||
case 'r': // return
|
||||
++position;
|
||||
statements.add(new Return(current.getPosition(), parseExpression(true)));
|
||||
|
||||
expectSemicolon = true;
|
||||
break;
|
||||
|
||||
case 's': // switch
|
||||
++position;
|
||||
final RValue parameter = parseBracket();
|
||||
final List<Double> values = new ArrayList<Double>();
|
||||
final List<RValue> caseStatements = new ArrayList<RValue>();
|
||||
RValue defaultCase = null;
|
||||
|
||||
consumeCharacter('{');
|
||||
while (peek().id() != '}') {
|
||||
if (position >= tokens.size()) {
|
||||
throw new ParserException(current.getPosition(), "Expected '}' instead of EOF");
|
||||
}
|
||||
if (defaultCase != null) {
|
||||
throw new ParserException(current.getPosition(), "Expected '}' instead of " + peek());
|
||||
}
|
||||
|
||||
if (hasKeyword("case")) {
|
||||
++position;
|
||||
|
||||
final Token valueToken = peek();
|
||||
if (!(valueToken instanceof NumberToken)) {
|
||||
throw new ParserException(current.getPosition(), "Expected number instead of " + peek());
|
||||
}
|
||||
|
||||
++position;
|
||||
|
||||
values.add(((NumberToken) valueToken).value);
|
||||
|
||||
consumeCharacter(':');
|
||||
caseStatements.add(parseStatements(false));
|
||||
} else if (hasKeyword("default")) {
|
||||
++position;
|
||||
|
||||
consumeCharacter(':');
|
||||
defaultCase = parseStatements(false);
|
||||
} else {
|
||||
throw new ParserException(current.getPosition(), "Expected 'case' or 'default' instead of " + peek());
|
||||
}
|
||||
}
|
||||
consumeCharacter('}');
|
||||
|
||||
statements.add(new Switch(current.getPosition(), parameter, values, caseStatements, defaultCase));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ParserException(current.getPosition(), "Unexpected keyword '" + keyword + "'");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
statements.add(parseExpression(true));
|
||||
|
||||
expectSemicolon = true;
|
||||
} // switch (current.id())
|
||||
|
||||
if (expectSemicolon) {
|
||||
if (peek().id() == ';') {
|
||||
++position;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (singleStatement) {
|
||||
break;
|
||||
}
|
||||
} // while (position < tokens.size())
|
||||
|
||||
switch (statements.size()) {
|
||||
case 0:
|
||||
if (singleStatement) {
|
||||
throw new ParserException(peek().getPosition(), "Statement expected.");
|
||||
}
|
||||
|
||||
return new Sequence(peek().getPosition());
|
||||
|
||||
case 1:
|
||||
return statements.get(0);
|
||||
|
||||
default:
|
||||
return new Sequence(peek().getPosition(), statements.toArray(new RValue[statements.size()]));
|
||||
}
|
||||
}
|
||||
|
||||
private RValue parseExpression(boolean canBeEmpty) throws ParserException {
|
||||
LinkedList<Identifiable> halfProcessed = new LinkedList<Identifiable>();
|
||||
|
||||
// process brackets, numbers, functions, variables and detect prefix operators
|
||||
boolean expressionStart = true;
|
||||
loop: while (position < tokens.size()) {
|
||||
final Token current = peek();
|
||||
|
||||
switch (current.id()) {
|
||||
case '0':
|
||||
halfProcessed.add(new Constant(current.getPosition(), ((NumberToken) current).value));
|
||||
++position;
|
||||
expressionStart = false;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
final IdentifierToken identifierToken = (IdentifierToken) current;
|
||||
++position;
|
||||
|
||||
final Token next = peek();
|
||||
if (next.id() == '(') {
|
||||
halfProcessed.add(parseFunctionCall(identifierToken));
|
||||
} else {
|
||||
final RValue variable = expression.getVariable(identifierToken.value, false);
|
||||
if (variable == null) {
|
||||
halfProcessed.add(new UnboundVariable(identifierToken.getPosition(), identifierToken.value));
|
||||
} else {
|
||||
halfProcessed.add(variable);
|
||||
}
|
||||
}
|
||||
expressionStart = false;
|
||||
break;
|
||||
|
||||
case '(':
|
||||
halfProcessed.add(parseBracket());
|
||||
expressionStart = false;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
case ')':
|
||||
case '}':
|
||||
case ';':
|
||||
break loop;
|
||||
|
||||
case 'o':
|
||||
if (expressionStart) {
|
||||
// Preprocess prefix operators into unary operators
|
||||
halfProcessed.add(new UnaryOperator((OperatorToken) current));
|
||||
} else {
|
||||
halfProcessed.add(current);
|
||||
}
|
||||
++position;
|
||||
expressionStart = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
halfProcessed.add(current);
|
||||
++position;
|
||||
expressionStart = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (halfProcessed.isEmpty() && canBeEmpty) {
|
||||
return new Sequence(peek().getPosition());
|
||||
}
|
||||
|
||||
return ParserProcessors.processExpression(halfProcessed);
|
||||
}
|
||||
|
||||
|
||||
private Token peek() {
|
||||
if (position >= tokens.size()) {
|
||||
return new NullToken(tokens.get(tokens.size() - 1).getPosition() + 1);
|
||||
}
|
||||
|
||||
return tokens.get(position);
|
||||
}
|
||||
|
||||
private Function parseFunctionCall(IdentifierToken identifierToken) throws ParserException {
|
||||
consumeCharacter('(');
|
||||
|
||||
try {
|
||||
if (peek().id() == ')') {
|
||||
++position;
|
||||
return Functions.getFunction(identifierToken.getPosition(), identifierToken.value);
|
||||
}
|
||||
|
||||
List<RValue> args = new ArrayList<RValue>();
|
||||
|
||||
loop: while (true) {
|
||||
args.add(parseExpression(false));
|
||||
|
||||
final Token current = peek();
|
||||
++position;
|
||||
|
||||
switch (current.id()) {
|
||||
case ',':
|
||||
continue;
|
||||
|
||||
case ')':
|
||||
break loop;
|
||||
|
||||
default:
|
||||
throw new ParserException(current.getPosition(), "Unmatched opening bracket");
|
||||
}
|
||||
}
|
||||
|
||||
return Functions.getFunction(identifierToken.getPosition(), identifierToken.value, args.toArray(new RValue[args.size()]));
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new ParserException(identifierToken.getPosition(), "Function '" + identifierToken.value + "' not found", e);
|
||||
}
|
||||
}
|
||||
|
||||
private RValue parseBracket() throws ParserException {
|
||||
consumeCharacter('(');
|
||||
|
||||
final RValue ret = parseExpression(false);
|
||||
|
||||
consumeCharacter(')');
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private boolean hasKeyword(String keyword) {
|
||||
final Token next = peek();
|
||||
|
||||
return next instanceof KeywordToken && ((KeywordToken) next).value.equals(keyword);
|
||||
}
|
||||
|
||||
private void assertCharacter(char character) throws ParserException {
|
||||
final Token next = peek();
|
||||
if (next.id() != character) {
|
||||
throw new ParserException(next.getPosition(), "Expected '" + character + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private void assertKeyword(String keyword) throws ParserException {
|
||||
if (!hasKeyword(keyword)) {
|
||||
throw new ParserException(peek().getPosition(), "Expected '" + keyword + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private void consumeCharacter(char character) throws ParserException {
|
||||
assertCharacter(character);
|
||||
++position;
|
||||
}
|
||||
|
||||
private void consumeKeyword(String keyword) throws ParserException {
|
||||
assertKeyword(keyword);
|
||||
++position;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.parser;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
|
||||
/**
|
||||
* Thrown when the parser encounters a problem.
|
||||
*/
|
||||
public class ParserException extends ExpressionException {
|
||||
|
||||
public ParserException(int position) {
|
||||
super(position, getPrefix(position));
|
||||
}
|
||||
|
||||
public ParserException(int position, String message, Throwable cause) {
|
||||
super(position, getPrefix(position) + ": " + message, cause);
|
||||
}
|
||||
|
||||
public ParserException(int position, String message) {
|
||||
super(position, getPrefix(position) + ": " + message);
|
||||
}
|
||||
|
||||
public ParserException(int position, Throwable cause) {
|
||||
super(position, getPrefix(position), cause);
|
||||
}
|
||||
|
||||
private static String getPrefix(int position) {
|
||||
return position < 0 ? "Parser error" : ("Parser error at " + (position + 1));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.parser;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Identifiable;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken;
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.Token;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Conditional;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Operators;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.RValue;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Helper classfor Parser. Contains processors for statements and operators.
|
||||
*/
|
||||
public final class ParserProcessors {
|
||||
|
||||
private static final Map<String, String> unaryOpMap = new HashMap<String, String>();
|
||||
|
||||
private static final Map<String, String>[] binaryOpMapsLA;
|
||||
private static final Map<String, String>[] binaryOpMapsRA;
|
||||
|
||||
static {
|
||||
unaryOpMap.put("-", "neg");
|
||||
unaryOpMap.put("!", "not");
|
||||
unaryOpMap.put("~", "inv");
|
||||
unaryOpMap.put("++", "inc");
|
||||
unaryOpMap.put("--", "dec");
|
||||
unaryOpMap.put("x++", "postinc");
|
||||
unaryOpMap.put("x--", "postdec");
|
||||
unaryOpMap.put("x!", "fac");
|
||||
|
||||
final Object[][][] binaryOpsLA = {
|
||||
{
|
||||
{ "^", "pow" },
|
||||
{ "**", "pow" },
|
||||
},
|
||||
{
|
||||
{ "*", "mul" },
|
||||
{ "/", "div" },
|
||||
{ "%", "mod" },
|
||||
},
|
||||
{
|
||||
{ "+", "add" },
|
||||
{ "-", "sub" },
|
||||
},
|
||||
{
|
||||
{ "<<", "shl" },
|
||||
{ ">>", "shr" },
|
||||
},
|
||||
{
|
||||
{ "<", "lth" },
|
||||
{ ">", "gth" },
|
||||
{ "<=", "leq" },
|
||||
{ ">=", "geq" },
|
||||
},
|
||||
{
|
||||
{ "==", "equ" },
|
||||
{ "!=", "neq" },
|
||||
{ "~=", "near" },
|
||||
},
|
||||
{
|
||||
{ "&&", "and" },
|
||||
},
|
||||
{
|
||||
{ "||", "or" },
|
||||
},
|
||||
};
|
||||
final Object[][][] binaryOpsRA = {
|
||||
{
|
||||
{ "=", "ass" },
|
||||
{ "+=", "aadd" },
|
||||
{ "-=", "asub" },
|
||||
{ "*=", "amul" },
|
||||
{ "/=", "adiv" },
|
||||
{ "%=", "amod" },
|
||||
{ "^=", "aexp" },
|
||||
},
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<String, String>[] lBinaryOpMapsLA = binaryOpMapsLA = new Map[binaryOpsLA.length];
|
||||
for (int i = 0; i < binaryOpsLA.length; ++i) {
|
||||
final Object[][] a = binaryOpsLA[i];
|
||||
switch (a.length) {
|
||||
case 0:
|
||||
lBinaryOpMapsLA[i] = Collections.emptyMap();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
final Object[] first = a[0];
|
||||
lBinaryOpMapsLA[i] = Collections.singletonMap((String) first[0], (String) first[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
Map<String, String> m = lBinaryOpMapsLA[i] = new HashMap<String, String>();
|
||||
for (final Object[] element : a) {
|
||||
m.put((String) element[0], (String) element[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<String, String>[] lBinaryOpMapsRA = binaryOpMapsRA = new Map[binaryOpsRA.length];
|
||||
for (int i = 0; i < binaryOpsRA.length; ++i) {
|
||||
final Object[][] a = binaryOpsRA[i];
|
||||
switch (a.length) {
|
||||
case 0:
|
||||
lBinaryOpMapsRA[i] = Collections.emptyMap();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
final Object[] first = a[0];
|
||||
lBinaryOpMapsRA[i] = Collections.singletonMap((String) first[0], (String) first[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
Map<String, String> m = lBinaryOpMapsRA[i] = new HashMap<String, String>();
|
||||
for (final Object[] element : a) {
|
||||
m.put((String) element[0], (String) element[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ParserProcessors() {
|
||||
}
|
||||
|
||||
static RValue processExpression(LinkedList<Identifiable> input) throws ParserException {
|
||||
return processBinaryOpsRA(input, binaryOpMapsRA.length - 1);
|
||||
}
|
||||
|
||||
private static RValue processBinaryOpsLA(LinkedList<Identifiable> input, int level) throws ParserException {
|
||||
if (level < 0) {
|
||||
return processUnaryOps(input);
|
||||
}
|
||||
|
||||
LinkedList<Identifiable> lhs = new LinkedList<Identifiable>();
|
||||
LinkedList<Identifiable> rhs = new LinkedList<Identifiable>();
|
||||
String operator = null;
|
||||
|
||||
for (Iterator<Identifiable> it = input.descendingIterator(); it.hasNext();) {
|
||||
Identifiable identifiable = it.next();
|
||||
if (operator == null) {
|
||||
rhs.addFirst(identifiable);
|
||||
|
||||
if (!(identifiable instanceof OperatorToken)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
operator = binaryOpMapsLA[level].get(((OperatorToken) identifiable).operator);
|
||||
if (operator == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rhs.removeFirst();
|
||||
} else {
|
||||
lhs.addFirst(identifiable);
|
||||
}
|
||||
}
|
||||
|
||||
RValue rhsInvokable = processBinaryOpsLA(rhs, level - 1);
|
||||
if (operator == null) return rhsInvokable;
|
||||
|
||||
RValue lhsInvokable = processBinaryOpsLA(lhs, level);
|
||||
|
||||
try {
|
||||
return Operators.getOperator(input.get(0).getPosition(), operator, lhsInvokable, rhsInvokable);
|
||||
} catch (NoSuchMethodException e) {
|
||||
final Token operatorToken = (Token) input.get(lhs.size());
|
||||
throw new ParserException(operatorToken.getPosition(), "Couldn't find operator '" + operator + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private static RValue processBinaryOpsRA(LinkedList<Identifiable> input, int level) throws ParserException {
|
||||
if (level < 0) {
|
||||
return processTernaryOps(input);
|
||||
}
|
||||
|
||||
LinkedList<Identifiable> lhs = new LinkedList<Identifiable>();
|
||||
LinkedList<Identifiable> rhs = new LinkedList<Identifiable>();
|
||||
String operator = null;
|
||||
|
||||
for (Identifiable identifiable : input) {
|
||||
if (operator == null) {
|
||||
lhs.addLast(identifiable);
|
||||
|
||||
if (!(identifiable instanceof OperatorToken)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
operator = binaryOpMapsRA[level].get(((OperatorToken) identifiable).operator);
|
||||
if (operator == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lhs.removeLast();
|
||||
} else {
|
||||
rhs.addLast(identifiable);
|
||||
}
|
||||
}
|
||||
|
||||
RValue lhsInvokable = processBinaryOpsRA(lhs, level - 1);
|
||||
if (operator == null) return lhsInvokable;
|
||||
|
||||
RValue rhsInvokable = processBinaryOpsRA(rhs, level);
|
||||
|
||||
try {
|
||||
return Operators.getOperator(input.get(0).getPosition(), operator, lhsInvokable, rhsInvokable);
|
||||
} catch (NoSuchMethodException e) {
|
||||
final Token operatorToken = (Token) input.get(lhs.size());
|
||||
throw new ParserException(operatorToken.getPosition(), "Couldn't find operator '" + operator + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private static RValue processTernaryOps(LinkedList<Identifiable> input) throws ParserException {
|
||||
LinkedList<Identifiable> lhs = new LinkedList<Identifiable>();
|
||||
LinkedList<Identifiable> mhs = new LinkedList<Identifiable>();
|
||||
LinkedList<Identifiable> rhs = new LinkedList<Identifiable>();
|
||||
|
||||
int partsFound = 0;
|
||||
int conditionalsFound = 0;
|
||||
|
||||
for (Identifiable identifiable : input) {
|
||||
final char character = identifiable.id();
|
||||
switch (character) {
|
||||
case '?':
|
||||
++conditionalsFound;
|
||||
break;
|
||||
case ':':
|
||||
--conditionalsFound;
|
||||
break;
|
||||
}
|
||||
|
||||
if (conditionalsFound < 0) {
|
||||
throw new ParserException(identifiable.getPosition(), "Unexpected ':'");
|
||||
}
|
||||
|
||||
switch (partsFound) {
|
||||
case 0:
|
||||
if (character == '?') {
|
||||
partsFound = 1;
|
||||
} else {
|
||||
lhs.addLast(identifiable);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (conditionalsFound == 0 && character == ':') {
|
||||
partsFound = 2;
|
||||
} else {
|
||||
mhs.addLast(identifiable);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
rhs.addLast(identifiable);
|
||||
}
|
||||
}
|
||||
|
||||
if (partsFound < 2) {
|
||||
return processBinaryOpsLA(input, binaryOpMapsLA.length - 1);
|
||||
}
|
||||
|
||||
RValue lhsInvokable = processBinaryOpsLA(lhs, binaryOpMapsLA.length - 1);
|
||||
RValue mhsInvokable = processTernaryOps(mhs);
|
||||
RValue rhsInvokable = processTernaryOps(rhs);
|
||||
|
||||
return new Conditional(input.get(lhs.size()).getPosition(), lhsInvokable, mhsInvokable, rhsInvokable);
|
||||
}
|
||||
|
||||
private static RValue processUnaryOps(LinkedList<Identifiable> input) throws ParserException {
|
||||
// Preprocess postfix operators into unary operators
|
||||
final Identifiable center;
|
||||
LinkedList<UnaryOperator> postfixes = new LinkedList<UnaryOperator>();
|
||||
do {
|
||||
if (input.isEmpty()) {
|
||||
throw new ParserException(-1, "Expression missing.");
|
||||
}
|
||||
|
||||
final Identifiable last = input.removeLast();
|
||||
if (last instanceof OperatorToken) {
|
||||
postfixes.addLast(new UnaryOperator(last.getPosition(), "x" + ((OperatorToken) last).operator));
|
||||
} else if (last instanceof UnaryOperator) {
|
||||
postfixes.addLast(new UnaryOperator(last.getPosition(), "x" + ((UnaryOperator) last).operator));
|
||||
} else {
|
||||
center = last;
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
if (!(center instanceof RValue)) {
|
||||
throw new ParserException(center.getPosition(), "Expected expression, found " + center);
|
||||
}
|
||||
|
||||
input.addAll(postfixes);
|
||||
|
||||
RValue ret = (RValue) center;
|
||||
while (!input.isEmpty()) {
|
||||
final Identifiable last = input.removeLast();
|
||||
final int lastPosition = last.getPosition();
|
||||
if (last instanceof UnaryOperator) {
|
||||
final String operator = ((UnaryOperator) last).operator;
|
||||
if (operator.equals("+")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String opName = unaryOpMap.get(operator);
|
||||
if (opName != null) {
|
||||
try {
|
||||
ret = Operators.getOperator(lastPosition, opName, ret);
|
||||
continue;
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new ParserException(lastPosition, "No such prefix operator: " + operator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (last instanceof Token) {
|
||||
throw new ParserException(lastPosition, "Extra token found in expression: " + last);
|
||||
} else if (last instanceof RValue) {
|
||||
throw new ParserException(lastPosition, "Extra expression found: " + last);
|
||||
} else {
|
||||
throw new ParserException(lastPosition, "Extra element found: " + last);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.parser;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Identifiable;
|
||||
|
||||
/**
|
||||
* A pseudo-token, inserted by the parser instead of the lexer.
|
||||
*/
|
||||
public abstract class PseudoToken implements Identifiable {
|
||||
|
||||
private final int position;
|
||||
|
||||
public PseudoToken(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract char id();
|
||||
|
||||
@Override
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.parser;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.lexer.tokens.OperatorToken;
|
||||
|
||||
/**
|
||||
* The parser uses this pseudo-token to mark operators as unary operators.
|
||||
*/
|
||||
public class UnaryOperator extends PseudoToken {
|
||||
|
||||
final String operator;
|
||||
|
||||
public UnaryOperator(OperatorToken operatorToken) {
|
||||
this(operatorToken.getPosition(), operatorToken.operator);
|
||||
}
|
||||
|
||||
public UnaryOperator(int position, String operator) {
|
||||
super(position);
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'p';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UnaryOperator(" + operator + ")";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.parser;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.LValue;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.RValue;
|
||||
|
||||
public class UnboundVariable extends PseudoToken implements LValue {
|
||||
|
||||
public final String name;
|
||||
|
||||
public UnboundVariable(int position, String name) {
|
||||
super(position);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'V';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UnboundVariable(" + name + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
throw new EvaluationException(getPosition(), "Tried to evaluate unbound variable!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LValue optimize() throws EvaluationException {
|
||||
throw new EvaluationException(getPosition(), "Tried to optimize unbound variable!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public double assign(double value) throws EvaluationException {
|
||||
throw new EvaluationException(getPosition(), "Tried to assign unbound variable!");
|
||||
}
|
||||
|
||||
public RValue bind(Expression expression, boolean isLValue) throws ParserException {
|
||||
final RValue variable = expression.getVariable(name, isLValue);
|
||||
if (variable == null) {
|
||||
throw new ParserException(getPosition(), "Variable '" + name + "' not found");
|
||||
}
|
||||
|
||||
return variable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
final RValue variable = expression.getVariable(name, preferLValue);
|
||||
if (variable == null) {
|
||||
throw new ParserException(getPosition(), "Variable '" + name + "' not found");
|
||||
}
|
||||
|
||||
return (LValue) variable;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
/**
|
||||
* A break or continue statement.
|
||||
*/
|
||||
public class Break extends Node {
|
||||
|
||||
boolean doContinue;
|
||||
|
||||
public Break(int position, boolean doContinue) {
|
||||
super(position);
|
||||
|
||||
this.doContinue = doContinue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
throw new BreakException(doContinue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'b';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return doContinue ? "continue" : "break";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
/**
|
||||
* Thrown when a break or continue is encountered.
|
||||
* Loop constructs catch this exception.
|
||||
*/
|
||||
public class BreakException extends EvaluationException {
|
||||
|
||||
final boolean doContinue;
|
||||
|
||||
public BreakException(boolean doContinue) {
|
||||
super(-1, doContinue ? "'continue' encountered outside a loop" : "'break' encountered outside a loop");
|
||||
|
||||
this.doContinue = doContinue;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
/**
|
||||
* An if/else statement or a ternary operator.
|
||||
*/
|
||||
public class Conditional extends Node {
|
||||
|
||||
private RValue condition;
|
||||
private RValue truePart;
|
||||
private RValue falsePart;
|
||||
|
||||
public Conditional(int position, RValue condition, RValue truePart, RValue falsePart) {
|
||||
super(position);
|
||||
|
||||
this.condition = condition;
|
||||
this.truePart = truePart;
|
||||
this.falsePart = falsePart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
if (condition.getValue() > 0.0) {
|
||||
return truePart.getValue();
|
||||
} else {
|
||||
return falsePart == null ? 0.0 : falsePart.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'I';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (falsePart == null) {
|
||||
return "if (" + condition + ") { " + truePart + " }";
|
||||
} else if (truePart instanceof Sequence || falsePart instanceof Sequence) {
|
||||
return "if (" + condition + ") { " + truePart + " } else { " + falsePart + " }";
|
||||
} else {
|
||||
return "(" + condition + ") ? (" + truePart + ") : (" + falsePart + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue optimize() throws EvaluationException {
|
||||
final RValue newCondition = condition.optimize();
|
||||
|
||||
if (newCondition instanceof Constant) {
|
||||
if (newCondition.getValue() > 0) {
|
||||
return truePart.optimize();
|
||||
} else {
|
||||
return falsePart == null ? new Constant(getPosition(), 0.0) : falsePart.optimize();
|
||||
}
|
||||
}
|
||||
|
||||
return new Conditional(getPosition(), newCondition, truePart.optimize(), falsePart == null ? null : falsePart.optimize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
condition = condition.bindVariables(expression, false);
|
||||
truePart = truePart.bindVariables(expression, false);
|
||||
if (falsePart != null) {
|
||||
falsePart = falsePart.bindVariables(expression, false);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
/**
|
||||
* A constant.
|
||||
*/
|
||||
public final class Constant extends Node {
|
||||
|
||||
private final double value;
|
||||
|
||||
public Constant(int position, double value) {
|
||||
super(position);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'c';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.ExpressionException;
|
||||
|
||||
/**
|
||||
* Thrown when there's a problem during expression evaluation.
|
||||
*/
|
||||
public class EvaluationException extends ExpressionException {
|
||||
|
||||
public EvaluationException(int position) {
|
||||
super(position, getPrefix(position));
|
||||
}
|
||||
|
||||
public EvaluationException(int position, String message, Throwable cause) {
|
||||
super(position, getPrefix(position) + ": " + message, cause);
|
||||
}
|
||||
|
||||
public EvaluationException(int position, String message) {
|
||||
super(position, getPrefix(position) + ": " + message);
|
||||
}
|
||||
|
||||
public EvaluationException(int position, Throwable cause) {
|
||||
super(position, getPrefix(position), cause);
|
||||
}
|
||||
|
||||
private static String getPrefix(int position) {
|
||||
return position < 0 ? "Evaluation error" : ("Evaluation error at " + (position + 1));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
/**
|
||||
* Represents a way to access blocks in a world. Has to accept non-rounded coordinates.
|
||||
*/
|
||||
public interface ExpressionEnvironment {
|
||||
|
||||
int getBlockType(double x, double y, double z);
|
||||
int getBlockData(double x, double y, double z);
|
||||
int getBlockTypeAbs(double x, double y, double z);
|
||||
int getBlockDataAbs(double x, double y, double z);
|
||||
int getBlockTypeRel(double x, double y, double z);
|
||||
int getBlockDataRel(double x, double y, double z);
|
||||
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
/**
|
||||
* A Java/C-style for loop.
|
||||
*/
|
||||
public class For extends Node {
|
||||
|
||||
RValue init;
|
||||
RValue condition;
|
||||
RValue increment;
|
||||
RValue body;
|
||||
|
||||
public For(int position, RValue init, RValue condition, RValue increment, RValue body) {
|
||||
super(position);
|
||||
|
||||
this.init = init;
|
||||
this.condition = condition;
|
||||
this.increment = increment;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
int iterations = 0;
|
||||
double ret = 0.0;
|
||||
|
||||
for (init.getValue(); condition.getValue() > 0; increment.getValue()) {
|
||||
if (iterations > 256) {
|
||||
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
|
||||
}
|
||||
++iterations;
|
||||
|
||||
try {
|
||||
ret = body.getValue();
|
||||
} catch (BreakException e) {
|
||||
if (e.doContinue) {
|
||||
//noinspection UnnecessaryContinue
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'F';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "for (" + init + "; " + condition + "; " + increment + ") { " + body + " }";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue optimize() throws EvaluationException {
|
||||
final RValue newCondition = condition.optimize();
|
||||
|
||||
if (newCondition instanceof Constant && newCondition.getValue() <= 0) {
|
||||
// If the condition is always false, the loop can be flattened.
|
||||
// So we run the init part and then return 0.0.
|
||||
return new Sequence(getPosition(), init, new Constant(getPosition(), 0.0)).optimize();
|
||||
}
|
||||
|
||||
//return new Sequence(getPosition(), init.optimize(), new While(getPosition(), condition, new Sequence(getPosition(), body, increment), false)).optimize();
|
||||
return new For(getPosition(), init.optimize(), newCondition, increment.optimize(), body.optimize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
init = init.bindVariables(expression, false);
|
||||
condition = condition.bindVariables(expression, false);
|
||||
increment = increment.bindVariables(expression, false);
|
||||
body = body.bindVariables(expression, false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Wrapper for a Java method and its arguments (other Nodes).
|
||||
*/
|
||||
public class Function extends Node {
|
||||
|
||||
/**
|
||||
* Add this annotation on functions that don't always return the same value
|
||||
* for the same inputs and on functions with side-effects.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Dynamic { }
|
||||
|
||||
final Method method;
|
||||
final RValue[] args;
|
||||
|
||||
Function(int position, Method method, RValue... args) {
|
||||
super(position);
|
||||
this.method = method;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final double getValue() throws EvaluationException {
|
||||
return invokeMethod(method, args);
|
||||
}
|
||||
|
||||
protected static double invokeMethod(Method method, Object[] args) throws EvaluationException {
|
||||
try {
|
||||
return (Double) method.invoke(null, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getTargetException() instanceof EvaluationException) {
|
||||
throw (EvaluationException) e.getTargetException();
|
||||
}
|
||||
throw new EvaluationException(-1, "Exception caught while evaluating expression", e.getTargetException());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new EvaluationException(-1, "Internal error while evaluating expression", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder ret = new StringBuilder(method.getName()).append('(');
|
||||
boolean first = true;
|
||||
for (Object obj : args) {
|
||||
if (!first) {
|
||||
ret.append(", ");
|
||||
}
|
||||
first = false;
|
||||
ret.append(obj);
|
||||
}
|
||||
return ret.append(')').toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'f';
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue optimize() throws EvaluationException {
|
||||
final RValue[] optimizedArgs = new RValue[args.length];
|
||||
boolean optimizable = !method.isAnnotationPresent(Dynamic.class);
|
||||
int position = getPosition();
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
final RValue optimized = optimizedArgs[i] = args[i].optimize();
|
||||
|
||||
if (!(optimized instanceof Constant)) {
|
||||
optimizable = false;
|
||||
}
|
||||
|
||||
if (optimized.getPosition() < position) {
|
||||
position = optimized.getPosition();
|
||||
}
|
||||
}
|
||||
|
||||
if (optimizable) {
|
||||
return new Constant(position, invokeMethod(method, optimizedArgs));
|
||||
} else {
|
||||
return new Function(position, method, optimizedArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
final Class<?>[] parameters = method.getParameterTypes();
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
final boolean argumentPrefersLValue = LValue.class.isAssignableFrom(parameters[i]);
|
||||
args[i] = args[i].bindVariables(expression, argumentPrefersLValue);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,503 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.runtime.Function.Dynamic;
|
||||
import com.sk89q.worldedit.math.noise.PerlinNoise;
|
||||
import com.sk89q.worldedit.math.noise.RidgedMultiFractalNoise;
|
||||
import com.sk89q.worldedit.math.noise.VoronoiNoise;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Contains all functions that can be used in expressions.
|
||||
*/
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public final class Functions {
|
||||
|
||||
private static class Overload {
|
||||
private final Method method;
|
||||
private final int mask;
|
||||
private final boolean isSetter;
|
||||
|
||||
private Overload(Method method) throws IllegalArgumentException {
|
||||
this.method = method;
|
||||
|
||||
boolean isSetter = false;
|
||||
int accum = 0;
|
||||
Class<?>[] parameters = method.getParameterTypes();
|
||||
for (Class<?> parameter : parameters) {
|
||||
if (isSetter) {
|
||||
throw new IllegalArgumentException("Method takes arguments that can't be cast to RValue.");
|
||||
}
|
||||
|
||||
if (double.class.equals(parameter)) {
|
||||
isSetter = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!RValue.class.isAssignableFrom(parameter)) {
|
||||
throw new IllegalArgumentException("Method takes arguments that can't be cast to RValue.");
|
||||
}
|
||||
|
||||
accum <<= 2;
|
||||
|
||||
if (LValue.class.isAssignableFrom(parameter)) {
|
||||
accum |= 3;
|
||||
} else {
|
||||
accum |= 1;
|
||||
}
|
||||
}
|
||||
mask = accum;
|
||||
this.isSetter = isSetter;
|
||||
}
|
||||
|
||||
public boolean matches(boolean isSetter, RValue... args) {
|
||||
if (this.isSetter != isSetter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.method.getParameterTypes().length != args.length) { // TODO: optimize
|
||||
return false;
|
||||
}
|
||||
|
||||
int accum = 0;
|
||||
for (RValue argument : args) {
|
||||
accum <<= 2;
|
||||
|
||||
if (argument instanceof LValue) {
|
||||
accum |= 3;
|
||||
} else {
|
||||
accum |= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (accum & mask) == mask;
|
||||
}
|
||||
}
|
||||
|
||||
public static Function getFunction(int position, String name, RValue... args) throws NoSuchMethodException {
|
||||
final Method getter = getMethod(name, false, args);
|
||||
try {
|
||||
Method setter = getMethod(name, true, args);
|
||||
return new LValueFunction(position, getter, setter, args);
|
||||
} catch (NoSuchMethodException e) {
|
||||
return new Function(position, getter, args);
|
||||
}
|
||||
}
|
||||
|
||||
private static Method getMethod(String name, boolean isSetter, RValue... args) throws NoSuchMethodException {
|
||||
final List<Overload> overloads = functions.get(name);
|
||||
if (overloads != null) {
|
||||
for (Overload overload : overloads) {
|
||||
if (overload.matches(isSetter, args)) {
|
||||
return overload.method;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new NoSuchMethodException(); // TODO: return null (check for side-effects first)
|
||||
}
|
||||
|
||||
private static final Map<String, List<Overload>> functions = new HashMap<String, List<Overload>>();
|
||||
static {
|
||||
for (Method method : Functions.class.getMethods()) {
|
||||
try {
|
||||
addFunction(method);
|
||||
} catch (IllegalArgumentException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void addFunction(Method method) throws IllegalArgumentException {
|
||||
final String methodName = method.getName();
|
||||
|
||||
Overload overload = new Overload(method);
|
||||
|
||||
List<Overload> overloads = functions.get(methodName);
|
||||
if (overloads == null) {
|
||||
functions.put(methodName, overloads = new ArrayList<Overload>());
|
||||
}
|
||||
|
||||
overloads.add(overload);
|
||||
}
|
||||
|
||||
|
||||
public static double sin(RValue x) throws EvaluationException {
|
||||
return Math.sin(x.getValue());
|
||||
}
|
||||
|
||||
public static double cos(RValue x) throws EvaluationException {
|
||||
return Math.cos(x.getValue());
|
||||
}
|
||||
|
||||
public static double tan(RValue x) throws EvaluationException {
|
||||
return Math.tan(x.getValue());
|
||||
}
|
||||
|
||||
|
||||
public static double asin(RValue x) throws EvaluationException {
|
||||
return Math.asin(x.getValue());
|
||||
}
|
||||
|
||||
public static double acos(RValue x) throws EvaluationException {
|
||||
return Math.acos(x.getValue());
|
||||
}
|
||||
|
||||
public static double atan(RValue x) throws EvaluationException {
|
||||
return Math.atan(x.getValue());
|
||||
}
|
||||
|
||||
public static double atan2(RValue y, RValue x) throws EvaluationException {
|
||||
return Math.atan2(y.getValue(), x.getValue());
|
||||
}
|
||||
|
||||
|
||||
public static double sinh(RValue x) throws EvaluationException {
|
||||
return Math.sinh(x.getValue());
|
||||
}
|
||||
|
||||
public static double cosh(RValue x) throws EvaluationException {
|
||||
return Math.cosh(x.getValue());
|
||||
}
|
||||
|
||||
public static double tanh(RValue x) throws EvaluationException {
|
||||
return Math.tanh(x.getValue());
|
||||
}
|
||||
|
||||
|
||||
public static double sqrt(RValue x) throws EvaluationException {
|
||||
return Math.sqrt(x.getValue());
|
||||
}
|
||||
|
||||
public static double cbrt(RValue x) throws EvaluationException {
|
||||
return Math.cbrt(x.getValue());
|
||||
}
|
||||
|
||||
|
||||
public static double abs(RValue x) throws EvaluationException {
|
||||
return Math.abs(x.getValue());
|
||||
}
|
||||
|
||||
public static double min(RValue a, RValue b) throws EvaluationException {
|
||||
return Math.min(a.getValue(), b.getValue());
|
||||
}
|
||||
|
||||
public static double min(RValue a, RValue b, RValue c) throws EvaluationException {
|
||||
return Math.min(a.getValue(), Math.min(b.getValue(), c.getValue()));
|
||||
}
|
||||
|
||||
public static double max(RValue a, RValue b) throws EvaluationException {
|
||||
return Math.max(a.getValue(), b.getValue());
|
||||
}
|
||||
|
||||
public static double max(RValue a, RValue b, RValue c) throws EvaluationException {
|
||||
return Math.max(a.getValue(), Math.max(b.getValue(), c.getValue()));
|
||||
}
|
||||
|
||||
|
||||
public static double ceil(RValue x) throws EvaluationException {
|
||||
return Math.ceil(x.getValue());
|
||||
}
|
||||
|
||||
public static double floor(RValue x) throws EvaluationException {
|
||||
return Math.floor(x.getValue());
|
||||
}
|
||||
|
||||
public static double rint(RValue x) throws EvaluationException {
|
||||
return Math.rint(x.getValue());
|
||||
}
|
||||
|
||||
public static double round(RValue x) throws EvaluationException {
|
||||
return Math.round(x.getValue());
|
||||
}
|
||||
|
||||
|
||||
public static double exp(RValue x) throws EvaluationException {
|
||||
return Math.exp(x.getValue());
|
||||
}
|
||||
|
||||
public static double ln(RValue x) throws EvaluationException {
|
||||
return Math.log(x.getValue());
|
||||
}
|
||||
|
||||
public static double log(RValue x) throws EvaluationException {
|
||||
return Math.log(x.getValue());
|
||||
}
|
||||
|
||||
public static double log10(RValue x) throws EvaluationException {
|
||||
return Math.log10(x.getValue());
|
||||
}
|
||||
|
||||
|
||||
public static double rotate(LValue x, LValue y, RValue angle) throws EvaluationException {
|
||||
final double f = angle.getValue();
|
||||
|
||||
final double cosF = Math.cos(f);
|
||||
final double sinF = Math.sin(f);
|
||||
|
||||
final double xOld = x.getValue();
|
||||
final double yOld = y.getValue();
|
||||
|
||||
x.assign(xOld * cosF - yOld * sinF);
|
||||
y.assign(xOld * sinF + yOld * cosF);
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
public static double swap(LValue x, LValue y) throws EvaluationException {
|
||||
final double tmp = x.getValue();
|
||||
|
||||
x.assign(y.getValue());
|
||||
y.assign(tmp);
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
||||
private static final Map<Integer, double[]> gmegabuf = new HashMap<Integer, double[]>();
|
||||
private final Map<Integer, double[]> megabuf = new HashMap<Integer, double[]>();
|
||||
|
||||
public Map<Integer, double[]> getMegabuf() {
|
||||
return megabuf;
|
||||
}
|
||||
|
||||
private static double[] getSubBuffer(Map<Integer, double[]> megabuf, Integer key) {
|
||||
double[] ret = megabuf.get(key);
|
||||
if (ret == null) {
|
||||
megabuf.put(key, ret = new double[1024]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static double getBufferItem(final Map<Integer, double[]> megabuf, final int index) {
|
||||
return getSubBuffer(megabuf, index & ~1023)[index & 1023];
|
||||
}
|
||||
|
||||
private static double setBufferItem(final Map<Integer, double[]> megabuf, final int index, double value) {
|
||||
return getSubBuffer(megabuf, index & ~1023)[index & 1023] = value;
|
||||
}
|
||||
|
||||
@Dynamic
|
||||
public static double gmegabuf(RValue index) throws EvaluationException {
|
||||
return getBufferItem(gmegabuf, (int) index.getValue());
|
||||
}
|
||||
|
||||
@Dynamic
|
||||
public static double gmegabuf(RValue index, double value) throws EvaluationException {
|
||||
return setBufferItem(gmegabuf, (int) index.getValue(), value);
|
||||
}
|
||||
|
||||
@Dynamic
|
||||
public static double megabuf(RValue index) throws EvaluationException {
|
||||
return getBufferItem(Expression.getInstance().getFunctions().megabuf, (int) index.getValue());
|
||||
}
|
||||
|
||||
@Dynamic
|
||||
public static double megabuf(RValue index, double value) throws EvaluationException {
|
||||
return setBufferItem(Expression.getInstance().getFunctions().megabuf, (int) index.getValue(), value);
|
||||
}
|
||||
|
||||
@Dynamic
|
||||
public static double closest(RValue x, RValue y, RValue z, RValue index, RValue count, RValue stride) throws EvaluationException {
|
||||
return findClosest(
|
||||
Expression.getInstance().getFunctions().megabuf,
|
||||
x.getValue(),
|
||||
y.getValue(),
|
||||
z.getValue(),
|
||||
(int) index.getValue(),
|
||||
(int) count.getValue(),
|
||||
(int) stride.getValue()
|
||||
);
|
||||
}
|
||||
|
||||
@Dynamic
|
||||
public static double gclosest(RValue x, RValue y, RValue z, RValue index, RValue count, RValue stride) throws EvaluationException {
|
||||
return findClosest(
|
||||
gmegabuf,
|
||||
x.getValue(),
|
||||
y.getValue(),
|
||||
z.getValue(),
|
||||
(int) index.getValue(),
|
||||
(int) count.getValue(),
|
||||
(int) stride.getValue()
|
||||
);
|
||||
}
|
||||
|
||||
private static double findClosest(Map<Integer, double[]> megabuf, double x, double y, double z, int index, int count, int stride) {
|
||||
int closestIndex = -1;
|
||||
double minDistanceSquared = Double.MAX_VALUE;
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
double currentX = getBufferItem(megabuf, index+0) - x;
|
||||
double currentY = getBufferItem(megabuf, index+1) - y;
|
||||
double currentZ = getBufferItem(megabuf, index+2) - z;
|
||||
|
||||
double currentDistanceSquared = currentX*currentX + currentY*currentY + currentZ*currentZ;
|
||||
|
||||
if (currentDistanceSquared < minDistanceSquared) {
|
||||
minDistanceSquared = currentDistanceSquared;
|
||||
closestIndex = index;
|
||||
}
|
||||
|
||||
index += stride;
|
||||
}
|
||||
|
||||
return closestIndex;
|
||||
}
|
||||
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
@Dynamic
|
||||
public static double random() {
|
||||
return random.nextDouble();
|
||||
}
|
||||
|
||||
@Dynamic
|
||||
public static double randint(RValue max) throws EvaluationException {
|
||||
return random.nextInt((int) Math.floor(max.getValue()));
|
||||
}
|
||||
|
||||
private static final ThreadLocal<PerlinNoise> localPerlin = new ThreadLocal<PerlinNoise>() {
|
||||
@Override
|
||||
protected PerlinNoise initialValue() {
|
||||
return new PerlinNoise();
|
||||
}
|
||||
};
|
||||
|
||||
public static double perlin(RValue seed, RValue x, RValue y, RValue z, RValue frequency, RValue octaves, RValue persistence) throws EvaluationException {
|
||||
PerlinNoise perlin = localPerlin.get();
|
||||
try {
|
||||
perlin.setSeed((int) seed.getValue());
|
||||
perlin.setFrequency(frequency.getValue());
|
||||
perlin.setOctaveCount((int) octaves.getValue());
|
||||
perlin.setPersistence(persistence.getValue());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new EvaluationException(0, "Perlin noise error: " + e.getMessage());
|
||||
}
|
||||
return perlin.noise(new Vector(x.getValue(), y.getValue(), z.getValue()));
|
||||
}
|
||||
|
||||
private static final ThreadLocal<VoronoiNoise> localVoronoi = new ThreadLocal<VoronoiNoise>() {
|
||||
@Override
|
||||
protected VoronoiNoise initialValue() {
|
||||
return new VoronoiNoise();
|
||||
}
|
||||
};
|
||||
|
||||
public static double voronoi(RValue seed, RValue x, RValue y, RValue z, RValue frequency) throws EvaluationException {
|
||||
VoronoiNoise voronoi = localVoronoi.get();
|
||||
try {
|
||||
voronoi.setSeed((int) seed.getValue());
|
||||
voronoi.setFrequency(frequency.getValue());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new EvaluationException(0, "Voronoi error: " + e.getMessage());
|
||||
}
|
||||
return voronoi.noise(new Vector(x.getValue(), y.getValue(), z.getValue()));
|
||||
}
|
||||
|
||||
private static final ThreadLocal<RidgedMultiFractalNoise> localRidgedMulti = new ThreadLocal<RidgedMultiFractalNoise>() {
|
||||
@Override
|
||||
protected RidgedMultiFractalNoise initialValue() {
|
||||
return new RidgedMultiFractalNoise();
|
||||
}
|
||||
};
|
||||
|
||||
public static double ridgedmulti(RValue seed, RValue x, RValue y, RValue z, RValue frequency, RValue octaves) throws EvaluationException {
|
||||
RidgedMultiFractalNoise ridgedMulti = localRidgedMulti.get();
|
||||
try {
|
||||
ridgedMulti.setSeed((int) seed.getValue());
|
||||
ridgedMulti.setFrequency(frequency.getValue());
|
||||
ridgedMulti.setOctaveCount((int) octaves.getValue());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new EvaluationException(0, "Ridged multi error: " + e.getMessage());
|
||||
}
|
||||
return ridgedMulti.noise(new Vector(x.getValue(), y.getValue(), z.getValue()));
|
||||
}
|
||||
|
||||
private static double queryInternal(RValue type, RValue data, double typeId, double dataValue) throws EvaluationException {
|
||||
// Compare to input values and determine return value
|
||||
final double ret = (typeId == type.getValue() && dataValue == data.getValue()) ? 1.0 : 0.0;
|
||||
|
||||
if (type instanceof LValue) {
|
||||
((LValue) type).assign(typeId);
|
||||
}
|
||||
|
||||
if (data instanceof LValue) {
|
||||
((LValue) data).assign(dataValue);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Dynamic
|
||||
public static double query(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException {
|
||||
final double xp = x.getValue();
|
||||
final double yp = y.getValue();
|
||||
final double zp = z.getValue();
|
||||
|
||||
final ExpressionEnvironment environment = Expression.getInstance().getEnvironment();
|
||||
|
||||
// Read values from world
|
||||
final double typeId = environment.getBlockType(xp, yp, zp);
|
||||
final double dataValue = environment.getBlockData(xp, yp, zp);
|
||||
|
||||
return queryInternal(type, data, typeId, dataValue);
|
||||
}
|
||||
|
||||
@Dynamic
|
||||
public static double queryAbs(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException {
|
||||
final double xp = x.getValue();
|
||||
final double yp = y.getValue();
|
||||
final double zp = z.getValue();
|
||||
|
||||
final ExpressionEnvironment environment = Expression.getInstance().getEnvironment();
|
||||
|
||||
// Read values from world
|
||||
final double typeId = environment.getBlockTypeAbs(xp, yp, zp);
|
||||
final double dataValue = environment.getBlockDataAbs(xp, yp, zp);
|
||||
|
||||
return queryInternal(type, data, typeId, dataValue);
|
||||
}
|
||||
|
||||
@Dynamic
|
||||
public static double queryRel(RValue x, RValue y, RValue z, RValue type, RValue data) throws EvaluationException {
|
||||
final double xp = x.getValue();
|
||||
final double yp = y.getValue();
|
||||
final double zp = z.getValue();
|
||||
|
||||
final ExpressionEnvironment environment = Expression.getInstance().getEnvironment();
|
||||
|
||||
// Read values from world
|
||||
final double typeId = environment.getBlockTypeRel(xp, yp, zp);
|
||||
final double dataValue = environment.getBlockDataRel(xp, yp, zp);
|
||||
|
||||
return queryInternal(type, data, typeId, dataValue);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
/**
|
||||
* A value that can be used on the left side of an assignment.
|
||||
*/
|
||||
public interface LValue extends RValue {
|
||||
|
||||
public double assign(double value) throws EvaluationException;
|
||||
|
||||
@Override
|
||||
public LValue optimize() throws EvaluationException;
|
||||
|
||||
@Override
|
||||
public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException;
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Wrapper for a pair of Java methods and their arguments (other Nodes),
|
||||
* forming an LValue.
|
||||
*/
|
||||
public class LValueFunction extends Function implements LValue {
|
||||
|
||||
private final Object[] setterArgs;
|
||||
private final Method setter;
|
||||
|
||||
LValueFunction(int position, Method getter, Method setter, RValue... args) {
|
||||
super(position, getter, args);
|
||||
assert (getter.isAnnotationPresent(Dynamic.class));
|
||||
|
||||
setterArgs = new Object[args.length + 1];
|
||||
System.arraycopy(args, 0, setterArgs, 0, args.length);
|
||||
this.setter = setter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'l';
|
||||
}
|
||||
|
||||
@Override
|
||||
public double assign(double value) throws EvaluationException {
|
||||
setterArgs[setterArgs.length - 1] = value;
|
||||
return invokeMethod(setter, setterArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LValue optimize() throws EvaluationException {
|
||||
final RValue optimized = super.optimize();
|
||||
if (optimized == this) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (optimized instanceof Function) {
|
||||
return new LValueFunction(optimized.getPosition(), method, setter, ((Function) optimized).args);
|
||||
}
|
||||
|
||||
return (LValue) optimized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
super.bindVariables(expression, preferLValue);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
/**
|
||||
* A node in the execution tree of an expression.
|
||||
*/
|
||||
public abstract class Node implements RValue {
|
||||
|
||||
private final int position;
|
||||
|
||||
public Node(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract String toString();
|
||||
|
||||
@Override
|
||||
public RValue optimize() throws EvaluationException {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
/**
|
||||
* Contains all unary and binary operators.
|
||||
*/
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public final class Operators {
|
||||
|
||||
private Operators() {
|
||||
}
|
||||
|
||||
public static Function getOperator(int position, String name, RValue lhs, RValue rhs) throws NoSuchMethodException {
|
||||
if (lhs instanceof LValue) {
|
||||
try {
|
||||
return new Function(position, Operators.class.getMethod(name, LValue.class, RValue.class), lhs, rhs);
|
||||
} catch (NoSuchMethodException ignored) { }
|
||||
}
|
||||
return new Function(position, Operators.class.getMethod(name, RValue.class, RValue.class), lhs, rhs);
|
||||
}
|
||||
|
||||
public static Function getOperator(int position, String name, RValue argument) throws NoSuchMethodException {
|
||||
if (argument instanceof LValue) {
|
||||
try {
|
||||
return new Function(position, Operators.class.getMethod(name, LValue.class), argument);
|
||||
} catch (NoSuchMethodException ignored) { }
|
||||
}
|
||||
return new Function(position, Operators.class.getMethod(name, RValue.class), argument);
|
||||
}
|
||||
|
||||
|
||||
public static double add(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() + rhs.getValue();
|
||||
}
|
||||
|
||||
public static double sub(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() - rhs.getValue();
|
||||
}
|
||||
|
||||
public static double mul(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() * rhs.getValue();
|
||||
}
|
||||
|
||||
public static double div(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() / rhs.getValue();
|
||||
}
|
||||
|
||||
public static double mod(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() % rhs.getValue();
|
||||
}
|
||||
|
||||
public static double pow(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return Math.pow(lhs.getValue(), rhs.getValue());
|
||||
}
|
||||
|
||||
|
||||
public static double neg(RValue x) throws EvaluationException {
|
||||
return -x.getValue();
|
||||
}
|
||||
|
||||
public static double not(RValue x) throws EvaluationException {
|
||||
return x.getValue() > 0.0 ? 0.0 : 1.0;
|
||||
}
|
||||
|
||||
public static double inv(RValue x) throws EvaluationException {
|
||||
return ~(long) x.getValue();
|
||||
}
|
||||
|
||||
|
||||
public static double lth(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() < rhs.getValue() ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
public static double gth(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() > rhs.getValue() ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
public static double leq(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() <= rhs.getValue() ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
public static double geq(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() >= rhs.getValue() ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
|
||||
public static double equ(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() == rhs.getValue() ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
public static double neq(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() != rhs.getValue() ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
public static double near(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return almostEqual2sComplement(lhs.getValue(), rhs.getValue(), 450359963L) ? 1.0 : 0.0;
|
||||
//return Math.abs(lhs.invoke() - rhs.invoke()) < 1e-7 ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
|
||||
public static double or(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() > 0.0 || rhs.getValue() > 0.0 ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
public static double and(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.getValue() > 0.0 && rhs.getValue() > 0.0 ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
|
||||
public static double shl(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return (long) lhs.getValue() << (long) rhs.getValue();
|
||||
}
|
||||
|
||||
public static double shr(RValue lhs, RValue rhs) throws EvaluationException {
|
||||
return (long) lhs.getValue() >> (long) rhs.getValue();
|
||||
}
|
||||
|
||||
|
||||
public static double ass(LValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.assign(rhs.getValue());
|
||||
}
|
||||
|
||||
public static double aadd(LValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.assign(lhs.getValue() + rhs.getValue());
|
||||
}
|
||||
|
||||
public static double asub(LValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.assign(lhs.getValue() - rhs.getValue());
|
||||
}
|
||||
|
||||
public static double amul(LValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.assign(lhs.getValue() * rhs.getValue());
|
||||
}
|
||||
|
||||
public static double adiv(LValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.assign(lhs.getValue() / rhs.getValue());
|
||||
}
|
||||
|
||||
public static double amod(LValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.assign(lhs.getValue() % rhs.getValue());
|
||||
}
|
||||
|
||||
public static double aexp(LValue lhs, RValue rhs) throws EvaluationException {
|
||||
return lhs.assign(Math.pow(lhs.getValue(), rhs.getValue()));
|
||||
}
|
||||
|
||||
|
||||
public static double inc(LValue x) throws EvaluationException {
|
||||
return x.assign(x.getValue() + 1);
|
||||
}
|
||||
|
||||
public static double dec(LValue x) throws EvaluationException {
|
||||
return x.assign(x.getValue() - 1);
|
||||
}
|
||||
|
||||
public static double postinc(LValue x) throws EvaluationException {
|
||||
final double oldValue = x.getValue();
|
||||
x.assign(oldValue + 1);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public static double postdec(LValue x) throws EvaluationException {
|
||||
final double oldValue = x.getValue();
|
||||
x.assign(oldValue - 1);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
|
||||
private static final double[] factorials = new double[171];
|
||||
static {
|
||||
double accum = 1;
|
||||
factorials[0] = 1;
|
||||
for (int i = 1; i < factorials.length; ++i) {
|
||||
factorials[i] = accum *= i;
|
||||
}
|
||||
}
|
||||
|
||||
public static double fac(RValue x) throws EvaluationException {
|
||||
final int n = (int) x.getValue();
|
||||
|
||||
if (n < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n >= factorials.length) {
|
||||
return Double.POSITIVE_INFINITY;
|
||||
}
|
||||
|
||||
return factorials[n];
|
||||
}
|
||||
|
||||
// Usable AlmostEqual function, based on http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
|
||||
private static boolean almostEqual2sComplement(double a, double b, long maxUlps) {
|
||||
// Make sure maxUlps is non-negative and small enough that the
|
||||
// default NAN won't compare as equal to anything.
|
||||
//assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024); // this is for floats, not doubles
|
||||
|
||||
long aLong = Double.doubleToRawLongBits(a);
|
||||
// Make aLong lexicographically ordered as a twos-complement long
|
||||
if (aLong < 0) aLong = 0x8000000000000000L - aLong;
|
||||
|
||||
long bLong = Double.doubleToRawLongBits(b);
|
||||
// Make bLong lexicographically ordered as a twos-complement long
|
||||
if (bLong < 0) bLong = 0x8000000000000000L - bLong;
|
||||
|
||||
final long longDiff = Math.abs(aLong - bLong);
|
||||
return longDiff <= maxUlps;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.Identifiable;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
/**
|
||||
* A value that can be used on the right side of an assignment.
|
||||
*/
|
||||
public interface RValue extends Identifiable {
|
||||
|
||||
public double getValue() throws EvaluationException;
|
||||
|
||||
public RValue optimize() throws EvaluationException;
|
||||
|
||||
public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException;
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
/**
|
||||
* A return statement.
|
||||
*/
|
||||
public class Return extends Node {
|
||||
|
||||
RValue value;
|
||||
|
||||
public Return(int position, RValue value) {
|
||||
super(position);
|
||||
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
throw new ReturnException(value.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'r';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "return " + value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
value = value.bindVariables(expression, false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
/**
|
||||
* Thrown when a return statement is encountered.
|
||||
* {@link com.sk89q.worldedit.internal.expression.Expression#evaluate}
|
||||
* catches this exception and returns the enclosed value.
|
||||
*/
|
||||
public class ReturnException extends EvaluationException {
|
||||
|
||||
final double value;
|
||||
|
||||
public ReturnException(double value) {
|
||||
super(-1);
|
||||
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A sequence of operations, usually separated by semicolons in the
|
||||
* input stream.
|
||||
*/
|
||||
public class Sequence extends Node {
|
||||
|
||||
final RValue[] sequence;
|
||||
|
||||
public Sequence(int position, RValue... sequence) {
|
||||
super(position);
|
||||
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 's';
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
double ret = 0;
|
||||
for (RValue invokable : sequence) {
|
||||
ret = invokable.getValue();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("seq(");
|
||||
boolean first = true;
|
||||
for (RValue invokable : sequence) {
|
||||
if (!first) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(invokable);
|
||||
first = false;
|
||||
}
|
||||
|
||||
return sb.append(')').toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue optimize() throws EvaluationException {
|
||||
final List<RValue> newSequence = new ArrayList<RValue>();
|
||||
|
||||
RValue droppedLast = null;
|
||||
for (RValue invokable : sequence) {
|
||||
droppedLast = null;
|
||||
invokable = invokable.optimize();
|
||||
if (invokable instanceof Sequence) {
|
||||
Collections.addAll(newSequence, ((Sequence) invokable).sequence);
|
||||
} else if (invokable instanceof Constant) {
|
||||
droppedLast = invokable;
|
||||
} else {
|
||||
newSequence.add(invokable);
|
||||
}
|
||||
}
|
||||
|
||||
if (droppedLast != null) {
|
||||
newSequence.add(droppedLast);
|
||||
}
|
||||
|
||||
if (newSequence.size() == 1) {
|
||||
return newSequence.get(0);
|
||||
}
|
||||
|
||||
return new Sequence(getPosition(), newSequence.toArray(new RValue[newSequence.size()]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
for (int i = 0; i < sequence.length; ++i) {
|
||||
sequence[i] = sequence[i].bindVariables(expression, false);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
/**
|
||||
* A simple-style for loop.
|
||||
*/
|
||||
public class SimpleFor extends Node {
|
||||
|
||||
LValue counter;
|
||||
RValue first;
|
||||
RValue last;
|
||||
RValue body;
|
||||
|
||||
public SimpleFor(int position, LValue counter, RValue first, RValue last, RValue body) {
|
||||
super(position);
|
||||
|
||||
this.counter = counter;
|
||||
this.first = first;
|
||||
this.last = last;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
int iterations = 0;
|
||||
double ret = 0.0;
|
||||
|
||||
double firstValue = first.getValue();
|
||||
double lastValue = last.getValue();
|
||||
|
||||
for (double i = firstValue; i <= lastValue; ++i) {
|
||||
if (iterations > 256) {
|
||||
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
|
||||
}
|
||||
++iterations;
|
||||
|
||||
try {
|
||||
counter.assign(i);
|
||||
ret = body.getValue();
|
||||
} catch (BreakException e) {
|
||||
if (e.doContinue) {
|
||||
//noinspection UnnecessaryContinue
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'S';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "for (" + counter + " = " + first + ", " + last + ") { " + body + " }";
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue optimize() throws EvaluationException {
|
||||
// TODO: unroll small loops into Sequences
|
||||
|
||||
return new SimpleFor(getPosition(), counter.optimize(), first.optimize(), last.optimize(), body.optimize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
counter = counter.bindVariables(expression, true);
|
||||
first = first.bindVariables(expression, false);
|
||||
last = last.bindVariables(expression, false);
|
||||
body = body.bindVariables(expression, false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* A switch/case construct.
|
||||
*/
|
||||
public class Switch extends Node implements RValue {
|
||||
|
||||
private RValue parameter;
|
||||
private final Map<Double, Integer> valueMap;
|
||||
private final RValue[] caseStatements;
|
||||
private RValue defaultCase;
|
||||
|
||||
public Switch(int position, RValue parameter, List<Double> values, List<RValue> caseStatements, RValue defaultCase) {
|
||||
this(position, parameter, invertList(values), caseStatements, defaultCase);
|
||||
|
||||
}
|
||||
|
||||
private static Map<Double, Integer> invertList(List<Double> values) {
|
||||
Map<Double, Integer> valueMap = new HashMap<Double, Integer>();
|
||||
for (int i = 0; i < values.size(); ++i) {
|
||||
valueMap.put(values.get(i), i);
|
||||
}
|
||||
return valueMap;
|
||||
}
|
||||
|
||||
private Switch(int position, RValue parameter, Map<Double, Integer> valueMap, List<RValue> caseStatements, RValue defaultCase) {
|
||||
super(position);
|
||||
|
||||
this.parameter = parameter;
|
||||
this.valueMap = valueMap;
|
||||
this.caseStatements = caseStatements.toArray(new RValue[caseStatements.size()]);
|
||||
this.defaultCase = defaultCase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'W';
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
final double parameter = this.parameter.getValue();
|
||||
|
||||
try {
|
||||
double ret = 0.0;
|
||||
|
||||
final Integer index = valueMap.get(parameter);
|
||||
if (index != null) {
|
||||
for (int i = index; i < caseStatements.length; ++i) {
|
||||
ret = caseStatements[i].getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return defaultCase == null ? ret : defaultCase.getValue();
|
||||
} catch (BreakException e) {
|
||||
if (e.doContinue) throw e;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("switch (");
|
||||
sb.append(parameter);
|
||||
sb.append(") { ");
|
||||
|
||||
for (int i = 0; i < caseStatements.length; ++i) {
|
||||
RValue caseStatement = caseStatements[i];
|
||||
sb.append("case ");
|
||||
for (Entry<Double, Integer> entry : valueMap.entrySet()) {
|
||||
if (entry.getValue() == i) {
|
||||
sb.append(entry.getKey());
|
||||
break;
|
||||
}
|
||||
}
|
||||
sb.append(": ");
|
||||
sb.append(caseStatement);
|
||||
sb.append(' ');
|
||||
}
|
||||
|
||||
if (defaultCase != null) {
|
||||
sb.append("default: ");
|
||||
sb.append(defaultCase);
|
||||
sb.append(' ');
|
||||
}
|
||||
|
||||
sb.append("}");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue optimize() throws EvaluationException {
|
||||
final RValue optimizedParameter = parameter.optimize();
|
||||
final List<RValue> newSequence = new ArrayList<RValue>();
|
||||
|
||||
if (optimizedParameter instanceof Constant) {
|
||||
final double parameter = optimizedParameter.getValue();
|
||||
|
||||
final Integer index = valueMap.get(parameter);
|
||||
if (index == null) {
|
||||
return defaultCase == null ? new Constant(getPosition(), 0.0) : defaultCase.optimize();
|
||||
}
|
||||
|
||||
boolean breakDetected = false;
|
||||
for (int i = index; i < caseStatements.length && !breakDetected; ++i) {
|
||||
final RValue invokable = caseStatements[i].optimize();
|
||||
|
||||
if (invokable instanceof Sequence) {
|
||||
for (RValue subInvokable : ((Sequence) invokable).sequence) {
|
||||
if (subInvokable instanceof Break) {
|
||||
breakDetected = true;
|
||||
break;
|
||||
}
|
||||
|
||||
newSequence.add(subInvokable);
|
||||
}
|
||||
} else {
|
||||
newSequence.add(invokable);
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultCase != null && !breakDetected) {
|
||||
final RValue invokable = defaultCase.optimize();
|
||||
|
||||
if (invokable instanceof Sequence) {
|
||||
Collections.addAll(newSequence, ((Sequence) invokable).sequence);
|
||||
} else {
|
||||
newSequence.add(invokable);
|
||||
}
|
||||
}
|
||||
|
||||
return new Switch(getPosition(), optimizedParameter, Collections.singletonMap(parameter, 0), newSequence, null);
|
||||
}
|
||||
|
||||
final Map<Double, Integer> newValueMap = new HashMap<Double, Integer>();
|
||||
|
||||
Map<Integer, Double> backMap = new HashMap<Integer, Double>();
|
||||
for (Entry<Double, Integer> entry : valueMap.entrySet()) {
|
||||
backMap.put(entry.getValue(), entry.getKey());
|
||||
}
|
||||
|
||||
for (int i = 0; i < caseStatements.length; ++i) {
|
||||
final RValue invokable = caseStatements[i].optimize();
|
||||
|
||||
final Double caseValue = backMap.get(i);
|
||||
if (caseValue != null) {
|
||||
newValueMap.put(caseValue, newSequence.size());
|
||||
}
|
||||
|
||||
if (invokable instanceof Sequence) {
|
||||
Collections.addAll(newSequence, ((Sequence) invokable).sequence);
|
||||
} else {
|
||||
newSequence.add(invokable);
|
||||
}
|
||||
}
|
||||
|
||||
return new Switch(getPosition(), optimizedParameter, newValueMap, newSequence, defaultCase.optimize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
parameter = parameter.bindVariables(expression, false);
|
||||
|
||||
for (int i = 0; i < caseStatements.length; ++i) {
|
||||
caseStatements[i] = caseStatements[i].bindVariables(expression, false);
|
||||
}
|
||||
|
||||
defaultCase = defaultCase.bindVariables(expression, false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
/**
|
||||
* A variable.
|
||||
*/
|
||||
public final class Variable extends Node implements LValue {
|
||||
|
||||
public double value;
|
||||
|
||||
public Variable(double value) {
|
||||
super(-1);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "var";
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'v';
|
||||
}
|
||||
|
||||
@Override
|
||||
public double assign(double value) {
|
||||
return this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LValue optimize() throws EvaluationException {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.expression.runtime;
|
||||
|
||||
import com.sk89q.worldedit.internal.expression.Expression;
|
||||
import com.sk89q.worldedit.internal.expression.parser.ParserException;
|
||||
|
||||
/**
|
||||
* A while loop.
|
||||
*/
|
||||
public class While extends Node {
|
||||
|
||||
RValue condition;
|
||||
RValue body;
|
||||
boolean footChecked;
|
||||
|
||||
public While(int position, RValue condition, RValue body, boolean footChecked) {
|
||||
super(position);
|
||||
|
||||
this.condition = condition;
|
||||
this.body = body;
|
||||
this.footChecked = footChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getValue() throws EvaluationException {
|
||||
int iterations = 0;
|
||||
double ret = 0.0;
|
||||
|
||||
if (footChecked) {
|
||||
do {
|
||||
if (iterations > 256) {
|
||||
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
|
||||
}
|
||||
++iterations;
|
||||
|
||||
try {
|
||||
ret = body.getValue();
|
||||
} catch (BreakException e) {
|
||||
if (e.doContinue) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (condition.getValue() > 0.0);
|
||||
} else {
|
||||
while (condition.getValue() > 0.0) {
|
||||
if (iterations > 256) {
|
||||
throw new EvaluationException(getPosition(), "Loop exceeded 256 iterations.");
|
||||
}
|
||||
++iterations;
|
||||
|
||||
try {
|
||||
ret = body.getValue();
|
||||
} catch (BreakException e) {
|
||||
if (e.doContinue) {
|
||||
//noinspection UnnecessaryContinue
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char id() {
|
||||
return 'w';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (footChecked) {
|
||||
return "do { " + body + " } while (" + condition + ")";
|
||||
} else {
|
||||
return "while (" + condition + ") { " + body + " }";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue optimize() throws EvaluationException {
|
||||
final RValue newCondition = condition.optimize();
|
||||
|
||||
if (newCondition instanceof Constant && newCondition.getValue() <= 0) {
|
||||
// If the condition is always false, the loop can be flattened.
|
||||
if (footChecked) {
|
||||
// Foot-checked loops run at least once.
|
||||
return body.optimize();
|
||||
} else {
|
||||
// Loops that never run always return 0.0.
|
||||
return new Constant(getPosition(), 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
return new While(getPosition(), newCondition, body.optimize(), footChecked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RValue bindVariables(Expression expression, boolean preferLValue) throws ParserException {
|
||||
condition = condition.bindVariables(expression, false);
|
||||
body = body.bindVariables(expression, false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.helper;
|
||||
|
||||
import com.sk89q.worldedit.util.Direction;
|
||||
|
||||
/**
|
||||
* Utility methods for working with directions in Minecraft.
|
||||
*/
|
||||
public final class MCDirections {
|
||||
|
||||
private MCDirections() {
|
||||
}
|
||||
|
||||
public static Direction fromHanging(int i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return Direction.SOUTH;
|
||||
case 1:
|
||||
return Direction.WEST;
|
||||
case 2:
|
||||
return Direction.NORTH;
|
||||
case 3:
|
||||
return Direction.EAST;
|
||||
default:
|
||||
return Direction.NORTH;
|
||||
}
|
||||
}
|
||||
|
||||
public static int toHanging(Direction direction) {
|
||||
switch (direction) {
|
||||
case SOUTH:
|
||||
return 0;
|
||||
case WEST:
|
||||
return 1;
|
||||
case NORTH:
|
||||
return 2;
|
||||
case EAST:
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static int fromLegacyHanging(byte i) {
|
||||
switch (i) {
|
||||
case 0: return 2;
|
||||
case 1: return 1;
|
||||
case 2: return 0;
|
||||
default: return 3;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte toLegacyHanging(int i) {
|
||||
switch (i) {
|
||||
case 0: return (byte) 2;
|
||||
case 1: return (byte) 1;
|
||||
case 2: return (byte) 0;
|
||||
default: return (byte) 3;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.registry;
|
||||
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
import com.sk89q.worldedit.extension.input.NoMatchException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* An abstract implementation of a factory for internal usage.
|
||||
*
|
||||
* @param <E> the element that the factory returns
|
||||
*/
|
||||
@SuppressWarnings("ProtectedField")
|
||||
public abstract class AbstractFactory<E> {
|
||||
|
||||
protected final WorldEdit worldEdit;
|
||||
protected final List<InputParser<E>> parsers = new ArrayList<InputParser<E>>();
|
||||
|
||||
/**
|
||||
* Create a new factory.
|
||||
*
|
||||
* @param worldEdit the WorldEdit instance
|
||||
*/
|
||||
protected AbstractFactory(WorldEdit worldEdit) {
|
||||
checkNotNull(worldEdit);
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
public E parseFromInput(String input, ParserContext context) throws InputParseException {
|
||||
E match;
|
||||
|
||||
for (InputParser<E> parser : parsers) {
|
||||
match = parser.parseFromInput(input, context);
|
||||
|
||||
if (match != null) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
|
||||
throw new NoMatchException("No match for '" + input + "'");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.registry;
|
||||
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
|
||||
/**
|
||||
* Input parser interface for {@link AbstractFactory}.
|
||||
*
|
||||
* @param <E> the element
|
||||
*/
|
||||
@SuppressWarnings("ProtectedField")
|
||||
public abstract class InputParser<E> {
|
||||
|
||||
protected final WorldEdit worldEdit;
|
||||
|
||||
protected InputParser(WorldEdit worldEdit) {
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
public abstract E parseFromInput(String input, ParserContext context) throws InputParseException;
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.util;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
/**
|
||||
* Abstract class for adapters.
|
||||
*
|
||||
* @param <E> class of adapted objects
|
||||
*/
|
||||
public abstract class AbstractAdapter<E> {
|
||||
|
||||
private final E object;
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param object the object to adapt
|
||||
*/
|
||||
public AbstractAdapter(E object) {
|
||||
checkNotNull(object);
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object.
|
||||
*
|
||||
* @return the object
|
||||
*/
|
||||
public E getHandle() {
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,207 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.internal.util;
|
||||
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||
import com.sk89q.minecraft.util.commands.NestedCommand;
|
||||
import com.sk89q.worldedit.command.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("UseOfSystemOutOrSystemErr")
|
||||
public final class DocumentationPrinter {
|
||||
|
||||
private DocumentationPrinter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates documentation.
|
||||
*
|
||||
* @param args arguments
|
||||
* @throws IOException thrown on I/O error
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
File commandsDir = new File(args[0]);
|
||||
|
||||
List<Class<?>> commandClasses = getCommandClasses(commandsDir);
|
||||
|
||||
System.out.println("Writing permissions wiki table...");
|
||||
writePermissionsWikiTable(commandClasses);
|
||||
System.out.println("Writing Bukkit plugin.yml...");
|
||||
writeBukkitYAML();
|
||||
|
||||
System.out.println("Done!");
|
||||
}
|
||||
|
||||
private static List<Class<?>> getCommandClasses(File dir) {
|
||||
List<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
|
||||
classes.add(BiomeCommands.class);
|
||||
classes.add(ChunkCommands.class);
|
||||
classes.add(ClipboardCommands.class);
|
||||
classes.add(GeneralCommands.class);
|
||||
classes.add(GenerationCommands.class);
|
||||
classes.add(HistoryCommands.class);
|
||||
classes.add(NavigationCommands.class);
|
||||
classes.add(RegionCommands.class);
|
||||
classes.add(ScriptingCommands.class);
|
||||
classes.add(SelectionCommands.class);
|
||||
classes.add(SnapshotUtilCommands.class);
|
||||
classes.add(ToolUtilCommands.class);
|
||||
classes.add(ToolCommands.class);
|
||||
classes.add(UtilityCommands.class);
|
||||
|
||||
/*for (File f : dir.listFiles()) {
|
||||
if (!f.getName().matches("^.*\\.java$")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String className = "com.sk89q.worldedit.commands."
|
||||
+ f.getName().substring(0, f.getName().lastIndexOf("."));
|
||||
|
||||
Class<?> cls;
|
||||
try {
|
||||
cls = Class.forName(className, true,
|
||||
Thread.currentThread().getContextClassLoader());
|
||||
} catch (ClassNotFoundException e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
classes.add(cls);
|
||||
}*/
|
||||
|
||||
return classes;
|
||||
}
|
||||
|
||||
private static void writePermissionsWikiTable(List<Class<?>> commandClasses)
|
||||
throws IOException {
|
||||
FileOutputStream stream = null;
|
||||
try {
|
||||
stream = new FileOutputStream("wiki_permissions.txt");
|
||||
PrintStream print = new PrintStream(stream);
|
||||
writePermissionsWikiTable(print, commandClasses, "/");
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void writePermissionsWikiTable(PrintStream stream,
|
||||
List<Class<?>> commandClasses, String prefix) {
|
||||
|
||||
for (Class<?> cls : commandClasses) {
|
||||
for (Method method : cls.getMethods()) {
|
||||
if (!method.isAnnotationPresent(Command.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Command cmd = method.getAnnotation(Command.class);
|
||||
|
||||
stream.println("|-");
|
||||
stream.print("| " + prefix + cmd.aliases()[0]);
|
||||
stream.print(" || ");
|
||||
|
||||
if (method.isAnnotationPresent(CommandPermissions.class)) {
|
||||
CommandPermissions perms =
|
||||
method.getAnnotation(CommandPermissions.class);
|
||||
|
||||
String[] permKeys = perms.value();
|
||||
for (int i = 0; i < permKeys.length; ++i) {
|
||||
if (i > 0) {
|
||||
stream.print(", ");
|
||||
}
|
||||
stream.print(permKeys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
stream.print(" || ");
|
||||
|
||||
boolean firstAlias = true;
|
||||
if (cmd.aliases().length != 0) {
|
||||
for (String alias : cmd.aliases()) {
|
||||
if (!firstAlias) stream.print("<br />");
|
||||
stream.print(prefix + alias);
|
||||
firstAlias = false;
|
||||
}
|
||||
}
|
||||
|
||||
stream.print(" || ");
|
||||
|
||||
if (cmd.flags() != null && !cmd.flags().equals("")) {
|
||||
stream.print(cmd.flags());
|
||||
}
|
||||
|
||||
stream.print(" || ");
|
||||
|
||||
if (cmd.desc() != null && !cmd.desc().equals("")) {
|
||||
stream.print(cmd.desc());
|
||||
}
|
||||
|
||||
stream.println();
|
||||
|
||||
if (method.isAnnotationPresent(NestedCommand.class)) {
|
||||
NestedCommand nested =
|
||||
method.getAnnotation(NestedCommand.class);
|
||||
|
||||
Class<?>[] nestedClasses = nested.value();
|
||||
writePermissionsWikiTable(stream,
|
||||
Arrays.asList(nestedClasses),
|
||||
prefix + cmd.aliases()[0] + " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeBukkitYAML()
|
||||
throws IOException {
|
||||
FileOutputStream stream = null;
|
||||
try {
|
||||
stream = new FileOutputStream("plugin.yml");
|
||||
PrintStream print = new PrintStream(stream);
|
||||
writeBukkitYAML(print);
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeBukkitYAML(PrintStream stream) {
|
||||
stream.println("name: WorldEdit");
|
||||
stream.println("main: com.sk89q.worldedit.bukkit.WorldEditPlugin");
|
||||
stream.println("version: ${project.version}");
|
||||
stream.println("softdepend: [Spout] #hack to fix trove errors");
|
||||
|
||||
stream.println();
|
||||
stream.println();
|
||||
stream.println("# Permissions aren't here. Read http://wiki.sk89q.com/wiki/WEPIF/DinnerPerms");
|
||||
stream.println("# for how WorldEdit permissions actually work.");
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user