Commits

Tim Vernum committed ad8de57

Import from private branch (rev:b0417cd6fe9a)

Comments (0)

Files changed (141)

modules/engine/source/java/config/us/terebi/engine/config/AbstractConfig.java

 import java.util.HashSet;
 import java.util.Set;
 
+import us.terebi.lang.lpc.io.FileResource;
+import us.terebi.lang.lpc.io.Resource;
 import us.terebi.util.StringUtil;
 
 /**
 {
     private static final long[] EMPTY_LONG_ARRAY = new long[0];
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
-    private static final File[] EMPTY_PATH = new File[0];
+    private static final File[] EMPTY_FILE_PATH = new File[0];
+    private static final Resource[] EMPTY_RESOURCE_PATH = new Resource[0];
 
     private final Set<String> _trueValues;
     private final Set<String> _falseValues;
     {
         return getConfigValue(key) != null;
     }
-    
+
     private String getPath(File file)
     {
         try
 
     public File getFile(String key, FileType... allowedTypes)
     {
-        String value = getConfigValue(key);
-        if (value == null)
-        {
-            return null;
-        }
-        if ("".equals(value))
-        {
-            return null;
-        }
-        return resolveFile(key, value, null, allowedTypes);
+        return getFile(key, null, allowedTypes);
     }
 
     public File getFile(String key, File relativeTo, FileType... allowedTypes)
         return resolveFile(key, value, relativeTo, allowedTypes);
     }
 
-    public File[] getPath(String key, FileType... allowedTypes)
+    public Resource getResource(String key, FileType... allowedTypes)
     {
-        return getPath(key, null, allowedTypes);
+        return getResource(key, null, allowedTypes);
     }
 
-    public File[] getPath(String key, File relativeTo, FileType... allowedTypes)
+    public Resource getResource(String key, File relativeTo, FileType... allowedTypes)
     {
         String value = getConfigValue(key);
         if (value == null)
         {
-            return EMPTY_PATH;
+            return null;
         }
         if ("".equals(value))
         {
-            return EMPTY_PATH;
+            return null;
+        }
+        return resolveResource(key, value, relativeTo, allowedTypes);
+    }
+
+    public File[] getFilePath(String key, FileType... allowedTypes)
+    {
+        return getFilePath(key, null, allowedTypes);
+    }
+
+    public File[] getFilePath(String key, File relativeTo, FileType... allowedTypes)
+    {
+        String value = getConfigValue(key);
+        if (value == null)
+        {
+            return EMPTY_FILE_PATH;
+        }
+        if ("".equals(value))
+        {
+            return EMPTY_FILE_PATH;
         }
         String[] parts = value.split(":");
         File[] path = new File[parts.length];
         return path;
     }
 
+    public Resource[] getResourcePath(String key, FileType... allowedTypes)
+    {
+        return getResourcePath(key, null, allowedTypes);
+    }
+
+    public Resource[] getResourcePath(String key, File relativeTo, FileType... allowedTypes)
+    {
+        String value = getConfigValue(key);
+        if (value == null)
+        {
+            return EMPTY_RESOURCE_PATH;
+        }
+        if ("".equals(value))
+        {
+            return EMPTY_RESOURCE_PATH;
+        }
+        String[] parts = value.split(":");
+        Resource[] path = new Resource[parts.length];
+        for (int i = 0; i < path.length; i++)
+        {
+            path[i] = resolveResource(key, parts[i], relativeTo, allowedTypes);
+        }
+        return path;
+    }
+
+    protected Resource resolveResource(String key, String name, File relativeTo, FileType... allowedArray)
+    {
+        File file = resolveFile(key, name, relativeTo, allowedArray);
+        return new FileResource(file, name);
+    }
+
     protected File resolveFile(String key, String name, File relativeTo, FileType... allowedArray)
     {
         File file;

modules/engine/source/java/config/us/terebi/engine/config/Config.java

 
 import java.io.File;
 
+import us.terebi.lang.lpc.io.Resource;
+
 /**
  * @author <a href="http://blog.adjective.org/">Tim Vernum</a>
  */
     
     public File getFile(String key, FileType... allowedTypes);
     public File getFile(String key, File relativeTo, FileType... allowedTypes);
+
+    public Resource getResource(String key, FileType... allowedTypes);
+    public Resource getResource(String key, File relativeTo, FileType... allowedTypes);
     
-    public File[] getPath(String key, FileType... allowedTypes);
-    public File[] getPath(String key, File relativeTo, FileType... allowedTypes);
+    public File[] getFilePath(String key, FileType... allowedTypes);
+    public File[] getFilePath(String key, File relativeTo, FileType... allowedTypes);
+
+    public Resource[] getResourcePath(String key, FileType... allowedTypes);
+    public Resource[] getResourcePath(String key, File relativeTo, FileType... allowedTypes);
 }

modules/engine/source/java/objects/us/terebi/engine/objects/CompileOptions.java

 
 import us.terebi.engine.config.Config;
 import us.terebi.engine.config.ConfigNames;
