Commits

Tim Vernum committed 2d5eb28

Import from private branch (rev:e6480e87dd7b)

  • Participants
  • Parent commits 7e14b88

Comments (0)

Files changed (55)

File CHANGES.text

+2010-12-20
+    Implement message() efun
+    Avoid concurrent modification exception in input handlers
+    Support zero in binary or
+
+2010-12-01
+    add_action support
+
+2010-11-29
+    Add useful 'toString' on input_to handler
+    Search inheritance tree from applies
+    Support zero length input
+    Don't wrap values as 'mixed' type
+    Add 'getLocation' to function literals
+    Treat void values as 0
+
 2010-11-26
+    Better error reporting if filter function does not return a value
+    Fix interpretation of 2nd arg to restore_object
     Don't allow LPC method to over-ride standard LpcObject/Object methods with the same name
     Require all compiled objects to implement "CompileImplementation" interface.
     Initialise fields after object is fully constructed so certain efuns (like this_object()) work
         <do-in-module module="plugin.crypt"       target="@{target}" />
         <do-in-module module="plugin.compat"      target="@{target}" />
         <do-in-module module="plugin.privs"       target="@{target}" />
+        <do-in-module module="plugin.action"      target="@{target}" />
         <do-in-module module="plugin.parser"      target="@{target}" />
         <do-in-module module="plugin.ed"          target="@{target}" />
     </sequential>

File modules/engine/source/java/server/us/terebi/engine/server/InputHandlerSet.java

