Commits

Tim Vernum  committed c183f2a

Import from private branch (rev:2042d13d56c1)

  • Participants
  • Parent commits d9b328b

Comments (0)

Files changed (55)

File modules/lib.ds/scripts/start.sh

 echo "Classpath = ${CP}"
 echo "Config = ${CONFIG_FILE}"
 
+DEBUG=0
+CLEAN=0
+
+while getopts "dc" option
+do
+    case $option in
+        d)
+            DEBUG=1
+            ;;
+        c)
+            CLEAN=1
+            ;;
+    esac
+done
+            
 [ -d ${WORK_DIR} ] || mkdir ${WORK_DIR}
+if [ $CLEAN -eq 1 ]
+then
+    rm -rf ${WORK_DIR}/*
+fi
 
-if [ "$1" = "-d" ]
+if [ $DEBUG -eq 1 ]
 then
     JAVA_OPTS="-Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address=9800,server=y,suspend=n"
 else
     JAVA_OPTS=""
 fi
 
+
 set -x
 java -cp ${CP} ${JAVA_OPTS} ${MAIN} ${CONFIG_FILE}
+

File modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/FileStore.java

 import java.io.FileOutputStream;
 import java.io.OutputStream;
 
+import org.apache.log4j.Logger;
+
 /**
  * 
  */
 public class FileStore implements ClassStore
 {
+    private final Logger LOG = Logger.getLogger(FileStore.class);
+
     private final File _directory;
 
     public FileStore(File directory)
     {
         _directory = directory;
+        LOG.info("New " + getClass().getSimpleName() + " @" + directory);
     }
 
     public OutputStream open(String packageName, String className) throws FileNotFoundException

File modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/ObjectBuilder.java

 import us.terebi.lang.lpc.parser.ast.SimpleNode;
 import us.terebi.lang.lpc.parser.jj.Token;
 import us.terebi.lang.lpc.runtime.jvm.LpcObject;
+import us.terebi.lang.lpc.runtime.jvm.exception.InternalError;
+import us.terebi.lang.lpc.runtime.jvm.exception.LpcRuntimeException;
 import us.terebi.lang.lpc.runtime.jvm.object.CompiledDefinition;
 import us.terebi.util.log.LogContext;
 
             int mappedLine = lineMapping.getLine(rawLine);
             throw new CompileException(file, mappedLine, e);
         }
+        catch (LpcRuntimeException e)
+        {
+            throw new InternalError("While compiling " + resource, e);
+        }
         return ast;
     }
 

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

 import org.adjective.stout.operation.Statement;
 import org.adjective.stout.operation.VM;
 
+import us.terebi.lang.lpc.compiler.CompileException;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
+import us.terebi.lang.lpc.compiler.java.context.VariableResolver;
+import us.terebi.lang.lpc.compiler.java.context.VariableResolver.VariableResolution;
 import us.terebi.lang.lpc.compiler.util.MemberVisitor;
 import us.terebi.lang.lpc.compiler.util.TypeSupport;
 import us.terebi.lang.lpc.parser.ast.ASTFields;
 
         List<Statement> statements = new ArrayList<Statement>();
 