+import us.terebi.lang.lpc.io.Resource;
 
 /**
  * @author <a href="http://blog.adjective.org/">Tim Vernum</a>
     private final File _javaOutputDirectory;
     private final List<Pattern> _debugPatterns;
 
-    private final File[] _includeDirectories;
-    private final File[] _autoIncludeFiles;
+    private final Resource[] _includeDirectories;
+    private final Resource[] _autoIncludeFiles;
 
     private final Map<String, String> _preprocessorDefinitions;
 
     {
         this( //
                 config.getFile(ConfigNames.COMPILE_OUTPUT, Config.FileType.EXISTING_DIRECTORY), //
-                config.getPath(ConfigNames.COMPILE_INCLUDE_DIRECTORIES, mudlib.root(), Config.FileType.EXISTING_DIRECTORY), //
-                config.getPath(ConfigNames.COMPILE_AUTO_INCLUDE, mudlib.root(), Config.FileType.EXISTING_FILE), //
+                config.getResourcePath(ConfigNames.COMPILE_INCLUDE_DIRECTORIES, mudlib.root(), Config.FileType.EXISTING_DIRECTORY), //
+                config.getResourcePath(ConfigNames.COMPILE_AUTO_INCLUDE, mudlib.root(), Config.FileType.EXISTING_FILE), //
                 config.getStrings(ConfigNames.COMPILE_DEBUG) //        
         );
 
     }
 
-    public CompileOptions(File javaOutputDirectory, File[] include, File[] autoInclude, String[] debugPatterns)
+    public CompileOptions(File javaOutputDirectory, Resource[] include, Resource[] autoInclude, String[] debugPatterns)
     {
         _javaOutputDirectory = javaOutputDirectory;
         _includeDirectories = include;
         return _javaOutputDirectory;
     }
 
-    public File[] includeDirectories()
+    public Resource[] includeDirectories()
     {
         return _includeDirectories;
     }
 
-    public File[] autoIncludeFiles()
+    public Resource[] autoIncludeFiles()
     {
         return _autoIncludeFiles;
     }

modules/engine/source/java/objects/us/terebi/engine/objects/EngineInitialiser.java

 import us.terebi.lang.lpc.compiler.CompilerObjectManager;
 import us.terebi.lang.lpc.compiler.ObjectBuilder;
 import us.terebi.lang.lpc.compiler.ObjectBuilderFactory;
+import us.terebi.lang.lpc.compiler.bytecode.context.DebugOptions;
 import us.terebi.lang.lpc.io.FileFinder;
+import us.terebi.lang.lpc.io.Resource;
 import us.terebi.lang.lpc.io.ResourceFinder;
 import us.terebi.lang.lpc.parser.LpcParser;
 import us.terebi.lang.lpc.runtime.ObjectDefinition;
         LpcParser parser = new LpcParser();
         FileFinder fileFinder = new FileFinder(_mudlib.root());
         parser.setSourceFinder(fileFinder);
-        for (File dir : _compileOptions.includeDirectories())
+        for (Resource dir : _compileOptions.includeDirectories())
         {
             parser.addSystemIncludeDirectory(dir);
         }
-        for (File auto : _compileOptions.autoIncludeFiles())
+        for (Resource auto : _compileOptions.autoIncludeFiles())
         {
             parser.addAutoIncludeFile(auto);
         }
         ObjectBuilderFactory factory = new ObjectBuilderFactory(efuns);
         factory.setWorkingDir(_compileOptions.compilerOutputDirectory());
         factory.setParser(parser);
-        factory.setDebugPatterns(_compileOptions.getDebugPatterns());
+        factory.setDebugOptions(new DebugOptions(_compileOptions.getDebugPatterns()));
         ObjectBuilder builder = factory.createBuilder(fileFinder);
 
         CompilerObjectManager objectManager = builder.getObjectManager();

modules/engine/source/java/plugin/us/terebi/engine/plugin/AbstractPlugin.java

 
 package us.terebi.engine.plugin;
 
+import java.util.Properties;
+
 import us.terebi.engine.config.Config;
 import us.terebi.lang.lpc.runtime.jvm.context.SystemContext;
 
         super();
     }
 
-    public void load(Config config, SystemContext context)
+    public void load(Config config, SystemContext context, Properties properties)
     {
         // No-op
     }

modules/engine/source/java/plugin/us/terebi/engine/plugin/Plugin.java

 
 package us.terebi.engine.plugin;
 
+import java.util.Properties;
+
 import us.terebi.engine.config.Config;
 import us.terebi.lang.lpc.runtime.jvm.context.SystemContext;
 
      * The provided {@link SystemContext} will have efuns, and some attachments (such as {@link us.terebi.engine.objects.CompileOptions},
      * but will not have an object manager or master/simul-efun objects.
      * This is the appropriate place to configure new efuns (so they can be used in the master object) and new preprocessor directives
+     * @param properties @TODO
      */