+/* ------------------------------------------------------------------------
+ * The Terebi (LPC) Game Engine
+ * Copyright 2010 Tim Vernum
+ * ------------------------------------------------------------------------
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * ------------------------------------------------------------------------
+ */
+
+package us.terebi.engine.server;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author <a href="http://blog.adjective.org/">Tim Vernum</a>
+ */
+public class InputHandlerSet
+{
+    private final List<InputHandler> _handlers;
+
+    public InputHandlerSet(InputHandler... handlers)
+    {
+        _handlers = new ArrayList<InputHandler>(Arrays.asList(handlers));
+    }
+
+    public void prepend(InputHandler handler)
+    {
+        _handlers.add(0, handler);
+    }
+
+    public void append(InputHandler handler)
+    {
+        _handlers.add(handler);
+    }
+
+    public void remove(InputHandler handler)
+    {
+        _handlers.remove(handler);
+    }
+
+    public Collection<InputHandler> handlers()
+    {
+        return Collections.unmodifiableCollection(_handlers);
+    }
+
+    public boolean contains(Class< ? extends InputHandler> type)
+    {
+        for (InputHandler handler : this._handlers)
+        {
+            if (type.isInstance(handler))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+}

File modules/engine/source/java/server/us/terebi/engine/server/ObjectShell.java

 package us.terebi.engine.server;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
 
 import org.apache.log4j.Logger;
 
 import us.terebi.engine.server.TerebiServer.ConnectionObjectFactory;
+import us.terebi.lang.lpc.runtime.AttributeMap;
 import us.terebi.lang.lpc.runtime.ObjectInstance;
 import us.terebi.lang.lpc.runtime.jvm.context.RuntimeContext;
 import us.terebi.lang.lpc.runtime.jvm.context.SystemContext;
-import us.terebi.lang.lpc.runtime.jvm.value.StringValue;
+import us.terebi.lang.lpc.runtime.jvm.exception.InternalError;
+import us.terebi.lang.lpc.runtime.jvm.exception.LpcRuntimeException;
 import us.terebi.lang.lpc.runtime.util.Apply;
 import us.terebi.net.core.AttributeChange;
 import us.terebi.net.core.Connection;
  */
 public class ObjectShell implements Shell
 {
+    public static final String SWITCHABLE_ATTRIBUTE_PREFIX = "user.";
+
     private final static Logger LOG = Logger.getLogger(ObjectShell.class);
 
-    private static final Apply INPUT_HANDLER = new Apply("process_input");
+    private static final String[] EMPTY_INPUT = new String[] { "" };
+
     private static final Apply LOGON_HANDLER = new Apply("logon");
 
-    public static final String OBJECT_CONNECTION_ATTRIBUTE = "net.connection";
-    private static final String OBJECT_SWITCH_TO = "net.connection.switch";
-    public static final String OBJECT_IDLE_ATTRIBUTE = "net.idle";
-    private static final String OBJECT_INPUT_HANDLER_ATTRIBUTE = "net.handler.input";
-    private static final String OBJECT_DESTRUCT_LISTENER = "net.connection.listener";
+    private static final String OBJECT_CONNECTION_ATTRIBUTE = SWITCHABLE_ATTRIBUTE_PREFIX + "net.connection";
+    private static final String OBJECT_SWITCH_TO = SWITCHABLE_ATTRIBUTE_PREFIX + "net.connection.switch";
+    private static final String OBJECT_IDLE_ATTRIBUTE = SWITCHABLE_ATTRIBUTE_PREFIX + "net.idle";
+    private static final String OBJECT_INPUT_HANDLER_ATTRIBUTE = SWITCHABLE_ATTRIBUTE_PREFIX + "net.handler.input";
+    private static final String OBJECT_DESTRUCT_LISTENER = SWITCHABLE_ATTRIBUTE_PREFIX + "net.connection.listener";
 
     private static final String PREFIX = ObjectShell.class.getName();
-    private static final String CONNECTION_OBJECT_ATTRIBUTE = PREFIX + ".object";
+    private static final String CONNECTION_OBJECT_ATTRIBUTE = PREFIX + ".net.object";
 
     private static final Object DESTRUCT_LISTENER = new ObjectInstance.DestructListener()
     {
         }
         instance.getAttributes().set(OBJECT_CONNECTION_ATTRIBUTE, connection);
         instance.getAttributes().set(OBJECT_DESTRUCT_LISTENER, DESTRUCT_LISTENER);
+        instance.getAttributes().set(OBJECT_INPUT_HANDLER_ATTRIBUTE, new InputHandlerSet(ProcessInputHandler.INSTANCE));
         connection.getAttributes().setAttribute(CONNECTION_OBJECT_ATTRIBUTE, instance);
 
         LOGON_HANDLER.invoke(instance);
             LOG.info("Object " + toObject.getCanonicalName() + " is already linked to a connection");
             return false;
         }
+
         ObjectInstance oldObject = getConnectionObject(connection);
-        oldObject.getAttributes().set(OBJECT_CONNECTION_ATTRIBUTE, null);
+        AttributeMap fromAttributes = oldObject.getAttributes();
+        AttributeMap toAttributes = toObject.getAttributes();
+
+        Iterable<String> names = fromAttributes.names();
+        for (String name : names)
+        {
+            if (name.startsWith(SWITCHABLE_ATTRIBUTE_PREFIX))
+            {
+                LOG.info("Copying attribute " + name + " from " + oldObject + " to " + toObject);
+                toAttributes.set(name, fromAttributes.get(name));
+            }
+            else
+            {
+                LOG.debug("Not copying attribute " + name + " from " + oldObject);
+            }
+        }
+
+        fromAttributes.remove(OBJECT_CONNECTION_ATTRIBUTE);
+        fromAttributes.set(OBJECT_SWITCH_TO, toObject);
         connection.getAttributes().setAttribute(CONNECTION_OBJECT_ATTRIBUTE, toObject);
-        toObject.getAttributes().set(OBJECT_CONNECTION_ATTRIBUTE, connection);
-        oldObject.getAttributes().set(OBJECT_SWITCH_TO, toObject);
         LOG.info("Switch connection " + connection + " from " + oldObject + " to " + toObject);
         return true;
     }
     public void inputReceived(String input, InputInfo info, Connection connection)
     {
         String[] lines = input.split("[\r\n]");
+        if (lines.length == 0)
+        {
+            lines = EMPTY_INPUT;
+        }
         for (String line : lines)
         {
-            if (line.length() > 0)
-            {
-                ObjectInstance instance = getConnectionObject(connection);
-                RuntimeContext.activate(_context);
-                handleInput(instance, connection, line);
-            }
+            ObjectInstance instance = getConnectionObject(connection);
+            RuntimeContext.activate(_context);
+            handleInput(instance, connection, line);
         }
     }
 
     private void handleInput(ObjectInstance user, Connection connection, String line)
     {
-        if (LOG.isDebugEnabled())
-        {
-            LOG.debug("Handle input for " + user);
-        }
-
-        Object attribute = user.getAttributes().get(OBJECT_INPUT_HANDLER_ATTRIBUTE);
-        if (attribute != null)
-        {
-            InputHandler input = (InputHandler) attribute;
-            String result = input.inputReceived(user, connection, line);
-            LOG.debug("Passed input through " + input + " and received " + result);
-            line = result;
-        }
-        if (line == null || line.length() == 0)
+        if (line == null)
         {
             return;
         }
-        INPUT_HANDLER.invoke(user, new StringValue(line));
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Handle input for " + user + " [" + user.getDefinition() + "]");
+        }
+
+        InputHandlerSet handlers = getInputHandlers(user);
+        // clone the handlers to avoid concurrent modification exceptions..
+        for (InputHandler handler : new ArrayList<InputHandler>(handlers.handlers()))
+        {
+            try
+            {
+                String result = handler.inputReceived(user, connection, line);
+                LOG.debug("Passed input through " + handler + " and received " + result);
+                if (result == null)
+                {
+                    return;
+                }
+                line = result;
+            }
+            catch (LpcRuntimeException e)
+            {
+                LOG.error("Unhandled exception ", e);
+                PrintWriter writer = connection.getWriter();
+                writer.write("Oh no! Something went wrong ...");
+                writer.flush();
+            }
+        }
     }
 
-    public static void setInputHandler(ObjectInstance user, InputHandler handler)
+    public static InputHandlerSet getInputHandlers(ObjectInstance user)
     {
-        user.getAttributes().set(OBJECT_INPUT_HANDLER_ATTRIBUTE, handler);
-    }
+        if (!isConnectionObject(user))
+        {
+            ObjectInstance switchedObject = getSwitchedObject(user);
+            if (switchedObject == null)
+            {
+                throw new InternalError("Attempt to get input handlers for non-connection " + user);
+            }
+            else
+            {
+                user = switchedObject;
+            }
+        }
+        Object attribute = user.getAttributes().get(OBJECT_INPUT_HANDLER_ATTRIBUTE);
+        if (attribute == null)
+        {
+            throw new InternalError("User attribute " + OBJECT_INPUT_HANDLER_ATTRIBUTE + " is missing from " + user);
+        }
 
-    public static InputHandler getInputHandler(ObjectInstance user)
-    {
-        return (InputHandler) user.getAttributes().get(OBJECT_INPUT_HANDLER_ATTRIBUTE);
+        if (!(attribute instanceof InputHandlerSet))
+        {
+            throw new InternalError("User attribute "
+                    + OBJECT_INPUT_HANDLER_ATTRIBUTE
+                    + " should be "
+                    + InputHandler.class.getSimpleName()
+                    + " but is "
+                    + attribute.getClass());
+        }
+
+        InputHandlerSet handlers = (InputHandlerSet) attribute;
+        return handlers;
     }
 
 }