+        final VariableResolver variables = getScope().variables();
         for (TokenNode child : ASTUtil.children(node))
         {
             assert child instanceof ASTVariable : "Child node is " + child.getClass() + " (but should be " + ASTVariable.class.getSimpleName() + ")";
             FieldDescriptor field = this.visit((ASTVariable) child, null);
-            getScope().variables().declareField(field.name, field.type);
+            VariableResolution existingVar = variables.getVariableInFrame(field.name);
+            if (existingVar != null)
+            {
+                throw new CompileException(child, "The field " + field.name + " (" + existingVar + ") has already been declared");
+            }
+            variables.declareField(field.name, field.type);
 
             FieldCompiler.addField(classSpec, field);
 

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

             Expression[] collections = new Expression[argVars.length];
             for (int i = 0; i < collections.length; i++)
             {
-                Expression expr = argVars[i].expression.expression;
+                Expression expr = ExpressionCompiler.getValue(argVars[i].expression);
                 if (argVars[i].expand)
                 {
                     collections[i] = VM.Expression.callMethod(expr, LpcValue.class, ByteCodeConstants.VALUE_AS_LIST);

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

         FunctionCallSupport fcs = new FunctionCallSupport(_scope);
         FunctionReference function = fcs.findFunction(ref, ref.getScope(), ref.getVariableName());
         Expression callable = FunctionCallCompiler.getCallable(function);
+        
+        MethodSignature pointer = VM.Method.find(CallableSupport.class, "pointer", Callable.class, ObjectInstance.class);
+        Expression owner = VM.Expression.callInherited(ByteCodeConstants.GET_OBJECT_INSTANCE, new Expression[0]); 
+        callable = VM.Expression.callStatic(CallableSupport.class, pointer, callable, owner);
+
         if (!arguments.isEmpty())
         {
             ExpressionCompiler compiler = new ExpressionCompiler(_parentScope, _context);
             Expression[] elements = new Expression[arguments.size()];
             for (int i = 0; i < elements.length; i++)
             {
-                elements[i] = compiler.compile(arguments.get(i)).expression;
+                elements[i] = ExpressionCompiler.getValue(compiler.compile(arguments.get(i)));
             }
             Expression array = VM.Expression.array(LpcValue.class, elements);
             MethodSignature bind = VM.Method.find(CallableSupport.class, "bindArguments", Callable.class, LpcValue[].class);
             callable = VM.Expression.callStatic(CallableSupport.class, bind, callable, array);
         }
 
+
         Expression value = VM.Expression.construct(VM.Method.constructor(FunctionValue.class, Callable.class), callable);
         return new LpcExpression(function.signature.getReturnType(), value);
     }
     private MethodSpec getExpressionExecute(LpcExpression expr)
     {
         List<ElementBuilder<Statement>> body = Collections.singletonList(VM.Statement.returnObject(ExpressionCompiler.getValue(expr)));
-        return getExecute(body);
+        return getInvoke(body);
     }
 
-    private MethodSpec getExecute(List< ? extends ElementBuilder< ? extends Statement>> statements)
+    private MethodSpec getInvoke(List< ? extends ElementBuilder< ? extends Statement>> statements)
     {
         Parameter parameter = new ParameterSpec(POSITIONAL_ARGUMENT_COLLECTION).withType(LpcValue[].class).create();
-        MethodSpec execute = new MethodSpec("execute").withModifiers(ElementModifier.PUBLIC).withParameters(parameter);
+        MethodSpec execute = new MethodSpec("invoke").withModifiers(ElementModifier.PROTECTED).withParameters(parameter);
         return execute.withReturnType(ByteCodeConstants.LPC_VALUE).withBody(statements);
     }
 
 
         statementCompiler.compileBlock(blockNode);
         _scope.variables().popScope();
-        
+
         statements.add(VM.Statement.returnObject(ByteCodeConstants.VOID));
 
-        return getExecute(statements);
+        return getInvoke(statements);
     }
 
     private MethodSpec getBlockConstructor(List<Parameter> parameters, LpcExpression[] immediates,

File modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/java/context/FunctionLookup.java

 import java.util.Collections;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.adjective.stout.core.UnresolvedType;
 
 import us.terebi.lang.lpc.compiler.java.context.VariableLookup.ObjectPath;
+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.InternalName;
         {
             return;
         }
-        throw new LookupException("Attempt to redefined signature for " + name + " from " + existing + " to " + replacement);
+        if (!existing.getReturnType().equals(replacement.getReturnType()))
+        {
+            throw new LookupException("Attempt to redefine return type for " + name + " from " + existing + " to " + replacement);
+        }
+        if (existing.getArguments().size() != replacement.getArguments().size())
+        {
+            throw new LookupException("Attempt to redefine argument count for " + name + " from " + existing + " to " + replacement);
+        }
+        Iterator< ? extends ArgumentDefinition> ie = existing.getArguments().iterator();
+        Iterator< ? extends ArgumentDefinition> ir = replacement.getArguments().iterator();
+        while (ie.hasNext())
+        {
+            ArgumentDefinition e = ie.next();
+            ArgumentDefinition r = ir.next();
+            if (!e.getType().equals(r.getType()))
+            {
+                throw new LookupException("Attempt to redefine argument type ("
+                        + e.getName()
+                        + ") for "
+                        + name
+                        + " from "
+                        + existing
+                        + " to "
+                        + replacement);
+            }
+        }
     }
 
     private void checkMatchingModifiers(String name, Set< ? extends Modifier> existing, Set< ? extends Modifier> replacement)
                 Modifier.PRIVATE));
         if (!accessModifiers.isEmpty())
         {
-            throw new LookupException("Attempt to redefined modifiers for " + name + " from " + existing + " to " + replacement);
+            throw new LookupException("Attempt to redefine modifiers for " + name + " from " + existing + " to " + replacement);
         }
 
         if (existing.contains(Modifier.VARARGS) && !replacement.contains(Modifier.VARARGS))

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

 
     public void checkArgumentCount(final int providedArguments, FunctionReference function, ASTFunctionArguments args)
     {
+        if (args.hasExpander())
+        {
+            return;
+        }
         Range<Integer> allowedArgCount = FunctionUtil.getAllowedNumberOfArgument(function.signature);
         if (!allowedArgCount.inRange(providedArguments))
         {

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

         }
         catch (LookupException e)
         {
-            throw new CompileException(_node, e.getMessage());
+            throw new CompileException(_node, e.getMessage(), e);
         }
     }
 

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

 import us.terebi.lang.lpc.runtime.jvm.efun.ClasspEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.CloneObjectEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.ClonepEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.CtimeEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.DebugInfoEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.DebugMessageEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.DestructEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.FunctionOwnerEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.FunctionpEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.FunctionsEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.GetElapsedExecTimeEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.GetMaxExecTimeEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.InheritListEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.InheritsEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.IntpEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.LivingEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.LivingsEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.LoadObjectEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.LocaltimeEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.MapArrayEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.MapDeleteEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.MapEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.QuerySnoopEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.QuerySnoopingEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.RandomEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.SetMaxExecTimeEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.ShutdownEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.SizeofEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.SnoopEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.StringpEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.TerminalColourEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.ThisObjectEfun;