-    public void load(Config config, SystemContext context);
+    public void load(Config config, SystemContext context, Properties properties);
 
     /**
      * Called during the initialisation process, after the object manager is loaded, but before the master object and simul-efun objects are loaded

modules/engine/source/java/plugin/us/terebi/engine/plugin/PluginResolver.java

         {
             return;
         }
-        _plugin.load(config, context);
+        _plugin.load(config, context, _config.getProperties());
     }
 
     private void create(ClassLoader classLoader)

modules/engine/source/java/plugin/us/terebi/engine/plugin/PluginSpec.java

     {
         return _name + " (" + IOUtil.canonicalPath(_file) + ")";
     }
+    
+    public Properties getProperties()
+    {
+        return _properties;
+    }
 }

modules/lib.ds/etc/log4j.xml

 
 <log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
 
-    <!-- TODO : Log to a file -->
-
     <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
         <layout class="org.apache.log4j.PatternLayout"> 
           <param name="ConversionPattern" value="%d [%t] %-5p %c {%x} - %m%n"/> 
 
     <appender name="DEBUG_FILE" class="org.apache.log4j.RollingFileAppender"> 
         <param name="file" value="debug.log"/>
-        <param name="MaxFileSize" value="25KB"/>
+        <param name="MaxFileSize" value="100KB"/>
         <param name="MaxBackupIndex" value="9"/>
         <layout class="org.apache.log4j.PatternLayout"> 
           <param name="ConversionPattern" value="%d [%t] %-5p %c {%x} - %m%n"/> 

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/CompileException.java

     }
 
 
+    public CompileException(CompileException cause, String location)
+    {
+        super(cause, location);
+        _token = cause.getToken();
+    }
+
     public Token getToken()
     {
         return _token;

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

 
     public CompiledObjectDefinition compile(Resource resource)
     {
-        LogContext lc = new LogContext(resource);
+        LogContext lc = new LogContext(resource.getPath());
         try
         {
             if (LOG.isDebugEnabled())
         ASTObjectDefinition ast = null;
         if (resource.newerThan(mod))
         {
-            LOG.info("Compiling " + resource + " to bytecode (" + name + ")");
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("Compiling " + resource + " to bytecode (" + name + ")");
+            }
             ast = compile(resource, name);
         }
         else
         {
-            LOG.info("Bytecode (" + name + ") for " + resource + " is up to date");
+            if (LOG.isDebugEnabled())
+            {
+                LOG.debug("Bytecode (" + name + ") for " + resource + " is up to date");
+            }
         }
 
         Class< ? extends LpcObject> cls = loadClass(ast, name);
         }
         catch (LpcRuntimeException e)
         {
-            throw new InternalError("While compiling " + resource, e);
+            throw new InternalError("While compiling " + resource + " - " + e.getMessage(), e);
         }
         return ast;
     }

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/ObjectBuilderFactory.java

 
 import java.io.File;
 import java.io.IOException;
-import java.util.List;
-import java.util.regex.Pattern;
 
 import us.terebi.lang.lpc.compiler.bytecode.ByteCodeCompiler;
+import us.terebi.lang.lpc.compiler.bytecode.context.DebugOptions;
 import us.terebi.lang.lpc.compiler.java.context.BasicScopeLookup;
 import us.terebi.lang.lpc.compiler.java.context.LpcCompilerObjectManager;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
     private CompilerObjectManager _manager;
     private LpcParser _parser;
     private File _workingDir;
-    private List<Pattern> _debugPatterns;
+    private DebugOptions _debug;
     private boolean _insertTimeCheck;
 
     public ObjectBuilderFactory(Efuns efuns) throws IOException
         {
             _manager = new LpcCompilerObjectManager();
         }
-        Compiler javaCompiler = new ByteCodeCompiler(_manager, _efuns, _debugPatterns, _insertTimeCheck);
+        Compiler javaCompiler = new ByteCodeCompiler(_manager, _efuns, _debug, _insertTimeCheck);
         ScopeLookup scope = new BasicScopeLookup(_manager);
         ObjectBuilder builder = new ObjectBuilder(finder, _manager, scope, _parser, javaCompiler, _workingDir);
         for (Object object : asList(_manager, _parser, _efuns, finder))
         }
     }
 
-    public void setDebugPatterns(List<Pattern> debugPatterns)
+    public void setDebugOptions(DebugOptions debugOptions)
     {
-        _debugPatterns = debugPatterns;
+        _debug = debugOptions;
     }
     
     public void setInsertTimeCheck(boolean insertTimeCheck)

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/ByteCodeCompiler.java

 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.util.List;
-import java.util.regex.Pattern;
 
 import org.adjective.stout.builder.ClassSpec;
 import org.adjective.stout.core.ClassDescriptor;
 import us.terebi.lang.lpc.compiler.Compiler;
 import us.terebi.lang.lpc.compiler.CompilerObjectManager;
 import us.terebi.lang.lpc.compiler.ObjectSource;
+import us.terebi.lang.lpc.compiler.bytecode.context.CompileContext;
+import us.terebi.lang.lpc.compiler.bytecode.context.CompileSettings;
+import us.terebi.lang.lpc.compiler.bytecode.context.CompilerState;
+import us.terebi.lang.lpc.compiler.bytecode.context.DebugOptions;
 import us.terebi.lang.lpc.compiler.java.context.BasicScopeLookup;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
 import us.terebi.lang.lpc.parser.LineMapping;
 {
     private final CompilerObjectManager _objectManager;
     private final Efuns _efuns;
-    private final List<Pattern> _debugPatterns;
+    private final DebugOptions _debug;
     private final boolean _insertTimeCheck;
 
-    public ByteCodeCompiler(CompilerObjectManager objectManager, Efuns efuns, List<Pattern> debugPatterns, boolean insertTimeCheck)
+    public ByteCodeCompiler(CompilerObjectManager objectManager, Efuns efuns, DebugOptions debug, boolean insertTimeCheck)
     {
         _objectManager = objectManager;
         _efuns = efuns;
-        _debugPatterns = debugPatterns;
+        _debug = debug;
         _insertTimeCheck = insertTimeCheck;
     }
 
         ClassSpec spec = ClassSpec.newClass(name.packageName, name.className).withSuperClass(LpcObject.class).withModifiers(ElementModifier.PUBLIC);
         spec.withSourceCode(source.getFilename());
         ASTObjectDefinition ast = source.getSyntaxTree();
-        CompileContext context = new CompileContext(store, new CompileOptions(), ast, spec, lineMapping, _debugPatterns, _insertTimeCheck);
+        CompileSettings settings = new CompileSettings(store, new CompileOptions(), ast, spec, lineMapping, _debug, _insertTimeCheck);
 
+        CompileContext context = CompilerState.root(settings);
+        
         compile(context, spec);
         store(spec, context);
     }
 
     public static ClassDescriptor store(ClassSpec spec, CompileContext context) throws IOException
     {
-        return store(spec, context.store(), context.getDebugPatterns(), context.isTimeCheckEnabled());
+        return store(spec, context.store(), context.debugOptions(), context.isTimeCheckEnabled());
     }
 
-    public static ClassDescriptor store(ClassSpec spec, ClassStore store, List<Pattern> debugPatterns, boolean execTimeCheck) throws IOException
+    public static ClassDescriptor store(ClassSpec spec, ClassStore store, DebugOptions debugOptions, boolean execTimeCheck) throws IOException
     {
         ClassDescriptor cls = spec.create();
-        ByteCodeWriter writer = new LpcByteCodeWriter(debugPatterns, execTimeCheck);
+        ByteCodeWriter writer = new LpcByteCodeWriter(debugOptions, execTimeCheck);
         byte[] bytes = writer.write(cls);
         OutputStream stream = store.open(cls.getPackage(), cls.getName());
         stream.write(bytes);

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/ByteCodeConstants.java

 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 import org.adjective.stout.core.ConstructorSignature;
 
     public static final MethodSignature AS_LONG = VM.Method.find(LpcValue.class, "asLong");
     public static final MethodSignature AS_DOUBLE = VM.Method.find(LpcValue.class, "asDouble");
+    public static final MethodSignature AS_LIST = VM.Method.find(LpcValue.class, "asList");
+
+    public static final ParameterisedClass COLLECTIONS = new ParameterisedClassImpl(Collections.class);
+    public static final ParameterisedClass LIST = new ParameterisedClassImpl(List.class);
+    public static final ParameterisedClass COLLECTION = new ParameterisedClassImpl(Collection.class);
+    public static final MethodSignature COLLECTION_SIZE = VM.Method.find(Collection.class, "size");
 }

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

 import org.adjective.stout.operation.VM;
 
 import us.terebi.lang.lpc.compiler.CompileException;
+import us.terebi.lang.lpc.compiler.bytecode.context.CompileContext;
 import us.terebi.lang.lpc.compiler.java.context.CompiledObjectDefinition;
 import us.terebi.lang.lpc.compiler.java.context.FunctionLookup;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
         _scope = scope;
         _spec = spec;
         _interface = ClassSpec.newInterface(_spec.getPackage(), _spec.getName() + "$I").withModifiers(ElementModifier.PUBLIC);
-        _declarationVisitor = new DelegatingDeclarationVisitor(new ClassCompiler(_scope, context), new FieldCompiler(_scope, context),
-                new MethodCompiler(_scope, context));
+        _declarationVisitor = new DelegatingDeclarationVisitor(//
+                new ClassCompiler(_scope, context), new FieldCompiler(_scope, context), new MethodCompiler(_scope, context));
         _initialisers = new ArrayList<Statement>();
     }
 
                         + key.argumentCount);
             }
             MethodSpec method = new MethodSpec(key.name);
-            
+
             method.withModifiers(ElementModifier.PUBLIC, ElementModifier.FINAL, ElementModifier.SYNTHETIC);
             method.withAnnotation(new AnnotationSpec(Dispatch.class));
             method.withReturnType(ByteCodeConstants.LPC_VALUE);

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/ClassCompiler.java

 
 import us.terebi.lang.lpc.compiler.CompileException;
 import us.terebi.lang.lpc.compiler.bytecode.FieldCompiler.FieldDescriptor;
+import us.terebi.lang.lpc.compiler.bytecode.context.CompileContext;
 import us.terebi.lang.lpc.compiler.java.CompileTimeField;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
 import us.terebi.lang.lpc.compiler.util.MemberVisitor;
         ClassSpec spec = ClassSpec.newClass(_context.publicClass().getPackage(), internalName);
         _context.pushClass(spec);
 
-        DynamicClassDefinition classDefinition = new CompiledClassDefinition(lpcName, getModifiers(MemberDefinition.Kind.CLASS), spec);
+        DynamicClassDefinition classDefinition = new CompiledClassDefinition(lpcName, spec);
 
         spec.withModifiers(ElementModifier.PUBLIC, ElementModifier.FINAL);
         spec.withSuperClass(LpcClass.class);
         AnnotationSpec annotation = new AnnotationSpec(LpcMember.class);
         annotation.withRuntimeVisibility(true);
         annotation.withAttribute("name", lpcName);
-        Set< ? extends Modifier> modifiers = classDefinition.getModifiers();
-        annotation.withAttribute("modifiers", modifiers.toArray(new MemberDefinition.Modifier[modifiers.size()]));
+        annotation.withAttribute("modifiers", new MemberDefinition.Modifier[0]);
         spec.withAnnotation(annotation);
 
         Set<FieldDescriptor> allFields = new HashSet<FieldDescriptor>();
         {
             throw new CompileException("Cannot write class file " + spec, e);
         }
-        
+
         _context.popClass(spec);
 
         return null;

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/CompileContext.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.compiler.bytecode;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-import org.adjective.stout.builder.ClassSpec;
-
-import us.terebi.lang.lpc.compiler.ClassStore;
-import us.terebi.lang.lpc.parser.LineMapping;
-import us.terebi.lang.lpc.parser.ast.ASTObjectDefinition;
-import us.terebi.util.collection.ArrayStack;
-import us.terebi.util.collection.Stack;
-
-/**
- * 
- */
-public class CompileContext
-{
-    private final ClassStore _store;
-    private final CompileOptions _options;
-    private final ASTObjectDefinition _tree;
-    private final ClassSpec _publicClass;
-    private final Stack<ClassSpec> _classes;
-    private final LineMapping _lineMapping;
-    private final List<Pattern> _debugPatterns;
-    private final boolean _timeCheck;
-
-    public CompileContext(ClassStore store, CompileOptions options, ASTObjectDefinition tree, ClassSpec classSpec, LineMapping lineMapping,
-            List<Pattern> debugPatterns, boolean timeCheck)
-    {
-        _store = store;
-        _options = options;
-        _tree = tree;
-        _publicClass = classSpec;
-        _lineMapping = lineMapping;
-        _debugPatterns = debugPatterns;
-        _timeCheck = timeCheck;
-        _classes = new ArrayStack<ClassSpec>();
-        _classes.push(classSpec);
-    }
-
-    public ClassStore store()
-    {
-        return _store;
-    }
-
-    public CompileOptions options()
-    {
-        return _options;
-    }
-
-    public ASTObjectDefinition tree()
-    {
-        return _tree;
-    }
-
-    public ClassSpec publicClass()
-    {
-        return _publicClass;
-    }
-
-    public ClassSpec currentClass()
-    {
-        return _classes.peek();
-    }
-
-    public void pushClass(ClassSpec spec)
-    {
-        _classes.push(spec);
-    }
-
-    public void popClass(ClassSpec spec)
-    {
-        ClassSpec pop = _classes.pop();
-        assert pop == spec;
-    }
-
-    public LineMapping getLineMapping()
-    {
-        return _lineMapping;
-    }
-
-    public List<Pattern> getDebugPatterns()
-    {
-        return _debugPatterns;
-    }
-
-    public boolean isTimeCheckEnabled()
-    {
-        return _timeCheck;
-    }
-}

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/CompiledClassDefinition.java

 
 package us.terebi.lang.lpc.compiler.bytecode;
 