File modules/engine/source/java/server/us/terebi/engine/server/ProcessInputHandler.java

+/* ------------------------------------------------------------------------
+ * The Terebi (LPC) Game Engine
+ * Copyright 2010 Tim Vernum
+ * ------------------------------------------------------------------------
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * ------------------------------------------------------------------------
+ */
+
+package us.terebi.engine.server;
+
+import us.terebi.lang.lpc.runtime.LpcValue;
+import us.terebi.lang.lpc.runtime.ObjectInstance;
+import us.terebi.lang.lpc.runtime.jvm.support.MiscSupport;
+import us.terebi.lang.lpc.runtime.jvm.value.StringValue;
+import us.terebi.lang.lpc.runtime.util.Apply;
+import us.terebi.net.core.Connection;
+
+/**
+ * @author <a href="http://blog.adjective.org/">Tim Vernum</a>
+ */
+public class ProcessInputHandler implements InputHandler
+{
+    public static final ProcessInputHandler INSTANCE = new ProcessInputHandler();
+
+    private static final Apply PROCESS_INPUT = new Apply("process_input");
+
+    public String inputReceived(ObjectInstance user, Connection connection, String line)
+    {
+        LpcValue result = PROCESS_INPUT.invoke(user, new StringValue(line));
+        if (MiscSupport.isNothing(result))
+        {
+            return line;
+        }
+        if (MiscSupport.isString(result))
+        {
+            return result.asString();
+        }
+        return null;
+    }
+
+}

File modules/lib.ds/etc/ds.terebi.config

 compile.include.directories=include:secure/include
 compile.include.auto=secure/include/global.h
 compile.output=../work/
-compile.debug=.*:save_player
+compile.debug=
 save.extension.default=.o
 plugins.directory=../driver/plugins/
 compat.mud.name=DeadSoulsNew

File modules/lib.ds/etc/log4j.xml

         <level value="INFO" />
     </logger>
 
+    <logger name="us.terebi.lang.lpc.compiler.classloader.AutoCompilingClassLoader" additivity="false">
+        <level value="INFO" />
+    </logger>
+
     <logger name="us.terebi.lang.lpc" additivity="true">
         <level value="DEBUG" />
     </logger>

File modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/ClassBuilder.java

 import us.terebi.lang.lpc.runtime.jvm.LpcMember;
 import us.terebi.lang.lpc.runtime.jvm.exception.InternalError;
 import us.terebi.lang.lpc.runtime.jvm.naming.MethodNamer;