-import us.terebi.lang.lpc.runtime.jvm.efun.TimeEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.ToFloatEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.ToIntEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.TypeofEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.UserpEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.UsersEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.ValuesEfun;
+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.string.StrsrchEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.string.TrimEfun;
 import us.terebi.lang.lpc.runtime.jvm.efun.string.UpperCaseEfun;
+import us.terebi.lang.lpc.runtime.jvm.efun.time.CtimeEfun;
+import us.terebi.lang.lpc.runtime.jvm.efun.time.GetElapsedExecTimeEfun;
+import us.terebi.lang.lpc.runtime.jvm.efun.time.GetMaxExecTimeEfun;
+import us.terebi.lang.lpc.runtime.jvm.efun.time.LocaltimeEfun;
+import us.terebi.lang.lpc.runtime.jvm.efun.time.SetMaxExecTimeEfun;
+import us.terebi.lang.lpc.runtime.jvm.efun.time.TimeEfun;
+import us.terebi.lang.lpc.runtime.jvm.efun.time.UptimeEfun;
 
 /**
  * 
         public static final Efun destruct = new DestructEfun();
         public static final Efun clonep = new ClonepEfun();
         public static final Efun virtualp = new VirtualpEfun();
+        public static final Efun variables = new VariablesEfun();
         public static final Efun store_variable = new StoreVariableEfun();
         public static final Efun fetch_variable = new FetchVariableEfun();
     }
         public static final Efun time = new TimeEfun();
         public static final Efun ctime = new CtimeEfun();
         public static final Efun localtime = new LocaltimeEfun();
+        public static final Efun uptime = new UptimeEfun();
         public static final Efun dump_file_descriptors = new NoOpEfun(LpcConstants.STRING.BLANK);
         public static final Efun reclaim_objects = new NoOpEfun(LpcConstants.INT.ZERO);
 

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

         MASTER, INSTANCE, INHERIT, PROTOTYPE;
     }
 
-    protected abstract CompiledObjectInstance newInstance(long id, InstanceType type, Object forThis, List< ? extends LpcValue> createArguments);
+    protected abstract CompiledObjectInstance newInstance(long id, InstanceType type, CompiledObjectInstance forInstance, List< ? extends LpcValue> createArguments);
 
     public void instanceDestructed(ObjectInstance instance)
     {
 
     public CompiledObjectInstance getInheritableInstance(ObjectInstance forInstance)
     {
-        Object thisPtr = null;
         if (forInstance instanceof CompiledObjectInstance)
         {
-            thisPtr = ((CompiledObjectInstance) forInstance).getImplementingObject();
+            CompiledObjectInstance coi = ((CompiledObjectInstance) forInstance);
+            return newInstance(0, InstanceType.INHERIT, coi, Collections.<LpcValue> emptyList());
         }
         else
         {
             throw new IllegalArgumentException("Cannot create instance for non-compiled object " + forInstance);
         }
-        return newInstance(0, InstanceType.INHERIT, thisPtr, Collections.<LpcValue> emptyList());
     }
 
     public CompiledObjectInstance getPrototypeInstance()

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

 
 import us.terebi.lang.lpc.compiler.CompilerObjectManager;
 import us.terebi.lang.lpc.compiler.java.context.CompiledObjectDefinition;
+import us.terebi.lang.lpc.compiler.java.context.CompiledObjectInstance;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
 import us.terebi.lang.lpc.runtime.ClassDefinition;
 import us.terebi.lang.lpc.runtime.CompiledMethodDefinition;
             LpcMember annotation = method.getAnnotation(LpcMember.class);
             if (annotation != null)
             {
-                _methods.put(annotation.name(), new CompiledMethod(this, method, _lookup));
+//                try
+//                {
+//                    method = iface.getMethod(method.getName(), method.getParameterTypes());
+                    _methods.put(annotation.name(), new CompiledMethod(this, method, _lookup));
+//                }
+//                catch (SecurityException e)
+//                {
+//                    throw new InternalError(e);
+//                }
+//                catch (NoSuchMethodException e)
+//                {
+//                    throw new InternalError(e);
+//                }
             }
         }
 
         return Collections.unmodifiableMap(_inherited);
     }
 
-    protected CompiledObject<T> newInstance(long id, InstanceType type, Object forThis, List< ? extends LpcValue> createArguments)
+    protected CompiledObject<T> newInstance(long id, InstanceType type, CompiledObjectInstance forInstance, List< ? extends LpcValue> createArguments)
     {
         if (id != 0)
         {
             getMasterInstance();
         }
 
-        T object = createObject(forThis);
+        T object = createObject(forInstance == null ? null : forInstance.getImplementingObject());
 
         Map<String, ObjectInstance> parents = new HashMap<String, ObjectInstance>();
 
         }
 
         object.setDefinition(this);
-        object.setInstance(instance);
+        object.setInstance(forInstance == null ? instance : forInstance);
         if (type == InstanceType.MASTER || type == InstanceType.INSTANCE)
         {
             register(instance);

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

 import us.terebi.lang.lpc.runtime.MemberDefinition;
 import us.terebi.lang.lpc.runtime.ObjectInstance;
 import us.terebi.lang.lpc.runtime.jvm.LpcMember;
+import us.terebi.lang.lpc.runtime.jvm.LpcMemberType;
 import us.terebi.lang.lpc.runtime.jvm.LpcParameter;
-import us.terebi.lang.lpc.runtime.jvm.LpcMemberType;
+import us.terebi.lang.lpc.runtime.jvm.exception.InternalError;
 import us.terebi.lang.lpc.runtime.jvm.exception.LpcRuntimeException;
 import us.terebi.lang.lpc.runtime.jvm.type.Types;
 import us.terebi.lang.lpc.runtime.jvm.value.NilValue;
     private final Set< ? extends Modifier> _modifiers;
     private final ScopeLookup _lookup;
 
+    @SuppressWarnings("unchecked")
     public CompiledMethod(CompiledObjectDefinition object, Method method, ScopeLookup lookup)
     {
         _objectDefinition = object;
-        _method = method;
         _name = resolveName(method);
         _signature = resolveSignature(method);
         _modifiers = resolveModifiers(method);
         _lookup = lookup;
+
+        Class[] interfaces = method.getDeclaringClass().getInterfaces();
+        assert interfaces.length == 1;
+        Class iface = interfaces[0];
+        
+      try
+      {
+          // Look for method on interface to support polymorphism
+          method = iface.getMethod(method.getName(), method.getParameterTypes());
+      }
+      catch (SecurityException e)
+      {
+          throw new InternalError(e);
+      }
+      catch (NoSuchMethodException e)
+      {
+          // Ignore
+      }
+      _method = method;
     }
 
     private FunctionSignature resolveSignature(Method method)
             }
             throw new IllegalStateException("Method " + _method + " did not return an LpcValue - returned " + result + " instead");
         }
+        catch (IllegalArgumentException e)
+        {
+            throw new LpcRuntimeException("During method " + _method + " - " + e.getMessage(), e);
+        }
         catch (IllegalAccessException e)
         {
             throw new LpcRuntimeException("During method " + _method + " - " + e.getMessage(), e);

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

         return _definition.getFields();
     }
 
-    protected CompiledObjectInstance newInstance(long id, InstanceType type, Object forThis, List< ? extends LpcValue> createArguments)
+    protected CompiledObjectInstance newInstance(long id, InstanceType type, CompiledObjectInstance forInstance, List< ? extends LpcValue> createArguments)
     {
         CompiledObjectInstance instance = _definition.getPrototypeInstance();
         for (FieldDefinition fieldDefinition : _definition.getFields().values())

File modules/lpc/source/java/parser/us/terebi/lang/lpc/io/ByteArrayResource.java

  */
 public class ByteArrayResource implements Resource
 {
+    private static final Resource[] NO_CHILDREN = new Resource[0];
+    
     private final byte[] _bytes;
     private final String _name;
 
     {
         return new NoSuchResource(this, name);
     }
+    
+    public Resource[] getChildren()
+    {
+        return NO_CHILDREN;
+    }
 
     public String getName()
     {
     {
         return true;
     }
+    
+    public long lastModified()
+    {
+        return System.currentTimeMillis();
+    }
 }

File modules/lpc/source/java/parser/us/terebi/lang/lpc/io/FileResource.java

         return new FileResource(new File(_file, name));
     }
 