-import java.util.Set;
-
 import org.adjective.stout.core.UnresolvedType;
 
 import us.terebi.lang.lpc.runtime.util.type.DynamicClassDefinition;
 {
     private final UnresolvedType _implementation;
 
-    public CompiledClassDefinition(String name, Set< ? extends Modifier> modifiers, UnresolvedType implementation)
+    public CompiledClassDefinition(String name, UnresolvedType implementation)
     {
-        super(name, modifiers);
+        super(name);
         _implementation = implementation;
     }
     

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/ExpressionCompiler.java

 import org.adjective.stout.core.Parameter;
 import org.adjective.stout.impl.MethodSignatureImpl;
 import org.adjective.stout.loop.Condition;
+import org.adjective.stout.operation.CreateArrayExpression;
 import org.adjective.stout.operation.EmptyExpression;
 import org.adjective.stout.operation.Expression;
 import org.adjective.stout.operation.LineNumberExpression;
 
 import us.terebi.lang.lpc.compiler.CompileException;
 import us.terebi.lang.lpc.compiler.bytecode.FunctionCallCompiler.FunctionArgument;
+import us.terebi.lang.lpc.compiler.bytecode.context.CompileContext;
+import us.terebi.lang.lpc.compiler.bytecode.stout.LogicalAndExpression;
+import us.terebi.lang.lpc.compiler.bytecode.stout.LogicalOrExpression;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
 import us.terebi.lang.lpc.compiler.java.context.FunctionLookup.FunctionReference;
 import us.terebi.lang.lpc.compiler.java.context.VariableResolver.VariableResolution;
 import us.terebi.lang.lpc.parser.ast.ASTComparisonExpression;
 import us.terebi.lang.lpc.parser.ast.ASTCompoundExpression;
 import us.terebi.lang.lpc.parser.ast.ASTConstant;
+import us.terebi.lang.lpc.parser.ast.ASTElementExpander;
 import us.terebi.lang.lpc.parser.ast.ASTExclusiveOrExpression;
 import us.terebi.lang.lpc.parser.ast.ASTExpressionCall;
 import us.terebi.lang.lpc.parser.ast.ASTFullType;
 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.jvm.LpcConstants;
 import us.terebi.lang.lpc.runtime.jvm.LpcFunction;
 import us.terebi.lang.lpc.runtime.jvm.LpcObject;
 import us.terebi.lang.lpc.runtime.jvm.LpcReference;
         {
             return lpcExpr;
         }
-        int line = _context.getLineMapping().getLine(token.beginLine);
+        int line = _context.lineMapping().getLine(token.beginLine);
         return new LpcExpression(lpcExpr.type, new LineNumberExpression(lpcExpr.expression, line), lpcExpr.reference);
     }
 
         return new LpcExpression(type, expr);
     }
 
