/*
* $Id: ModuleStatement.java,v 1.4 2002/09/16 08:05:06 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.script.statements;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Calendar;
import java.util.HashSet;
import java.util.HashMap;
import anvil.ForgingException;
import anvil.java.util.BindingEnumeration;
import anvil.core.Any;
import anvil.core.AnyString;
import anvil.core.Array;
import anvil.core.Modules;
import anvil.core.runtime.AnyFunction;
import anvil.ErrorListener;
import anvil.Location;
import anvil.Log;
import anvil.codec.Code;
import anvil.codec.ClassRoom;
import anvil.codec.Field;
import anvil.codec.Method;
import anvil.codec.CodecConstants;
import anvil.codec.ConstantPool;
import anvil.doc.Doc;
import anvil.doc.DocParser;
import anvil.parser.Tag;
import anvil.ErrorListener;
import anvil.script.ClassType;
import anvil.script.CompilableFunction;
import anvil.script.compiler.ByteCompiler;
import anvil.script.Context;
import anvil.script.Type;
import anvil.script.Function;
import anvil.script.Dependency;
import anvil.script.Import;
import anvil.script.InterfaceType;
import anvil.script.Namespace;
import anvil.script.NamespaceType;
import anvil.script.parser.TemplateParser;
import anvil.script.Scope;
import anvil.script.Module;
import anvil.script.ModuleEnvelope;
import anvil.script.Grammar;
import anvil.script.expression.Expression;
import anvil.script.statements.taglib.TagLibrary;
import anvil.server.Address;
import anvil.server.LocalizationPreferences;
import anvil.server.Zone;
import anvil.java.util.Hashlist;
import anvil.java.util.Holder;
/**
* class ModuleStatement
*
* @author: Jani Lehtim�ki
*/
public class ModuleStatement extends DefinitionStatement
implements Module, CodecConstants
{
private ModuleEnvelope _envelope;
private Address _address;
private BlockStatement _staticinit;
private BlockStatement _init;
private int _inlinecount;
private Method _constructor;
private HashMap _dependencies = new HashMap();
public ModuleStatement(ModuleEnvelope envelope, Location location)
{
super(null, location);
init(envelope, location);
}
public ModuleStatement(ModuleEnvelope envelope, Location location, String name, String document)
{
super(null, location, name, DocParser.parseModule(name, document));
init(envelope, location);
declare(new ImportedModuleStatement(name, this, _document));
}
private void init(ModuleEnvelope envelope, Location location)
{
_staticinit = new ImplicitBlockStatement(this, location);
_init = new ImplicitBlockStatement(this, location);
_envelope = envelope;
_address = envelope.getAddress();
_descriptor = envelope.getDescriptor();
_contentstate = envelope.getAddress().getZone().getContentProcessing();
declare(new ImportedModuleStatement("module", this, null));
addExternal(Context.GLOBAL, Context.TYPE);
}
public int typeOf()
{
return Statement.ST_MODULE;
}
public String name()
{
return "module";
}
public int getType()
{
return MODULE;
}
public Scope getParent()
{
return null;
}
public String getQualifiedName()
{
return "";
}
public void addDependency(Import imprt)
{
Address addr = imprt.getAddress();
if (addr != null) {
_dependencies.put(addr, new Dependency(addr, null, imprt.getLocation()));
}
}
public Iterator getDependencies()
{
return _dependencies.values().iterator();
}
public Dependency getDependency(Address address)
{
return (Dependency)_dependencies.get(address);
}
public ModuleEnvelope getEnvelope()
{
return _envelope;
}
public Address getAddress()
{
return _address;
}
public String getPathinfo()
{
return _address.getPathinfo();
}
public int getNextInlined()
{
return _inlinecount++;
}
public boolean isStaticRegion()
{
return true;
}
public Type lookupDeclaration(String name)
{
Type type = (Type)_types.get(name);
if (type != null) {
return type;
}
Namespace ns = _address.getZone().getNamespace(name);
if (ns != null) {
type = new ImportedNamespaceStatement(this, name, null);
if (type != null) {
return type;
}
}
return super.lookupDeclaration(name);
}
public VariableStatement declare(Location location, String name, Expression expr, String document, boolean statik)
{
VariableStatement var;
declare(var = new StaticVariableStatement(location, this, name, expr, document));
return var;
}
public void parse(TemplateParser parser, Tag tag)
{
super.parse(parser, tag);
String name = tag.getValue("name");
if (name != null) {
if (Grammar.isValidIdentifier(name)) {
declare(new ImportedModuleStatement(name, this, null));
_name = name;
} else {
parser.error(getLocation(), "Template name '"+_name+"' is invalid");
}
} else {
_name = "module";
}
_document = DocParser.parseModule(_name, parser.getDocument());
declare(new ImportedModuleStatement(_name, this, _document));
}
private void addInitializers(Enumeration types)
{
while(types.hasMoreElements()) {
Type type = (Type)types.nextElement();
switch(type.getType()) {
case STATIC_VARIABLE:
case CONSTANT_VARIABLE:
VariableStatement var = (VariableStatement)type;
_staticinit.add(new EvalStatement(_staticinit, getLocation(), var.createStaticInitializer()));
if (!var.hasConstantInitializer()) {
_init.add(new EvalStatement(_init, getLocation(), var.createInitializer()));
}
break;
case CLASS:
case INTERFACE:
case NAMESPACE:
addInitializers(((Scope)type).getDeclarations());
break;
}
}
}
public void check(ErrorListener context)
{
super.check(context);
addInitializers(getDeclarations());
}
public final synchronized void init(Context context)
{
throw new RuntimeException("Attempted to call 'void init(Context)' on ModuleStatement");
}
public void onCharacters(TemplateParser parser, String cdata)
{
}
public boolean onTag(TemplateParser parser, int type, Tag tag)
{
switch(type) {
case ST_TAG:
break;
case ST_IMPORT:
onImport(parser, tag);
break;
case ST_VAR:
onVar(parser, tag);
break;
case ST_CONST:
onConst(parser, tag);
break;
case ST_FUNCTION:
onFunction(parser, type, tag);
break;
case ST_CLASS:
onClass(parser, type, tag);
break;
case ST_NAMESPACE:
onNamespace(parser, type, tag);
break;
case ST_ENDMODULE:
parser.pop();
break;
default:
return false;
}
return true;
}
public Method getConstructor()
{
return _constructor;
}
public void compileConstructor(ByteCompiler context)
{
ClassRoom clazz = context.getClassRoom();
ConstantPool pool = clazz.getPool();
Method constructor = clazz.createConstructor("()V", ACC_PUBLIC);
_constructor = constructor;
Code code = constructor.getCode();
StringBuffer clsid = new StringBuffer();
clsid.append("$Id: ");
clsid.append(_address.getPathinfo());
clsid.append(" 1.0 ");
LocalizationPreferences prefs = _address.getZone().getLocalizationPreferences();
Calendar cal = Calendar.getInstance(prefs.getTimezoneInstance(), prefs.getLocaleInstance());
anvil.util.Conversions.toString(clsid, cal);
Field clsidfield = clazz.createField("_id", "Ljava/lang/String;", ACC_PUBLIC|ACC_STATIC|ACC_FINAL);
clsidfield.setConstantValue(pool.addString(clsid.toString()));
context.pushCode(code);
code.self();
code.invokespecial(pool.addMethodRef("anvil/script/compiler/CompiledModule",
"<init>", "()V"));
context.popCode();
Method versionmethod = clazz.createMethod("getVersion", "()I", ACC_PUBLIC);
code = versionmethod.getCode();
context.pushCode(code);
code.iconst(_envelope.getVersion());
code.ireturn();
clazz.createField("_module", "Lanvil/script/compiler/CompiledModule;", ACC_PUBLIC|ACC_STATIC);
clazz.createField("_type", "Lanvil/core/Any;", ACC_PUBLIC|ACC_STATIC);
context.popCode();
}
public void compileStaticInit(ByteCompiler context)
{
ClassRoom clazz = context.getClassRoom();
Code code = clazz.getStatic().getCode();
ConstantPool pool = code.getPool();
context.pushCode(code);
if (_staticinit != null) {
_staticinit.compile(context);
}
Enumeration e = _types.elements();
while(e.hasMoreElements()) {
Type type = (Type)e.nextElement();
int typeid = type.getType();
if (typeid == CLASS || typeid == INTERFACE) {
code.getstatic(pool.addFieldRef(type.getTypeRef(pool),
"_members", "[Ljava/lang/Object;"));
code.pop();
}
}
context.popCode();
}
public void compileInit(ByteCompiler context)
{
ClassRoom clazz = context.getClassRoom();
Method method = clazz.createMethod("init", "(Lanvil/script/Context;)V", ACC_PUBLIC|ACC_FINAL|ACC_SYNCHRONIZED);
Code code = method.getCode();
context.pushCode(code);
code.addLocal();
if (_init != null) {
_init.compile(context);
}
code.vreturn();
context.popCode();
}
private void compileDependencies(ByteCompiler context)
{
ClassRoom clazz = context.getClassRoom();
Code code = context.getCode();
ConstantPool pool = code.getPool();
Field field = clazz.createField("_imports", "[Ljava/lang/String;", Code.ACC_PUBLIC|Code.ACC_STATIC);
code.iconst(_dependencies.size()*2);
code.anewarray("java/lang/String");
Iterator iter = _dependencies.values().iterator();
for(int i=0; iter.hasNext(); ) {
Dependency dep = (Dependency)iter.next();
code.dup();
code.iconst(i++);
code.astring(dep.getPathinfo());
code.aastore();
code.dup();
code.iconst(i++);
code.astring(dep.getDescriptor());
code.aastore();
}
code.putstatic(field);
}
public void compile(ByteCompiler context)
{
compileMembers(context, _types.size(), _types.elements());
compileDependencies(context);
compileConstructor(context);
compileStaticInit(context);
compileInit(context);
super.compile(context);
_constructor.getCode().vreturn();
}
}