+    public Resource[] getChildren()
+    {
+        File[] files = _file.listFiles();
+        Resource[] resources = new Resource[files.length];
+        for (int i = 0; i < resources.length; i++)
+        {
+            resources[i] = new FileResource(files[i]);
+        }
+        return resources;
+    }
+
     public String getName()
     {
         return _file.getName();
         }
         return _file.lastModified() >= mod;
     }
+    
+    public long lastModified()
+    {
+        return _file.lastModified();
+    }
 }

File modules/lpc/source/java/parser/us/terebi/lang/lpc/io/NoSuchResource.java

  */
 public class NoSuchResource implements Resource
 {
+    private static final Resource[] NO_CHILDREN = new Resource[0];
+
     private final Resource _parent;
     private final String _name;
 
         return new NoSuchResource(this, name);
     }
 
+    public Resource[] getChildren()
+    {
+        return NO_CHILDREN;
+    }
+
     public String getName()
     {
         return _name;
         return false;
     }
 
+    public long lastModified()
+    {
+        return -1;
+    }
+
 }

File modules/lpc/source/java/parser/us/terebi/lang/lpc/io/Resource.java

  */
 public interface Resource
 {
+    public Resource getParent();
     public Resource getChild(String name);
-    public Resource getParent();
+    public Resource[] getChildren();
+
     public String getName();
     public String getPath();
     public String getParentName();
     public void delete() throws IOException;
     
     public boolean newerThan(long mod);
+    public long lastModified();
 }