+    private LpcExpression zero()
+    {
+        Expression zero = VM.Expression.getStaticField(LpcConstants.MIXED.class, "ZERO", LpcValue.class);
+        return expression(zero, Types.MIXED);
+    }
+
     public void precompile(ExpressionNode node, LpcExpression expression)
     {
         _precompile.put(node, expression);
         else if (constant instanceof Integer)
         {
             int i = ((Number) constant).intValue();
-            return expression(makeValue(Integer.TYPE, VM.Expression.constant(i)), (i == 0 ? Types.MIXED : Types.INT));
+            if (i == 0)
+            {
+                return zero();
+            }
+            return expression(makeValue(Integer.TYPE, VM.Expression.constant(i)), Types.INT);
         }
-        else if ((constant instanceof Number))
+        if ((constant instanceof Number))
         {
             long l = ((Number) constant).longValue();
-            return expression(makeValue(Long.TYPE, VM.Expression.constant(l)), (l == 0 ? Types.MIXED : Types.INT));
+            if (l == 0)
+            {
+                return zero();
+            }
+            return expression(makeValue(Long.TYPE, VM.Expression.constant(l)), Types.INT);
         }
         else if (constant instanceof Character)
         {
         return VM.Expression.construct(STRING_VALUE_CONSTRUCTOR, javaString);
     }
 
-    public Object visit(ASTArrayLiteral node, Object data)
+    public LpcExpression visit(ASTArrayLiteral node, Object data)
     {
         Expression[] elements = new Expression[node.jjtGetNumChildren()];
+        boolean needsExpand = ASTUtil.hasDescendant(ASTElementExpander.class, node);
+
         int i = 0;
         LpcType elementType = null;
         for (TokenNode child : ASTUtil.children(node))
         {
-            LpcExpression expr = (LpcExpression) child.jjtAccept(this, data);
+            assert child instanceof ASTArrayElement;
+            ASTArrayElement element = (ASTArrayElement) child;
+            LpcExpression expr = this.compile(element.jjtGetChild(0));
             elements[i] = getValue(expr);
+            if (needsExpand)
+            {
+                if (element.jjtGetNumChildren() == 2)
+                {
+                    elements[i] = VM.Expression.callMethod(elements[i], LPC_VALUE, ByteCodeConstants.AS_LIST);
+                }
+                else
+                {
+                    elements[i] = VM.Expression.callStatic(ByteCodeConstants.COLLECTIONS, ByteCodeConstants.SINGLETON_LIST, elements[i]);
+                }
+            }
+
             if (elementType == null)
             {
                 elementType = expr.type;
             elementType = Types.MIXED;
         }
 
-        Expression array = VM.Expression.array(LpcValue.class, elements);
-        MethodSignature makeArray = VM.Method.find(LpcObject.class, "makeArray", LpcValue[].class);
+        Expression array = new CreateArrayExpression( needsExpand ? ByteCodeConstants.LIST : ByteCodeConstants.LPC_VALUE, elements);
+
+        MethodSignature makeArray = needsExpand //
+        ? VM.Method.find(LpcObject.class, "makeArray", List[].class)
+                : VM.Method.find(LpcObject.class, "makeArray", LpcValue[].class);
+
         Expression result = VM.Expression.callInherited(makeArray, array);
         return expression(result, Types.arrayOf(elementType));
     }
 
     public LpcExpression visit(ASTArrayElement node, Object data)
     {
-        if (node.jjtGetNumChildren() == 2)
-        {
-            // @TODO expando...
-        }
-        return compile(node.jjtGetChild(0));
+        throw new UnsupportedOperationException("Cannot visit " + node);
     }
 
     public Object visit(ASTMappingLiteral node, Object data)
     public Object visit(ASTCompoundExpression node, Object data)
     {
         LpcExpression var = null;
-        List<ElementBuilder<? extends Statement>> statements = new ArrayList<ElementBuilder<? extends Statement>>();
+        List<ElementBuilder< ? extends Statement>> statements = new ArrayList<ElementBuilder< ? extends Statement>>();
         for (TokenNode child : ASTUtil.children(node))
         {
-            if(var != null) {
+            if (var != null)
+            {
                 statements.add(VM.Statement.ignore(getValue(var)));
             }
             var = compile(child);

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

 import org.adjective.stout.operation.VM;
 
 import us.terebi.lang.lpc.compiler.CompileException;
+import us.terebi.lang.lpc.compiler.bytecode.context.CompileContext;
 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;
 
             FieldCompiler.addField(classSpec, field);
 
-            statements.add(FieldCompiler.initialiseLpcField(field, EnclosingType.OBJECT).create());
+            statements.add(initialiseLpcField(field, EnclosingType.OBJECT).create());
         }
 
         return statements;
         if (assignment != null)
         {
             ExpressionCompiler compiler = new ExpressionCompiler(scope, context);
-            init = ExpressionCompiler.getValue(compiler.compile(assignment));
+            LpcExpression expr = compiler.compile(assignment);
+            TypeSupport.checkType(node, expr.type, type);
+            init = ExpressionCompiler.getValue(expr);
         }
         return new FieldDescriptor(node.getVariableName(), type, modifiers, init);
     }

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

 import org.adjective.stout.operation.VM;
 
 import us.terebi.lang.lpc.compiler.CompileException;
+import us.terebi.lang.lpc.compiler.bytecode.context.CompileContext;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
 import us.terebi.lang.lpc.compiler.java.context.FunctionLookup.FunctionReference;
 import us.terebi.lang.lpc.compiler.java.context.VariableLookup.ObjectPath;
 import us.terebi.lang.lpc.compiler.util.FunctionCallSupport;
+import us.terebi.lang.lpc.compiler.util.TypeSupport;
 import us.terebi.lang.lpc.compiler.util.FunctionCallSupport.ArgumentData;
 import us.terebi.lang.lpc.parser.ast.ASTArgumentExpression;
 import us.terebi.lang.lpc.parser.ast.ASTFunctionArguments;
 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;
 import us.terebi.lang.lpc.runtime.Callable;
 import us.terebi.lang.lpc.runtime.ClassDefinition;
+import us.terebi.lang.lpc.runtime.LpcType;
 import us.terebi.lang.lpc.runtime.LpcValue;
 import us.terebi.lang.lpc.runtime.MemberDefinition.Modifier;
 import us.terebi.lang.lpc.runtime.jvm.LpcObject;
 
     public static boolean requiresDispatch(Set< ? extends Modifier> modifiers)
     {
-        if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.NOMASK))
+        if (modifiers.contains(Modifier.PRIVATE))
         {
             return false;
         }
                             + " to "
                             + data.function.name);
                 }