-import us.terebi.lang.lpc.runtime.util.SystemLog;
 
 /**
  * 
 
     private MethodDescriptor getInitMethod()
     {
-        Statement[] statements = new Statement[_initialisers.size() + 2];
-        int i = 1;
-        statements[0] = VM.Statement.callStatic(new ParameterisedClassImpl(SystemLog.class),
-                VM.Method.find((SystemLog.class), "message", String.class), VM.Expression.constant("--INIT--" + this._spec.getInternalName())).create();
+        Statement[] statements = new Statement[_initialisers.size() + 1];
+        int i = 0;
         for (Statement statement : _initialisers)
         {
             statements[i] = statement;

File modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/FunctionCallCompiler.java

 import us.terebi.lang.lpc.parser.ast.ExpressionNode;
 import us.terebi.lang.lpc.parser.ast.Node;
 import us.terebi.lang.lpc.parser.jj.ParserConstants;
-import us.terebi.lang.lpc.parser.util.ASTUtil;
 import us.terebi.lang.lpc.parser.util.BaseASTVisitor;
 import us.terebi.lang.lpc.runtime.ArgumentDefinition;
 import us.terebi.lang.lpc.runtime.ArgumentSemantics;
     private LpcExpression compileSimpleArg(ASTArgumentExpression node, ArgumentData data)
     {
         LpcType requiredType = data.definition.getType();
-        if (data.function.name.equals("SetId"))
-        {
-            System.out.println("Function is " + data.function);
-            System.out.println("Compiling " + ASTUtil.getCompleteImage(node) + " as simple arg; required type = " + requiredType);
-        }
         if (data.definition.isVarArgs())
         {
             requiredType = Types.elementOf(requiredType);
-            if (data.function.name.equals("SetId"))
-            {
-                System.out.println(data.definition.getName() + " is varargs; required type = " + requiredType);
-            }
         }
         LpcExpression expr = compileExpression(node.jjtGetChild(0));
         TypeSupport.checkType(node, expr.type, requiredType);

File modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/FunctionLiteralCompiler.java

 import org.adjective.stout.builder.ParameterSpec;
 import org.adjective.stout.core.ConstructorSignature;
 import org.adjective.stout.core.ElementModifier;
+import org.adjective.stout.core.MethodDescriptor;
 import org.adjective.stout.core.MethodSignature;
 import org.adjective.stout.core.Parameter;
 import org.adjective.stout.operation.Expression;
 import us.terebi.lang.lpc.compiler.util.FunctionCallSupport;
 import us.terebi.lang.lpc.compiler.util.MethodSupport;
 import us.terebi.lang.lpc.compiler.util.Positional;
+import us.terebi.lang.lpc.parser.LineMapping;
 import us.terebi.lang.lpc.parser.ast.ASTCompoundExpression;
 import us.terebi.lang.lpc.parser.ast.ASTFunctionLiteral;
 import us.terebi.lang.lpc.parser.ast.ASTImmediateExpression;
         spec.withSuperClass(LpcFunction.class);
         spec.withModifiers(ElementModifier.PUBLIC, ElementModifier.FINAL);
         _context.pushClass(spec);
+        
+        MethodSpec getLocation = getLocationMethod(token);
+        spec.withMethod(getLocation.create());
         return spec;
     }
 
+    @SuppressWarnings("unchecked")
+    private MethodSpec getLocationMethod(Token token)
+    {
+        LineMapping lines = _context.lineMapping();
+        String location = lines.getFile(token.beginLine) + ':' + lines.getLine(token.beginLine) + ':' + token.beginColumn;
+        MethodSpec getLocation = new MethodSpec("getLocation");
+        getLocation.withReturnType(String.class);
+        getLocation.withBody(VM.Statement.returnObject(VM.Expression.constant(location)));
+        return getLocation;
+    }
+
     private Set<VariableResolution> getReferencedVariables(Collection<ASTVariableReference> vars)
     {
         VariableResolver variables = _parentScope.variables();
         Collection<ASTVariableReference> vars = findReferencedVariables(node);
         ClassSpec spec = createClassSpec(node);
 
-
         List<Parameter> parameters = new ArrayList<Parameter>();
         
         parameters.add(new ParameterSpec("s$owner").withType(LpcObject.class).create());

File modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/classloader/AutoCompilingClassLoader.java

         }
         try
         {
-            LOG.debug("Attempt to compile " + lpc);
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("Attempt to compile " + lpc);
+            }
             _compiler.precompile(lpc);
         }
         catch (CompileException e)
         {
-            LOG.debug("Cannot compile " + lpc + "for " + name + " - " + e);
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("Cannot compile " + lpc + "for " + name + " - " + e);
+            }
         }
     }
 }

File modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/util/TypeSupport.java

             return true;
         }
 
-        LpcType type = actual;
         for (LpcType allowed : allowedTypes)
         {
-            if (isCoVariant(allowed, type))
+            if (isCoVariant(allowed, actual))
             {
                 return true;
             }
             {
                 return true;
             }
-            if (type.getKind() == LpcType.Kind.MIXED && type.getArrayDepth() >= allowed.getArrayDepth())
+            if (actual.getKind() == LpcType.Kind.MIXED && actual.getArrayDepth() >= allowed.getArrayDepth())
             {
                 return true;
             }
-            if (Types.FLOAT.equals(allowed) && Types.INT.equals(type))
+            if (actual.getKind() == LpcType.Kind.ZERO && actual.getArrayDepth() == allowed.getArrayDepth())
+            {
+                return true;
+            }
+            if (Types.FLOAT.equals(allowed) && Types.INT.equals(actual))
             {
                 return true;
             }
         }
+        
         return false;
     }
 

File modules/lpc/source/java/compiler/us/terebi/lang/lpc/runtime/jvm/StandardEfuns.java

 import us.terebi.lang.lpc.runtime.jvm.efun.MasterEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.MatchPathEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.MemberArrayEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.MessageEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.NoOpEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.NullpEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.ObjectpEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.VariablesEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.VirtualpEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.WriteEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.action.AddActionEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.action.CommandEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.action.CommandsEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.action.EnableCommandsEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.action.QueryVerbEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.action.SetLivingNameEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.callout.CallOutEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.callout.CallOutInfoEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.callout.FindCallOutEfun;
         public static final Efun living = new LivingEfun();
         public static final Efun livings = new LivingsEfun();
         public static final Efun write = new WriteEfun();
-        public static final Efun message = new MessageEfun();
         public static final Efun flush_messages = new FlushMessagesEfun();
         public static final Efun terminal_colour = new TerminalColourEfun();
         public static final Efun snoop = new SnoopEfun();
         public static final Efun get_elapsed_execution_time = new GetElapsedExecTimeEfun();
     }
 
-    public static class ACTION
-    {
-        public static final Efun query_verb = new QueryVerbEfun();
-        public static final Efun add_action = new AddActionEfun();
-        public static final Efun enable_commands = new EnableCommandsEfun();
-        public static final Efun command = new CommandEfun();
-        public static final Efun commands = new CommandsEfun();
-        public static final Efun set_living_name = new SetLivingNameEfun();
-    }
-
     public static class NET
     {
         public static final Efun query_ip_number = new QueryIpNumberEfun();
                 populate(_efuns, CALLS.class);
                 populate(_efuns, FILE.class);
                 populate(_efuns, SYSTEM.class);
-                populate(_efuns, ACTION.class);
                 populate(_efuns, NET.class);
             }
         }

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/LpcFunction.java

         _support = new LpcRuntimeSupport();
     }
 
-    protected CharSequence getDescription()
-    {
-        return "function";
-    }
-
     public LpcType getActualType()
     {
         return Types.FUNCTION;
         return this.getClass() == other.getClass();
     }
 
+    public abstract String getLocation();
+
+    protected CharSequence getDescription()
+    {
+        return "function:" + getLocation();
+    }
+
     public CharSequence debugInfo()
     {
-        return "function" + getSignature().toString() + " { ... }";
+        return "function@" + getOwner() + '[' + getLocation() + ']' + getSignature().toString() + " { ... }";
     }
 
     public ObjectInstance getOwner()
     {
         return _support.simul_efun(name);
     }
-    
+
     public CharSequence getName()
     {
         return null;

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/AbstractEfun.java

             return LpcConstants.NIL;
         }
     }
+
+    protected int asInt(LpcValue flag)
+    {
+        long l = flag.asLong();
+        if (l > Integer.MAX_VALUE)
+        {
+            throw new LpcRuntimeException("The value " + flag + " is too large");
+        }
+        return (int) l;
+    }
 }

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/CallOtherEfun.java

 import us.terebi.lang.lpc.runtime.jvm.context.ObjectManager;
 import us.terebi.lang.lpc.runtime.jvm.context.RuntimeContext;
 import us.terebi.lang.lpc.runtime.jvm.exception.LpcRuntimeException;
-import us.terebi.lang.lpc.runtime.jvm.object.VirtualObjectDefinition;
 import us.terebi.lang.lpc.runtime.jvm.support.CallableSupport;
 import us.terebi.lang.lpc.runtime.jvm.support.MiscSupport;
 import us.terebi.lang.lpc.runtime.jvm.support.ValueSupport;

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/FilterEfun.java

 import us.terebi.lang.lpc.runtime.FunctionSignature;
 import us.terebi.lang.lpc.runtime.LpcType;
 import us.terebi.lang.lpc.runtime.LpcValue;
+import us.terebi.lang.lpc.runtime.jvm.exception.LpcRuntimeException;
 import us.terebi.lang.lpc.runtime.jvm.support.MiscSupport;
 import us.terebi.lang.lpc.runtime.jvm.type.Types;
 import us.terebi.lang.lpc.runtime.jvm.value.ArrayValue;

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/FindObjectEfun.java

         checkArguments(arguments);
         String name = arguments.get(0).asString();
 
+        ObjectInstance object = find_object(name);
+        if (object == null)
+        {
+            return NilValue.INSTANCE;
+        }
+        else
+        {
+            return object.asValue();
+        }
+    }
+
+    public static ObjectInstance find_object(String name)
+    {
         ThreadContext context = RuntimeContext.obtain();
         ObjectManager manager = context.system().objectManager();
         try
         {
             ObjectInstance object = manager.findObject(new ObjectId(name));
-            return getValue(object);
+            return object;
         }
         catch (NumberFormatException e)
         {
-            return NilValue.INSTANCE;
+            return null;
         }
     }
 

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/MessageEfun.java

-/* ------------------------------------------------------------------------
- * $Id$
- * Copyright 2009 Tim Vernum
- * ------------------------------------------------------------------------
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ------------------------------------------------------------------------
- */
-
-package us.terebi.lang.lpc.runtime.jvm.efun;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import us.terebi.lang.lpc.runtime.ArgumentDefinition;
-import us.terebi.lang.lpc.runtime.Callable;
-import us.terebi.lang.lpc.runtime.FunctionSignature;
-import us.terebi.lang.lpc.runtime.LpcType;
-import us.terebi.lang.lpc.runtime.LpcValue;
-import us.terebi.lang.lpc.runtime.jvm.type.Types;
-import us.terebi.lang.lpc.runtime.jvm.value.VoidValue;
-import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
-
-/**
- * 
- */
-public class MessageEfun extends AbstractEfun implements FunctionSignature, Callable
-{
-    //    void message( mixed class, mixed message, mixed target, mixed exclude );
-
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        ArrayList<ArgumentDefinition> list = new ArrayList<ArgumentDefinition>();
-        list.add(new ArgumentSpec("class", Types.MIXED));
-        list.add(new ArgumentSpec("message", Types.MIXED));
-        list.add(new ArgumentSpec("target", Types.MIXED));
-        list.add(new ArgumentSpec("exclude", Types.MIXED));
-        return list;
-    }
-
-    public boolean acceptsLessArguments()
-    {
-        return true;
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.VOID;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        /* @TODO : EFUN */
-        return VoidValue.INSTANCE;
-    }
-
-}

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/SortArrayEfun.java

 import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
 
 import static us.terebi.lang.lpc.runtime.jvm.support.MiscSupport.isFunction;