File modules/lpc/source/java/parser/us/terebi/lang/lpc/parser/ast/ASTArgumentExpression.java

         }
         return 0;
     }
+
+    public boolean hasExpander()
+    {
+        return getArgumentType() == ParserConstants.EXPANDO;
+    }
 }

File modules/lpc/source/java/parser/us/terebi/lang/lpc/parser/ast/ASTFunctionArguments.java

     {
         return visitor.visit(this, data);
     }
+
+    public boolean hasExpander()
+    {
+        for (int i = 0; i < this.jjtGetNumChildren(); i++)
+        {
+            Node node = this.jjtGetChild(i);
+            if (node instanceof ASTArgumentExpression)
+            {
+                final ASTArgumentExpression arg = (ASTArgumentExpression) node;
+                if (arg.hasExpander())
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }

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

 import us.terebi.lang.lpc.runtime.LpcValue;
 import us.terebi.lang.lpc.runtime.ObjectDefinition;
 import us.terebi.lang.lpc.runtime.ObjectInstance;
+import us.terebi.lang.lpc.runtime.jvm.context.CallStack.Origin;
 import us.terebi.lang.lpc.runtime.jvm.exception.InternalError;
 import us.terebi.lang.lpc.runtime.jvm.exception.LpcRuntimeException;
 import us.terebi.lang.lpc.runtime.jvm.type.Types;
 import us.terebi.lang.lpc.runtime.jvm.value.MappingValue;
 import us.terebi.lang.lpc.runtime.jvm.value.NilValue;
 import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
+import us.terebi.lang.lpc.runtime.util.InContext;
 import us.terebi.lang.lpc.runtime.util.Signature;
+import us.terebi.lang.lpc.runtime.util.InContext.Exec;
 
 /**
  * 
         return execute(toArray(arguments));
     }
 
+    public LpcValue execute(final LpcValue... arguments)
+    {
+        return InContext.execute(Origin.POINTER, _owner, new Exec<LpcValue>()
+        {
+            public LpcValue execute()
+            {
+                return invoke(arguments);
+            }
+        });
+    }
+
+    protected abstract LpcValue invoke(LpcValue[] arguments);
+
     private LpcValue[] toArray(List< ? extends LpcValue> arguments)
     {
         return arguments.toArray(new LpcValue[arguments.size()]);

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

 import java.util.List;
 
 import us.terebi.lang.lpc.runtime.ObjectInstance;
+import us.terebi.lang.lpc.runtime.jvm.exception.InternalError;
 import us.terebi.util.collection.ArrayStack;
 import us.terebi.util.collection.Stack;
 
 
         public MajorFrame(Origin origin, ObjectInstance instance, int javaStackSize)
         {
+            if (instance == null)
+            {
+                throw new InternalError("Attempt to push frame (" + origin + ") with no object");
+            }
             this._origin = origin;
             this._instance = instance;
             this._javaStackSize = javaStackSize;

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/context/StartTime.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.context;
+
+/**
+ * 
+ */
+public class StartTime
+{
+    public final long time;
+
+    public StartTime()
+    {
+        time = System.currentTimeMillis();
+    }
+
+}

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

         _resourceFinder = resourceFinder;
         _lock = new Object();
         _attachments = new ObjectMap();
+        _attachments
+        .put(StartTime.class, new StartTime());
     }
 
     public ObjectMap attachments()

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/CtimeEfun.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.text.DateFormat;
-import java.util.Collections;
-import java.util.Date;
-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.StringValue;
-import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
-
-/**
- * 
- */
-public class CtimeEfun extends AbstractEfun implements FunctionSignature, Callable
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.singletonList(new ArgumentSpec("clock", Types.INT));
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.STRING;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        checkArguments(arguments);
-        LpcValue clock = arguments.get(0);
-        String ctime = DateFormat.getDateTimeInstance().format(new Date(clock.asLong() * 1000));
-        return new StringValue(ctime);
-    }
-}

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