-                return new FunctionArgument(compileExpression(node.jjtGetChild(0)), false, true);
+                return new FunctionArgument(compileExpandoArg(node), false, true);
             default:
                 if (data.definition.getSemantics() == ArgumentSemantics.IMPLICIT_REFERENCE)
                 {
                     return new FunctionArgument(compileRef(node, data), true, false);
                 }
-                return new FunctionArgument(compileExpression(node.jjtGetChild(0)), false, false);
+                return new FunctionArgument(compileSimpleArg(node, data), false, false);
         }
     }
 
+    private LpcExpression compileExpandoArg(ASTArgumentExpression node)
+    {
+        // @TODO Check type
+        return compileExpression(node.jjtGetChild(0));
+    }
+
+    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);
+        return expr;
+    }
+
     private LpcExpression compileRef(ASTArgumentExpression node, ArgumentData data)
     {
         if (data.definition.getSemantics() == ArgumentSemantics.BY_VALUE)

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

 import org.adjective.stout.operation.VM;
 
 import us.terebi.lang.lpc.compiler.CompileException;
+import us.terebi.lang.lpc.compiler.bytecode.context.CompileContext;
 import us.terebi.lang.lpc.compiler.java.context.LookupException;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
 import us.terebi.lang.lpc.compiler.java.context.VariableResolver;
     public FunctionLiteralCompiler(ScopeLookup parentScope, CompileContext context)
     {
         _parentScope = parentScope;
-        _context = context;
+        _context = context.enterFunctionLiteral();
         _scope = new InnerClassScopeLookup(parentScope, context.publicClass());
     }
 
         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());
         Map<String, VariableResolution> variables = getReferencedVariables(vars, spec, parameters);
 
         MethodSpec constructor = getBlockConstructor(parameters, immediates, argumentDefinitions);
         spec.withMethod(constructor);
 
+        _scope.variables().pushScope();
         MethodSpec execute = getBlockExecute(blockNode, argumentDefinitions, compiler);
+        _scope.variables().popScope();
+        
         spec.withMethod(execute);