-import static us.terebi.lang.lpc.runtime.jvm.support.MiscSupport.isInt;
+import static us.terebi.lang.lpc.runtime.jvm.support.MiscSupport.isInteger;
 import static us.terebi.lang.lpc.runtime.jvm.support.MiscSupport.isString;
 
 /**
 
     private List<LpcValue> sort(List<LpcValue> list, LpcValue arg0, List<LpcValue> args)
     {
-        if (isInt(arg0))
+        if (isInteger(arg0))
         {
             return sort(list, arg0.asLong());
         }

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/action/AddActionEfun.java

-/* ------------------------------------------------------------------------
- * Copyright 2010 Tim Vernum
- * ------------------------------------------------------------------------
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ------------------------------------------------------------------------
- */
-
-package us.terebi.lang.lpc.runtime.jvm.efun.action;
-
-import java.util.Arrays;
-import java.util.List;
-
-import us.terebi.lang.lpc.runtime.ArgumentDefinition;
-import us.terebi.lang.lpc.runtime.LpcType;
-import us.terebi.lang.lpc.runtime.LpcValue;
-import us.terebi.lang.lpc.runtime.jvm.efun.AbstractEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.Efun;
-import us.terebi.lang.lpc.runtime.jvm.type.Types;
-import us.terebi.lang.lpc.runtime.jvm.value.VoidValue;
-import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
-
-/**
- * 
- */
-public class AddActionEfun extends AbstractEfun implements Efun
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Arrays.asList( //
-                new ArgumentSpec("fun", Types.MIXED), //
-                new ArgumentSpec("verb", Types.MIXED), //
-                new ArgumentSpec("flag", Types.INT) //
-        );
-    }
-
-    public boolean acceptsLessArguments()
-    {
-        return true;
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.VOID;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        // @TODO Auto-generated method stub
-        return VoidValue.INSTANCE;
-    }
-
-}

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/action/CommandEfun.java