-/* ------------------------------------------------------------------------
- * 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.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.support.ExecutionTimeCheck;
-import us.terebi.lang.lpc.runtime.jvm.support.ValueSupport;
-import us.terebi.lang.lpc.runtime.jvm.type.Types;
-
-/**
- * 
- */
-public class GetElapsedExecTimeEfun extends AbstractEfun implements Efun
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.emptyList();
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.INT;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        long t = ExecutionTimeCheck.get().getElapsedTime();
-        return ValueSupport.intValue(t);
-   }
-
-}

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

-/* ------------------------------------------------------------------------
- * 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.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.support.ExecutionTimeCheck;
-import us.terebi.lang.lpc.runtime.jvm.support.ValueSupport;
-import us.terebi.lang.lpc.runtime.jvm.type.Types;
-
-/**
- * 
- */
-public class GetMaxExecTimeEfun extends AbstractEfun implements Efun
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.emptyList();
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.INT;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        long t = ExecutionTimeCheck.get().getMaximumTime();
-        return ValueSupport.intValue(t);
-    }
-
-}

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/LocaltimeEfun.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.Calendar;
-import java.util.Collections;
-import java.util.GregorianCalendar;
-import java.util.List;
-import java.util.TimeZone;
-
-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.ArrayValue;
-import us.terebi.lang.lpc.runtime.jvm.value.IntValue;
-import us.terebi.lang.lpc.runtime.jvm.value.StringValue;
-import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
-
-/**
- * 
- */
-public class LocaltimeEfun extends AbstractEfun implements FunctionSignature, Callable
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.singletonList(new ArgumentSpec("clock", Types.INT));
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.MIXED_ARRAY;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        checkArguments(arguments);
-        LpcValue clock = arguments.get(0);
-        long time = clock.asLong() * 1000;
-
-        GregorianCalendar calendar = new GregorianCalendar();
-        calendar.setTimeInMillis(time);
-
-        List<LpcValue> array = new ArrayList<LpcValue>(10);
-        array.add(new IntValue(calendar.get(Calendar.SECOND)));
-        array.add(new IntValue(calendar.get(Calendar.MINUTE)));
-        array.add(new IntValue(calendar.get(Calendar.HOUR)));
-        array.add(new IntValue(calendar.get(Calendar.DAY_OF_MONTH)));
-        array.add(new IntValue(calendar.get(Calendar.MONTH)));
-        array.add(new IntValue(calendar.get(Calendar.YEAR) + 1900));
-        array.add(new IntValue(calendar.get(Calendar.DAY_OF_WEEK)));
-        array.add(new IntValue(calendar.get(Calendar.DAY_OF_YEAR)));
-        TimeZone timeZone = calendar.getTimeZone();
-        long offset = timeZone.getOffset(time) / 1000;
-        array.add(new IntValue(offset));
-        array.add(new StringValue(timeZone.getDisplayName()));
-        return new ArrayValue(Types.MIXED_ARRAY, array);
-    }
-}

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