-
         store(spec);
 
         Expression[] args = new Expression[parameters.size()];

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/LogicalAndExpression.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.compiler.bytecode;
-
-import org.objectweb.asm.Label;
-import org.objectweb.asm.Opcodes;
-
-import org.adjective.stout.core.ExecutionStack;
-import org.adjective.stout.core.InstructionCollector;
-import org.adjective.stout.core.UnresolvedType;
-import org.adjective.stout.instruction.GenericInstruction;
-import org.adjective.stout.instruction.LabelInstruction;
-import org.adjective.stout.loop.ExpressionCondition;
-import org.adjective.stout.operation.DuplicateStackExpression;
-import org.adjective.stout.operation.Expression;
-
-/**
- * 
- */
-class LogicalAndExpression implements Expression
-{
-    private final Expression[] _branches;
-
-    public LogicalAndExpression(Expression[] branches)
-    {
-        _branches = branches;
-    }
-
-    public UnresolvedType getExpressionType(ExecutionStack stack)
-    {
-        return ByteCodeConstants.LPC_VALUE;
-    }
-
-    public void getInstructions(ExecutionStack stack, InstructionCollector collector)
-    {
-        Label end = new Label();
-        DuplicateStackExpression dup = new DuplicateStackExpression();
-        GenericInstruction pop = new GenericInstruction(Opcodes.POP);
-
-        for (int i = 0; i < _branches.length - 1; i++)
-        {
-            Expression branch = _branches[i];
-            branch.getInstructions(stack, collector);
-            new ExpressionCondition(ExpressionCompiler.toBoolean(dup)).jumpWhenFalse(end).getInstructions(stack, collector);
-            pop.getInstructions(stack, collector);
-        }
-
-        _branches[_branches.length - 1].getInstructions(stack, collector);
-        new LabelInstruction(end).getInstructions(stack, collector);
-    }
-
-}

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/LogicalOrExpression.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.compiler.bytecode;
-
-import org.objectweb.asm.Label;
-import org.objectweb.asm.Opcodes;
-
-import org.adjective.stout.core.ExecutionStack;
-import org.adjective.stout.core.InstructionCollector;
-import org.adjective.stout.core.UnresolvedType;
-import org.adjective.stout.instruction.GenericInstruction;
-import org.adjective.stout.instruction.LabelInstruction;
-import org.adjective.stout.loop.ExpressionCondition;
-import org.adjective.stout.operation.DuplicateStackExpression;
-import org.adjective.stout.operation.Expression;
-
-/**
- * 
- */
-class LogicalOrExpression implements Expression
-{
-    private final Expression[] _branches;
-
-    public LogicalOrExpression(Expression[] branches)
-    {
-        _branches = branches;
-    }
-
-    public UnresolvedType getExpressionType(ExecutionStack stack)
-    {
-        return ByteCodeConstants.LPC_VALUE;
-    }
-
-    public void getInstructions(ExecutionStack stack, InstructionCollector collector)
-    {
-        Label end = new Label();
-        DuplicateStackExpression dup = new DuplicateStackExpression();
-        GenericInstruction pop = new GenericInstruction(Opcodes.POP);
-
-        for (Expression branch : _branches)
-        {
-            branch.getInstructions(stack, collector);
-            new ExpressionCondition(ExpressionCompiler.toBoolean(dup)).jumpWhenTrue(end).getInstructions(stack, collector);
-            pop.getInstructions(stack, collector);
-        }
-        
-        ByteCodeConstants.NIL.getInstructions(stack, collector);
-        new LabelInstruction(end).getInstructions(stack, collector);
-    }
-
-}

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/LpcByteCodeWriter.java

 
 package us.terebi.lang.lpc.compiler.bytecode;
 
-import java.util.List;
-import java.util.regex.Pattern;
-
-import org.apache.log4j.Logger;
 import org.objectweb.asm.AnnotationVisitor;
 import org.objectweb.asm.Attribute;
 import org.objectweb.asm.ClassVisitor;
 import org.adjective.stout.operation.VM;
 import org.adjective.stout.writer.ByteCodeWriter;
 