-/* ------------------------------------------------------------------------
- * Copyright 2010 Tim Vernum
- * ------------------------------------------------------------------------
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ------------------------------------------------------------------------
- */
-
-package us.terebi.lang.lpc.runtime.jvm.efun.action;
-
-import java.util.Collections;
-import java.util.List;
-
-import us.terebi.lang.lpc.runtime.ArgumentDefinition;
-import us.terebi.lang.lpc.runtime.LpcType;
-import us.terebi.lang.lpc.runtime.LpcValue;
-import us.terebi.lang.lpc.runtime.jvm.LpcConstants;
-import us.terebi.lang.lpc.runtime.jvm.efun.AbstractEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.Efun;
-import us.terebi.lang.lpc.runtime.jvm.type.Types;
-import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
-
-/**
- * 
- */
-public class CommandEfun extends AbstractEfun implements Efun
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.singletonList(new ArgumentSpec("str", Types.STRING));
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.INT;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        // @TODO Auto-generated method stub
-        return LpcConstants.INT.ZERO;
-    }
-
-}

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/action/CommandsEfun.java

-/* ------------------------------------------------------------------------
- * Copyright 2010 Tim Vernum
- * ------------------------------------------------------------------------
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ------------------------------------------------------------------------
- */
-
-package us.terebi.lang.lpc.runtime.jvm.efun.action;
-
-import java.util.Collections;
-import java.util.List;
-
-import us.terebi.lang.lpc.runtime.ArgumentDefinition;
-import us.terebi.lang.lpc.runtime.LpcType;
-import us.terebi.lang.lpc.runtime.LpcValue;
-import us.terebi.lang.lpc.runtime.jvm.efun.AbstractEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.Efun;
-import us.terebi.lang.lpc.runtime.jvm.type.Types;
-import us.terebi.lang.lpc.runtime.jvm.value.ArrayValue;
-
-/**
- * 
- */
-public class CommandsEfun extends AbstractEfun implements Efun
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.emptyList();
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.MIXED_ARRAY_ARRAY;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        // @TODO Auto-generated method stub
-        return new ArrayValue(getReturnType(), 0);
-    }
-
-}

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/action/EnableCommandsEfun.java

-/* ------------------------------------------------------------------------
- * Copyright 2010 Tim Vernum
- * ------------------------------------------------------------------------
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ------------------------------------------------------------------------
- */
-
-package us.terebi.lang.lpc.runtime.jvm.efun.action;
-
-import java.util.Collections;
-import java.util.List;
-
-import us.terebi.lang.lpc.runtime.ArgumentDefinition;
-import us.terebi.lang.lpc.runtime.LpcType;
-import us.terebi.lang.lpc.runtime.LpcValue;
-import us.terebi.lang.lpc.runtime.jvm.efun.AbstractEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.Efun;
-import us.terebi.lang.lpc.runtime.jvm.type.Types;
-import us.terebi.lang.lpc.runtime.jvm.value.VoidValue;
-
-/**
- * 
- */
-public class EnableCommandsEfun extends AbstractEfun implements Efun
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.emptyList();
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.VOID;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        // @TODO Auto-generated method stub
-        return VoidValue.INSTANCE;
-    }
-
-}

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/action/QueryVerbEfun.java

-/* ------------------------------------------------------------------------
- * Copyright 2010 Tim Vernum
- * ------------------------------------------------------------------------
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ------------------------------------------------------------------------
- */
-
-package us.terebi.lang.lpc.runtime.jvm.efun.action;
-
-import java.util.Collections;
-import java.util.List;
-
-import us.terebi.lang.lpc.runtime.ArgumentDefinition;
-import us.terebi.lang.lpc.runtime.LpcType;
-import us.terebi.lang.lpc.runtime.LpcValue;
-import us.terebi.lang.lpc.runtime.jvm.LpcConstants;
-import us.terebi.lang.lpc.runtime.jvm.efun.AbstractEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.Efun;
-import us.terebi.lang.lpc.runtime.jvm.type.Types;
-
-/**
- * 
- */
-public class QueryVerbEfun extends AbstractEfun implements Efun
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.emptyList();
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.STRING;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        // @TODO Auto-generated method stub
-        return LpcConstants.STRING.BLANK;
-    }
-
-}

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/action/SetLivingNameEfun.java

-/* ------------------------------------------------------------------------
- * Copyright 2010 Tim Vernum
- * ------------------------------------------------------------------------
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ------------------------------------------------------------------------
- */
-
-package us.terebi.lang.lpc.runtime.jvm.efun.action;
-
-import java.util.Collections;
-import java.util.List;
-
-import us.terebi.lang.lpc.runtime.ArgumentDefinition;
-import us.terebi.lang.lpc.runtime.LpcType;
-import us.terebi.lang.lpc.runtime.LpcValue;
-import us.terebi.lang.lpc.runtime.jvm.efun.AbstractEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.Efun;
-import us.terebi.lang.lpc.runtime.jvm.type.Types;
-import us.terebi.lang.lpc.runtime.jvm.value.VoidValue;
-import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
-
-/**
- * 
- */
-public class SetLivingNameEfun extends AbstractEfun implements Efun
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.singletonList(new ArgumentSpec("name", Types.STRING));
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.VOID;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        // @TODO Auto-generated method stub
-        return VoidValue.INSTANCE;
-    }
-
-}

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/string/RegexpEfun.java

 import us.terebi.lang.lpc.runtime.LpcValue;
 import us.terebi.lang.lpc.runtime.jvm.efun.AbstractEfun;
 import us.terebi.lang.lpc.runtime.jvm.type.Types;