-/* ------------------------------------------------------------------------
- * 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.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.support.ExecutionTimeCheck;
-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 SetMaxExecTimeEfun extends AbstractEfun implements Efun
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.singletonList(new ArgumentSpec("max", Types.INT));
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.VOID;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        checkArguments(arguments);
-        long t = arguments.get(0).asLong();
-        ExecutionTimeCheck.get().setMaximumTime(t);
-        return VoidValue.INSTANCE;
-    }
-
-}

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

 import java.util.Collections;
 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.FunctionSignature;
  */
 public class ThisObjectEfun extends AbstractEfun implements FunctionSignature, Callable
 {
+    private final static Logger LOG = Logger.getLogger(ThisObjectEfun.class);
+
     protected List< ? extends ArgumentDefinition> defineArguments()
     {
         return Collections.emptyList();
     {
         CallStack stack = context.callStack();
         ObjectInstance instance = stack.peekFrame(0).instance();
+        if (LOG.isDebugEnabled())
+        {
+            LOG.debug("this_object() : Stack = " + stack + " ; this_object = " + instance);
+        }
         return instance;
     }
 }

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/TimeEfun.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.Collections;
-import java.util.List;
-
-import us.terebi.lang.lpc.runtime.ArgumentDefinition;
-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.IntValue;
-
-/**
- * 
- */
-public class TimeEfun extends AbstractEfun implements FunctionSignature
-{
-    protected List< ? extends ArgumentDefinition> defineArguments()
-    {
-        return Collections.emptyList();
-    }
-
-    public LpcType getReturnType()
-    {
-        return Types.INT;
-    }
-
-    public LpcValue execute(List< ? extends LpcValue> arguments)
-    {
-        long currentTypeSeconds = System.currentTimeMillis() / 1000;
-        return new IntValue(currentTypeSeconds);
-    }
-
-}

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/VariablesEfun.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;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import us.terebi.lang.lpc.runtime.ArgumentDefinition;
+import us.terebi.lang.lpc.runtime.FieldDefinition;
+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.MemberDefinition.Modifier;
+import us.terebi.lang.lpc.runtime.jvm.type.Types;
+import us.terebi.lang.lpc.runtime.jvm.value.ArrayValue;
+import us.terebi.lang.lpc.runtime.jvm.value.StringValue;
+import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
+
+/**
+ * 
+ */
+public class VariablesEfun extends AbstractEfun implements Efun
+{
+    protected List< ? extends ArgumentDefinition> defineArguments()
+    {
+        return Arrays.asList( //
+                new ArgumentSpec("name", Types.STRING), //
+                new ArgumentSpec("flag", Types.INT) //
+        );
+    }
+
+    public LpcType getReturnType()
+    {
+        return Types.MIXED_ARRAY;
+    }
+
+    public boolean acceptsLessArguments()
+    {
+        return true;
+    }
+
+    public LpcValue execute(List< ? extends LpcValue> arguments)
+    {
+        checkArguments(arguments);
+
+        ObjectInstance object = arguments.get(0).asObject();
+        boolean flag = arguments.get(1).asBoolean();
+
+        Collection< ? extends FieldDefinition> fields = object.getDefinition().getFields().values();
+        List<LpcValue> result = new ArrayList<LpcValue>(fields.size());
+        for (FieldDefinition field : fields)
+        {
+            if (flag)
+            {
+                result.add(new ArrayValue(Types.STRING_ARRAY, new StringValue(field.getName()), new StringValue(describe(field.getType(),
+                        field.getModifiers()))));
+            }
+            else
+            {
+                result.add(new StringValue(field.getName()));
+            }
+        }
+        
+        return new ArrayValue(flag ? Types.STRING_ARRAY_ARRAY : Types.STRING_ARRAY, result);
+    }
+
+    private CharSequence describe(LpcType type, Set< ? extends Modifier> modifiers)
+    {
+        if (modifiers.isEmpty())
+        {
+            return type.toString();
+        }
+
+        final int capacity = (modifiers.size() + 1) * 8;
+        StringBuilder builder = new StringBuilder(capacity);
+        
+        for (Modifier modifier : modifiers)
+        {
+            builder.append(modifier.toString().toLowerCase());
+            builder.append(' ');
+        }
+        builder.append(type);
+        return builder;
+    }
+
+}

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

 
     public Resource getChild(String name)
     {
-        return new GameResource(_resource.getChild(name), _object, _efun);
+        return makeResource(_resource.getChild(name));
+    }
+
+    private GameResource makeResource(final Resource delegate)
+    {
+        return new GameResource(delegate, _object, _efun);
+    }
+
+    public Resource[] getChildren()
+    {
+        Resource[] delegate = _resource.getChildren();
+        Resource[] wrapped = new Resource[delegate.length];
+        for (int i = 0; i < wrapped.length; i++)
+        {
+            wrapped[i] = makeResource(delegate[i]);
+        }
+        return wrapped;
     }
 
     public Resource getParent()
     {
-        return new GameResource(_resource.getParent(), _object, _efun);
+        return makeResource(_resource.getParent());
     }
 
     public InputStream read() throws IOException
         return _resource.newerThan(mod);
     }
     
-    
+    public long lastModified()
+    {
+        checkReadAccess();
+        return _resource.lastModified();
+    }
+
 }

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

 
 package us.terebi.lang.lpc.runtime.jvm.efun.file;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOCase;
+import org.apache.log4j.Logger;
+
+import us.terebi.lang.lpc.io.Resource;
 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.efun.AbstractEfun;
+import us.terebi.lang.lpc.runtime.jvm.LpcConstants;
+import us.terebi.lang.lpc.runtime.jvm.support.ValueSupport;
 import us.terebi.lang.lpc.runtime.jvm.type.Types;
+import us.terebi.lang.lpc.runtime.jvm.value.ArrayValue;
+import us.terebi.lang.lpc.runtime.jvm.value.IntValue;
+import us.terebi.lang.lpc.runtime.jvm.value.StringValue;
 import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
 
 /**
  * 
  */