+import us.terebi.lang.lpc.compiler.bytecode.context.DebugOptions;
 import us.terebi.lang.lpc.runtime.jvm.support.ExecutionTimeCheck;
 
 /**
  */
 public class LpcByteCodeWriter extends ByteCodeWriter
 {
-    private final Logger LOG = Logger.getLogger(LpcByteCodeWriter.class);
-
-    private final List<Pattern> _debugPatterns;
+    private final DebugOptions _debug;
     private final boolean _insertTimeChecks;
     private ClassDescriptor _class;
 
-    public LpcByteCodeWriter(List<Pattern> debugPatterns, boolean insertTimeChecks)
+    public LpcByteCodeWriter(DebugOptions debugOptions, boolean insertTimeChecks)
     {
-        _debugPatterns = debugPatterns;
+        _debug = (debugOptions == null ? new DebugOptions(null) : debugOptions);
         _insertTimeChecks = insertTimeChecks;
     }
 
 
     private boolean isDebug(MethodDescriptor method)
     {
-        if (_debugPatterns == null)
-        {
-            return false;
-        }
-
-        // @TODO clean this up...
-        String spec = _class.getInternalName().substring(3) + ":" + method.getName();
-        for (Pattern pattern : _debugPatterns)
-        {
-            if (pattern.matcher(spec).matches())
-            {
-                LOG.info("Enabling debug for " + _class + " " + method + " [pattern:" + pattern + "]");
-                return true;
-            }
-        }
-        return false;
+        return _debug.isDebugEnabled(_class, method);
     }
 
     protected ClassWriter createClassWriter(int flags)

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/MethodCompiler.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.bytecode.context.CompileContext;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
 import us.terebi.lang.lpc.compiler.util.MemberVisitor;
 import us.terebi.lang.lpc.compiler.util.MethodSupport;
 import us.terebi.lang.lpc.runtime.jvm.LpcMemberType;
 import us.terebi.lang.lpc.runtime.jvm.LpcParameter;
 import us.terebi.lang.lpc.runtime.jvm.LpcVariable;
+import us.terebi.lang.lpc.runtime.jvm.exception.LpcRuntimeException;
 
 /**
  * 
             LpcType argType = arg.getType();
             AnnotationSpec annotation = new AnnotationSpec(LpcParameter.class);
             annotation.withAttribute("kind", argType.getKind());
-            annotation.withAttribute("depth", type.getArrayDepth());
-            if (type.isClass())
+            annotation.withAttribute("depth", argType.getArrayDepth());
+            if (argType.isClass())
             {
-                annotation.withAttribute("className", type.getClassDefinition().getName());
+                annotation.withAttribute("className", argType.getClassDefinition().getName());
             }
             annotation.withAttribute("name", arg.getName());
             annotation.withAttribute("semantics", arg.getSemantics());
                     )));
         }
 
-        new StatementCompiler(getScope(), _context, statements).compileBlock(support.getBody());
+        try
+        {
+            new StatementCompiler(getScope(), _context.enterMethod(support), statements).compileBlock(support.getBody());
+        }
+        catch (CompileException e)
+        {
+            throw new CompileException(e, "In method " + support.getMethodName());
+        }
+        catch (LpcRuntimeException e)
+        {
+            throw new LpcRuntimeException(e, "In method " + support.getMethodName());
+        }
 
         statements.add(VM.Statement.returnObject(ByteCodeConstants.NIL));
         return statements;

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/StatementCompiler.java

 import org.objectweb.asm.Label;
 
 import org.adjective.stout.builder.ElementBuilder;
+import org.adjective.stout.core.ConstructorSignature;
 import org.adjective.stout.core.ExtendedType;
 import org.adjective.stout.impl.ParameterisedClassImpl;
 import org.adjective.stout.loop.Condition;
 import org.adjective.stout.operation.VM;
 
 import us.terebi.lang.lpc.compiler.CompileException;
+import us.terebi.lang.lpc.compiler.bytecode.context.CompileContext;
 import us.terebi.lang.lpc.compiler.java.StatementVisitor;
 import us.terebi.lang.lpc.compiler.java.context.ScopeLookup;
 import us.terebi.lang.lpc.compiler.util.StatementResult;
 import us.terebi.lang.lpc.runtime.jvm.exception.InternalError;
 import us.terebi.lang.lpc.runtime.jvm.support.ComparisonSupport;
 import us.terebi.lang.lpc.runtime.jvm.type.Types;
+import us.terebi.lang.lpc.runtime.jvm.value.TypedValue;
 import us.terebi.util.Pair;
 
 import static us.terebi.lang.lpc.compiler.bytecode.ByteCodeConstants.MAP_ENTRY_GET_KEY;
     protected void visitReturn(ASTControlStatement node)
     {
         Expression expr;
+        LpcType type;
         if (node.jjtGetNumChildren() != 0)
         {
-            // @TODO check type
-            expr = processExpression(node.jjtGetChild(0)).expression;
+            LpcExpression lpcExpr = processExpression(node.jjtGetChild(0));
+            type = lpcExpr.type;
+            expr = lpcExpr.expression;
         }
         else
         {
+            type = Types.VOID;
             expr = ByteCodeConstants.VOID;
         }
+
+        if (!_context.inFunctionLiteral())
+        {
+            LpcType returnType = _context.method().getReturnType();
+            TypeSupport.checkType(node, type, returnType);
+            if (!Types.MIXED.equals(returnType) && !returnType.isClass())
+            {
+                ConstructorSignature constructor = VM.Method.constructor(TypedValue.class, LpcType.Kind.class, Integer.TYPE, LpcValue.class);
+                Expression kind = VM.Expression.getEnum(returnType.getKind());
+                Expression depth = VM.Expression.constant(returnType.getArrayDepth());
+                expr = VM.Expression.construct(constructor, kind, depth, expr);
+            }
+        }
         _statements.add(VM.Statement.returnObject(expr));
     }
 

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/StatementVisitorProxy.java

 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 
+import us.terebi.lang.lpc.compiler.bytecode.context.CompileContext;
 import us.terebi.lang.lpc.parser.ast.Node;
 import us.terebi.lang.lpc.parser.ast.ParserVisitor;
 import us.terebi.lang.lpc.parser.ast.PragmaNode;

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/context/CompileContext.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.compiler.bytecode.context;
+
+import org.adjective.stout.builder.ClassSpec;
+
+import us.terebi.lang.lpc.compiler.ClassStore;
+import us.terebi.lang.lpc.compiler.bytecode.CompileOptions;
+import us.terebi.lang.lpc.parser.LineMapping;
+import us.terebi.lang.lpc.parser.ast.ASTObjectDefinition;
+
+/**
+ * 
+ */
+public interface CompileContext
+{
+    public MethodInfo method();
+    public boolean inFunctionLiteral();
+
+    public CompileOptions options();
+    public ClassStore store();
+
+    public ASTObjectDefinition tree();
+
+    public ClassSpec publicClass();
+    public ClassSpec currentClass();
+    public void popClass(ClassSpec spec);
+    public void pushClass(ClassSpec spec);
+    
+    public boolean isTimeCheckEnabled();
+    public DebugOptions debugOptions();
+    public LineMapping lineMapping();
+    
+    public CompilerState enterFunctionLiteral();
+    public CompilerState enterMethod(MethodInfo method);
+}

modules/lpc/source/java/compiler/us/terebi/lang/lpc/compiler/bytecode/context/CompileSettings.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.compiler.bytecode.context;
+
+import org.adjective.stout.builder.ClassSpec;
+
+import us.terebi.lang.lpc.compiler.ClassStore;
+import us.terebi.lang.lpc.compiler.bytecode.CompileOptions;
+import us.terebi.lang.lpc.parser.LineMapping;
+import us.terebi.lang.lpc.parser.ast.ASTObjectDefinition;
+import us.terebi.util.collection.ArrayStack;
+import us.terebi.util.collection.Stack;
+
+/**
+ * 
+ */
+public class CompileSettings
+{
+    private final ClassStore _store;
+    private final CompileOptions _options;
+    private final ASTObjectDefinition _tree;
+    private final ClassSpec _publicClass;
+    private final Stack<ClassSpec> _classes;
+    private final LineMapping _lineMapping;
+    private final DebugOptions _debug;
+    private final boolean _timeCheck;
+
+    public CompileSettings(ClassStore store, CompileOptions options, ASTObjectDefinition tree, ClassSpec classSpec, LineMapping lineMapping,
+            DebugOptions debug, boolean timeCheck)
+    {
+        _store = store;
+        _options = options;
+        _tree = tree;