+import us.terebi.lang.lpc.runtime.jvm.value.NilValue;
 import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
 
 /**
     public LpcValue execute(List< ? extends LpcValue> arguments)
     {
         // @TODO Auto-generated method stub
-        return null;
+        return NilValue.INSTANCE;
     }
 
 }

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/string/StrsrchEfun.java

         {
             return ValueSupport.intValue(search(str, pattern.asString(), flag));
         }
-        if (MiscSupport.isInt(pattern))
+        if (MiscSupport.isInteger(pattern))
         {
             return ValueSupport.intValue(search(str, pattern.asLong(), flag));
         }

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/support/BinarySupport.java

         {
             return NilValue.INSTANCE;
         }
-        if (MiscSupport.isInt(values[0]))
+        if (MiscSupport.isInteger(values[0]))
         {
             long v = 0;
             for (LpcValue value : values)

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/support/MiscSupport.java

 {
     public static boolean isType(LpcType type, LpcValue value)
     {
+        if (value == null)
+        {
+            return false;
+        }
         return type.equals(value.getActualType());
     }
 
         return Types.MIXED.equals(type) || Types.ZERO.equals(type) || Types.NIL.equals(type);
     }
 
+    public static boolean isVoid(LpcValue value)
+    {
+        return isType(Types.VOID, value);
+    }
+
 }

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/value/TypedValue.java

         _value = value;
     }
 
-    public static TypedValue type(LpcType type, LpcValue value)
+    public static LpcValue type(LpcType type, LpcValue value)
     {
         if (value instanceof TypedValue)
         {
                 return typed;
             }
         }
+        if (MiscSupport.isDynamicType(type))
+        {
+            return value;
+        }
         return new TypedValue(type, value);
     }
 
-    public static TypedValue type(Kind kind, int arrayDepth, LpcValue value)
+    public static LpcValue type(Kind kind, int arrayDepth, LpcValue value)
     {
         return type(Types.getType(kind, null, arrayDepth), value);
     }

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/value/VoidValue.java

 
     public boolean asBoolean()
     {
-        throw this.isNot("a value");
+        return false;
     }
 
     protected boolean valueEquals(LpcValue other)

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/util/Apply.java

 
 import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
+
+import org.apache.log4j.Logger;
 
 import us.terebi.lang.lpc.runtime.Callable;
 import us.terebi.lang.lpc.runtime.LpcValue;
 import us.terebi.lang.lpc.runtime.ObjectInstance;
 import us.terebi.lang.lpc.runtime.jvm.context.CallStack;
 import us.terebi.lang.lpc.runtime.jvm.context.CallStack.Origin;
+import us.terebi.lang.lpc.runtime.jvm.support.CallableSupport;
 import us.terebi.lang.lpc.runtime.jvm.value.NilValue;
 
 /**
  */
 public class Apply
 {
+    private final Logger LOG = Logger.getLogger(Apply.class);
+
     private final String _name;
 
     public Apply(String name)
         final MethodDefinition method = getMethod(instance);
         if (method == null)
         {
+            LOG.debug("No method " + _name + " found in " + instance);
             return NilValue.INSTANCE;
         }
 
         return InContext.execute(Origin.APPLY, instance, new InContext.Exec<LpcValue>()
         {
+            @SuppressWarnings("synthetic-access")
             public LpcValue execute()
             {
-                return method.execute(instance, arguments);
+                LpcValue value = method.execute(instance, arguments);
+                if (LOG.isDebugEnabled())
+                {
+                    LOG.debug("Method " + method + " in " + instance + " ->" + value);
+                }
+                return value;
             }
         });
     }
 
     private MethodDefinition getMethod(ObjectInstance instance)
     {
-        Map<String, ? extends MethodDefinition> methods = instance.getDefinition().getMethods();
-        MethodDefinition method = methods.get(_name);
-        return method;
+        return CallableSupport.findMethod(_name, instance.getDefinition(), instance);
     }
 
     public String toString()
         return "apply " + _name;
     }
 
+    public boolean existsIn(ObjectInstance instance)
+    {
+        return getMethod(instance) != null;
+    }
+
 }

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/util/BoundMethod.java

 
     public String toString()
     {
-        return _instance.getCanonicalName() + "->" + _method.toString();
+        return _instance.getCanonicalName() + "::" + _method.toString();
     }
 
     public CharSequence getName()

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/util/CallableProxy.java

     
     public String toString()
     {
-        return getClass().getSimpleName() + ":" + _delegate;
+        return getClass().getSimpleName() + '~' + _delegate;
     }
 
     public CharSequence getName()

File modules/net/source/java/net/us/terebi/net/telnet/TelnetChannelConnectionHandler.java

 
     void readConnection(TelnetChannelConnection connection)
     {
-        LOG.debug("Processing " + connection);
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("Processing " + connection);
+        }
         try
         {
             connection.readInput();
         {
             connection.bind(_shell);
         }
-        
+
         _connections.add(connection);
-        
+
         LOG.info("New connection: " + connection);
         try
         {
         return Collections.unmodifiableSet(_connections);
     }
 }
-

File modules/plugin.action/.classpath

+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="source/java/action"/>
+	<classpathentry kind="src" path="source/java/plugin"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/terebi.engine"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/terebi.lpc"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/terebi.net"/>
+	<classpathentry kind="lib" path="/terebi.engine/lib/server/log4j-1.2.14.jar"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/terebi.plugin.interactive"/>
+	<classpathentry kind="output" path="output/eclipse"/>
+</classpath>

File modules/plugin.action/.project

+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>terebi.plugin.action</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

File modules/plugin.action/build.xml