-public class GetDirectoryInfoEfun extends AbstractEfun implements FunctionSignature, Callable
+public class GetDirectoryInfoEfun extends FileEfun implements FunctionSignature, Callable
 {
+    private final Logger LOG = Logger.getLogger(GetDirectoryInfoEfun.class);
+
     //    mixed array get_dir(string dir);
     //
     //    mixed array get_dir(string dir, int flag);
 
     public LpcValue execute(List< ? extends LpcValue> arguments)
     {
-        /* @TODO : EFUN */
-       return null;
+        checkArguments(arguments);
+        String path = arguments.get(0).asString();
+        long flag = arguments.get(1).asLong();
+
+        try
+        {
+            return ValueSupport.arrayValue(getDirectoryInfo(path, flag));
+        }
+        catch (IOException e)
+        {
+            LOG.warn(e);
+            return LpcConstants.ARRAY.EMPTY;
+        }
     }
 
+    private List<LpcValue> getDirectoryInfo(String path, long flag) throws IOException
+    {
+        boolean listDirectory = path.endsWith("/");
+        boolean longListing = (flag == -1);
+
+        Resource[] files = resolveWildCard(path);
+        List<LpcValue> array = new ArrayList<LpcValue>(files.length);
+
+        for (Resource resource : files)
+        {
+            if (listDirectory)
+            {
+                if (!resource.isDirectory())
+                {
+                    continue;
+                }
+                for (Resource child : resource.getChildren())
+                {
+                    array.add(getInfo(child, longListing));
+                }
+            }
+            else
+            {
+                array.add(getInfo(resource, longListing));
+            }
+        }
+        
+        return array;
+    }
+
+    private LpcValue getInfo(Resource resource, boolean longListing)
+    {
+        if (longListing)
+        {
+            return new ArrayValue(Types.MIXED_ARRAY, //
+                    new StringValue(resource.getPath()), new IntValue(resource.getSizeInBytes()), new IntValue(resource.lastModified()));
+        }
+        return null;
+    }
+
+    private Resource[] resolveWildCard(String path) throws IOException
+    {
+        if (path.indexOf('*') == -1 && path.indexOf('?') == -1)
+        {
+            return new Resource[] { getResource(path) };
+        }
+
+        List<Resource> match = new ArrayList<Resource>();
+
+        int slash = path.lastIndexOf('/', path.length() - 1);
+        String parentPath = path.substring(0, slash);
+        String childPath = path.substring(slash);
+
+        Resource[] parents = resolveWildCard(parentPath);
+        for (Resource parent : parents)
+        {
+            Resource[] children = parent.getChildren();
+            for (Resource child : children)
+            {
+                if (FilenameUtils.wildcardMatch(child.getName(), childPath, IOCase.INSENSITIVE))
+                {
+                    match.add(child);
+                }
+            }
+        }
+
+        return match.toArray(new Resource[match.size()]);
+    }
 }

File modules/lpc/source/java/runtime/us/terebi/lang/lpc/runtime/jvm/efun/time/CtimeEfun.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.time;
+
+import java.text.DateFormat;
+import java.util.Collections;
+import java.util.Date;
+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.efun.AbstractEfun;
+import us.terebi.lang.lpc.runtime.jvm.type.Types;
+import us.terebi.lang.lpc.runtime.jvm.value.StringValue;
+import us.terebi.lang.lpc.runtime.util.ArgumentSpec;
+
+/**
+ * 
+ */
+public class CtimeEfun extends AbstractEfun implements FunctionSignature, Callable
+{
+    protected List< ? extends ArgumentDefinition> defineArguments()
+    {
+        return Collections.singletonList(new ArgumentSpec("clock", Types.INT));
+    }
+
+    public LpcType getReturnType()
+    {
+        return Types.STRING;
+    }
+
+    public LpcValue execute(List< ? extends LpcValue> arguments)
+    {
+        checkArguments(arguments);
+        LpcValue clock = arguments.get(0);
+        String ctime = DateFormat.getDateTimeInstance().format(new Date(clock.asLong() * 1000));
+        return new StringValue(ctime);
+    }
+}

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

+/* ------------------------------------------------------------------------
+ * 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.time;
+
+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.support.ExecutionTimeCheck;
+import us.terebi.lang.lpc.runtime.jvm.support.ValueSupport;
+import us.terebi.lang.lpc.runtime.jvm.type.Types;
+
+/**
+ * 
+ */
+public class GetElapsedExecTimeEfun extends AbstractEfun implements Efun
+{
+    protected List< ? extends ArgumentDefinition> defineArguments()
+    {
+        return Collections.emptyList();
+    }
+
+    public LpcType getReturnType()
+    {
+        return Types.INT;
+    }
+
+    public LpcValue execute(List< ? extends LpcValue> arguments)
+    {
+        long t = ExecutionTimeCheck.get().getElapsedTime();
+        return ValueSupport.intValue(t);
+   }
+
+}

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

+/* ------------------------------------------------------------------------