+<project name="terebi.action"  default="all" basedir="." >
+
+  <property name="dir.source"                   location="source/"                       />
+  <property name="dir.source.java"              location="${dir.source}/java"            />
+  <property name="dir.source.resource"          location="${dir.source}/resource"        />
+  <property name="dir.source.resource.plugin"   location="${dir.source.resource}/plugin" />
+
+  <property name="dir.output"         location="output/ant"            />
+  <property name="dir.output.classes" location="${dir.output}/classes" />
+  <property name="dir.output.plugin"  location="${dir.output}/plugin" />
+
+  <target name="all"   description="Builds Plugin + runs tests" depends="build" />
+  <target name="build" description="Builds Plugin"              depends="compile, jar " />
+
+  <target name="compile" depends="compile.action, compile.plugin" />
+
+  <macrodef name="compile_java">
+       <attribute name="dir" />
+       <attribute name="classpath" />
+       <sequential>
+            <mkdir dir="${dir.output.classes}" />
+            <javac srcdir="${dir.source.java}/@{dir}"
+                   destdir="${dir.output.classes}"
+                   classpathref="@{classpath}"
+                   debug="true"
+                   deprecation="true" 
+                   optimize="true"
+                   listfiles="false"
+                   source="1.5">
+            </javac>
+       </sequential>
+  </macrodef>
+
+  <path id="build.classpath">
+    <pathelement location="../lpc/output/ant/classes" />
+    <pathelement location="../net/output/ant/classes" />
+    <pathelement location="../engine/output/ant/classes" />
+    <pathelement location="../plugin.interactive/output/ant/classes" />
+    <fileset dir="../engine/lib/server" />
+  </path>
+
+  <target name="compile.action">
+    <compile_java dir="action" classpath="build.classpath" />
+  </target>
+     
+  <target name="compile.plugin">
+    <compile_java dir="plugin" classpath="build.classpath" />
+  </target>
+     
+  <target name="jar" depends="compile" >
+    <mkdir dir="${dir.output.plugin}" />
+    <jar destfile="${dir.output.plugin}/action.jar" 
+         basedir="${dir.output.classes}">
+        <metainf dir="${dir.source.resource.plugin}" includes="terebi.properties" />
+    </jar>
+  </target>
+
+  <target name="dist.source" >
+    <zip destfile="${dir.output.plugin}/${ant.project.name}-source.zip">
+      <fileset dir="." includes="source/java/**" />
+      <fileset dir="." includes="source/resource/plugin/*" />
+    </zip>
+  </target>
+
+  <target name="dist" depends="jar,dist.source" />
+
+  <target name="clean">
+    <delete dir="${dir.output}" />
+  </target>
+
+</project>

File modules/plugin.action/source/java/action/us/terebi/plugins/action/efun/AddActionEfun.java

+/* ------------------------------------------------------------------------
+ * Copyright 2010 Tim Vernum
+ * ------------------------------------------------------------------------
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ------------------------------------------------------------------------
+ */
+
+package us.terebi.plugins.action.efun;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import us.terebi.lang.lpc.runtime.ArgumentDefinition;
+import us.terebi.lang.lpc.runtime.Callable;
+import us.terebi.lang.lpc.runtime.LpcType;
+import us.terebi.lang.lpc.runtime.LpcValue;
+import us.terebi.lang.lpc.runtime.ObjectInstance;
+import us.terebi.lang.lpc.runtime.jvm.efun.AbstractEfun;
+import us.terebi.lang.lpc.runtime.jvm.efun.Efun;
+import us.terebi.lang.lpc.runtime.jvm.efun.ThisObjectEfun;
+import us.terebi.lang.lpc.runtime.jvm.support.MiscSupport;
+import us.terebi.lang.lpc.runtime.jvm.type.Types;
+import us.terebi.lang.lpc.runtime.jvm.value.VoidValue;
+import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
+import us.terebi.plugins.action.handler.ActionHandler;
+import us.terebi.plugins.action.handler.ActionHandler.Action;
+import us.terebi.plugins.action.handler.ActionHandler.VerbType;
+import us.terebi.plugins.interactive.efun.ThisPlayerEfun;
+
+/**
+ * 
+ */
+public class AddActionEfun extends AbstractEfun implements Efun
+{
+    private final Logger LOG = Logger.getLogger(AddActionEfun.class);
+
+    //    void add_action( string | function fun, string | string array cmd );
+    //    void add_action( string | function fun, string | string array cmd, int flag );
+
+    protected List< ? extends ArgumentDefinition> defineArguments()
+    {
+        return Arrays.asList( //
+                new ArgumentSpec("fun", Types.MIXED), //
+                new ArgumentSpec("verb", Types.MIXED), //
+                new ArgumentSpec("flag", Types.INT) //
+        );
+    }
+
+    public boolean acceptsLessArguments()
+    {
+        return true;
+    }
+
+    public LpcType getReturnType()
+    {
+        return Types.VOID;
+    }
+
+    public LpcValue execute(List< ? extends LpcValue> arguments)
+    {
+        LpcValue fun = getArgument(arguments, 0);
+        LpcValue verb = getArgument(arguments, 1);
+        LpcValue flag = getArgument(arguments, 2);
+
+        Callable handler = getFunctionReference(fun);
+        VerbType type;
+        switch (asInt(flag))
+        {
+            case 1:
+                type = VerbType.ABBREV;
+                break;
+            case 2:
+                type = VerbType.PREFIX;
+                break;
+            case 0:
+            default:
+                type = VerbType.REGULAR;
+                break;
+        }
+
+        if (MiscSupport.isArray(verb))
+        {
+            List<LpcValue> verbs = verb.asList();
+            for (LpcValue verbElement : verbs)
+            {
+                add_action(handler, verbElement.asString(), type);
+            }
+        }
+        else
+        {