Package anvil.script.statements

Source Code of anvil.script.statements.DefinitionStatement

/*
* $Id: DefinitionStatement.java,v 1.10 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 anvil.ErrorListener;
import anvil.Location;
import anvil.java.util.Hashlist;
import anvil.parser.Tag;
import anvil.core.Modules;
import anvil.doc.Doc;
import anvil.codec.ConstantPool;
import anvil.codec.Code;
import anvil.codec.ClassRoom;
import anvil.codec.Field;
import anvil.script.Grammar;
import anvil.script.Name;
import anvil.script.Type;
import anvil.script.Import;
import anvil.script.Imported;
import anvil.script.Scope;
import anvil.script.TypeRef;
import anvil.script.ExternalTypeRef;
import anvil.script.expression.Expression;
import anvil.script.expression.LinkNode;
import anvil.script.parser.TemplateParser;
import anvil.script.compiler.ByteCompiler;
import anvil.script.statements.taglib.TagLibrary;
import anvil.script.statements.taglib.TagLibraryBundle;
import anvil.server.Address;
import anvil.server.Zone;
import anvil.server.ZoneInactiveException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.ArrayList;
import java.net.URL;


/**
* class DefinitionStatement
*
* @author: Jani Lehtim�ki
*/
public abstract class DefinitionStatement extends ScopedStatement implements Scope
{

  protected Hashlist            _types     = new Hashlist();
  protected ArrayList           _imports   = null;
  protected HashMap             _externals = null;
  protected TagLibraryBundle    _taglibs   = new TagLibraryBundle();
  protected DefinitionStatement _parent;
  protected String              _name;
  protected String              _descriptor;
  protected Doc                 _document;
  protected int                 _contentstate = CONTENT_COMPRESS;



  public DefinitionStatement(DefinitionStatement parent, Location location)
  {
    super(parent, location);
    _parent = parent;
    if (parent != null) {
      _contentstate = parent.getContentState();
    }
  }


  public DefinitionStatement(
     DefinitionStatement parent,
     Location location,
     String name,
     Doc document)
  {
    super(parent, location);
    _parent   = parent;
    _name     = name;
    _document = document;
  }
 

  public StringBuffer toString(StringBuffer buffer, boolean addDot)
  {
    if (getType() == Type.MODULE) {
      return buffer;
    }
    _parent.toString(buffer, true);
    buffer.append(_name);
    if (addDot) {
      buffer.append('.');
    }
    return buffer;
  }


  public String toString()
  {
    return toString(new StringBuffer(24)
      .append(TYPE_NAMES[getType()])
      .append(' '), false)
        .toString();
 


  public String getQualifiedName()
  {
    String start = _parent.getQualifiedName();
    if (start.length()>0) {
      return start + '.' + _name;
    } else {
      return _name;
    }
  }

  public String getName()
  {
    return _name;
  }


  public Statement getParentDefinition()
  {
    return _parent;
  }


  public Scope getParent()
  {
    return _parent;
  }


  public Doc getDocument()
  {
    return _document;
  }
 

  public int getContentState()
  {
    return _contentstate;
  }


  public void setContentState(int state)
  {
    _contentstate = state;
  }


  public int getTypeRef(ConstantPool pool)
  {
    return pool.addClass(_descriptor);
  }


  public String getDescriptor()
  {
    return _descriptor;
  }
 

  public Enumeration getDeclarations()
  {
    return _types.elements();
  }


  public Type lookupDeclaration(String name)
  {
    if (_externals != null) {
      return (Type)_externals.get(name);
    }
    return null;
  }


  public boolean isEntityReserved(String name)
  {
    return false;
  }


  public int getNextInlined()
  {
    return 0;
  }
 

  public Type lookupLocalDeclaration(String name)
  {
    return (Type)_types.get(name);
  }
 
 
  public void declare(Type type)
  {
    _types.put(type.getName(), type);
  }
 
 
  public void declare(String name, Type type)
  {
    _types.put(name, type);
  }
 

  public VariableStatement declare(Location location, String name, Expression expr, String document)
  {
    return declare(location, name, expr, document, false);
  }
 

  public VariableStatement declare(Location location, String name, Expression expr, String document, boolean statik)
  {
    return null;
  }


  public void parse(TemplateParser parser, Tag tag)
  {
    if (tag.contains("pack")) {
      _contentstate = CONTENT_PACK;
    } else if (tag.contains("compress")) {
      _contentstate = CONTENT_COMPRESS;
    } else if (tag.contains("preserve")) {
      _contentstate = CONTENT_PRESERVE;
    } else if (tag.contains("silent")) {
      _contentstate = CONTENT_SILENT;
    }
  }


  public void check(ErrorListener context)
  {
    Enumeration enum = _types.elements();
    while(enum.hasMoreElements()) {
      Statement stmt = (Statement)enum.nextElement();
      stmt.check(context);
    }
  }


  public void compile(ByteCompiler context)
  {
    Enumeration enum = _types.elements();
    while(enum.hasMoreElements()) {
      Statement stmt = (Statement)enum.nextElement();
      stmt.compile(context);
    }
  }


  protected static void compileMembers(ByteCompiler context, int size, Enumeration types)
  {
    ClassRoom clazz = context.getClassRoom();
    ConstantPool pool = clazz.getPool();
    Field members = clazz.createField("_members", "[Ljava/lang/Object;", Code.ACC_PUBLIC|Code.ACC_STATIC);
    Code code = clazz.getStatic().getCode();
    context.pushCode(code);
    int intclazz = pool.addClass("java/lang/Integer");
    int intclazzctor = pool.addMethodRef(intclazz, "<init>", "(I)V");
    code.iconst(size * 4);
    code.anewarray("java/lang/Object");
    for(int i=0; types.hasMoreElements();) {
      Type type = (Type)types.nextElement();
      switch(type.getType()) {
      case Type.MODULE:
      case Type.CLASS:
      case Type.INTERFACE:
      case Type.NAMESPACE:
      case Type.FUNCTION:
      case Type.METHOD:
      case Type.INTERFACE_METHOD:
      case Type.CONSTRUCTOR:
      case Type.CONSTANT_VARIABLE:
      case Type.STATIC_VARIABLE:
      case Type.MEMBER_VARIABLE:
        {
          code.dup();
          code.iconst(i++);
          code.anew(intclazz);
          code.dup();
          code.iconst(type.getType());
          code.invokespecial(intclazzctor);
          code.aastore();

          code.dup();
          code.iconst(i++);
          code.astring(type.getName());
          code.aastore();

          code.dup();
          code.iconst(i++);
          Doc doc = type.getDocument();
          if (doc != null) {
            doc.compile(code);
          } else {
            code.aconst_null();
          }
          code.aastore();     

          code.dup();
          code.iconst(i++);
          switch(type.getType()) {
          case Type.FUNCTION:
          case Type.METHOD:
          case Type.INTERFACE_METHOD:
          case Type.CONSTRUCTOR:
            ((FunctionStatement)type).compileDescriptor(context);
            break;
          default:
            code.aconst_null();
          }
          code.aastore();
        }
        break;
       
      default:
        break;
      }
    }
    code.putstatic(members);
    context.popCode();
  }



 
  protected void addExternal(String name, Type type)
  {
    if (_externals == null) {
      _externals = new HashMap();
    }
    _externals.put(name, new Imported(getModuleStatement(), name, type));
  }
 
 

  protected void addImport(Import imprt)
  {
    if (_imports == null) {
      _imports = new ArrayList();
    }
    _imports.add(imprt);
    getModuleStatement().addDependency(imprt);
 


  protected void addExternal(ErrorListener listener, Location location, Object source, String as, Type type)
  {
    switch(type.getType()) {
    case MODULE:
    case NAMESPACE:
    case CLASS:
    case INTERFACE:
    case FUNCTION:
    case CONSTANT_VARIABLE:
    case STATIC_VARIABLE:
    case IMPORT:
      if (lookupDeclaration(as) == null) {
        addExternal(as, type);   
      } else {
        listener.error(location, "Entity '"+type+"' from '"+source+"' causes conflict: name already declared");
     
      break;
     
    default:
      listener.error(location, "Entity '"+type+"' from '"+source+"' cannot be imported");
      break;
    }
  } 
 
 
  protected static final Type follow(Type type, Name name)
  {
    int n = name.size();
    for(int i=0; i<n; i++) {
      if (!(type instanceof Scope)) {
        return null;
      }
      type = ((Scope)type).lookupDeclaration(name.get(i));
    }
    return type;
  }
 
 
  protected void addExternals(ErrorListener listener, Location location, Object source, Scope scope)
  {
    Enumeration enum = scope.getDeclarations();
    while(enum.hasMoreElements()) {
      Type child = (Type)enum.nextElement();
      switch(child.getType()) {
      case NAMESPACE:
      case CLASS:
      case INTERFACE:
      case FUNCTION:
      case CONSTANT_VARIABLE:
      case STATIC_VARIABLE:
      case IMPORT:
        addExternal(listener, location, source, child.getName(), child);
        break;
      }
    }
  }
 
 
  public void importExternals(ErrorListener listener)
  {
    if (_imports != null) {
      int size = _imports.size();
      for(int i=0; i<size; i++) {
        Import imprt = (Import)_imports.get(i);
        Location location = imprt.getLocation();
        Object source = imprt.getSource();
        Name[] decls = imprt.getDeclarations();
        Type type = imprt.resolve(listener);
        if (type != null) {
          if (imprt.importAll()) {
            if (type instanceof Scope) {
              addExternals(listener, location, source, (Scope)type);
            } else {
              listener.error(location, "Trying to import all contained types from non-scoped entity '"+source+"'");
           
           
          } else if (decls != null) {
         
            if (type instanceof Scope) {
              int n = decls.length;
              for(int j=0; j<n; j++) {
                Name childname = decls[j];
                Type child = follow(type, childname);
                if (child != null) {
                  if (childname.hasStar()) {
                    switch(child.getType()) {
                    case MODULE:
                    case NAMESPACE:
                    case CLASS:
                    case INTERFACE:
                      addExternals(listener, location, source, (Scope)child);
                      break;
                    default:
                      listener.error(location, "Entity '"+child+"' does not contain any entities that may be imported");
                      break;
                    }
                  } else {
                    addExternal(listener, location, source, childname.as(), child);
                  }
                } else {
                  listener.error(location, "Entity '"+childname+"' not found from '"+source+"'");
                }
              }
             
            } else {
              listener.error(location, "Trying to import named entities from non-scoped entity '"+type+"'");
            }
         
          } else {
            addExternal(listener, location, source, imprt.getAs(), type);
          }
        }
      }
    }
    Enumeration e = _types.elements();
    while(e.hasMoreElements()) {
      Statement stmt = (Statement)e.nextElement();
      stmt.importExternals(listener);
    }
  }
 

  public void addEntityImport(
      ErrorListener listener,
      Location location,
      Name entity,
      Name[] decls,
      boolean withStar)
  {
    LinkNode link = new LinkNode(this, location, entity);
    Import imprt = new Import(null, location, entity, new TypeRef(link), entity.as(), decls, withStar);
    addImport(imprt);
  }



  private static String extractNameFromHref(String href)
  {
    String name;
    int i = href.lastIndexOf('/');
    if (i>=0) {
      name = href.substring(i+1);
    } else {
      name = href;
    }
    i = name.indexOf('.');
    if (i>0) {
      name = name.substring(0, i);
    }
    return name;
  }

 
  public void addHrefImport(
      ErrorListener listener,
      Location location,
      String href,
      String as,
      Name[] decls,
      boolean withStar)
  {
    ModuleStatement script = getModuleStatement();
    String pathinfo = script.getAddress().merge(href);
   
    Address address = null;
    try {
      address = script.getAddress().resolve(href);
    } catch (ZoneInactiveException e) {
      listener.error(location, "Target's zone is inactive: '" + href + "'");
    }
    if (address.equals(script.getAddress())) {
      listener.error(location, "Trying to import self: '" + href + "'");
      return;
    }
    if (as == null) {
      as = extractNameFromHref(address.getPathinfo());
    }
    if (!Grammar.isValidIdentifier(as)) {
      listener.error(location, "Identifier '" + as + "' is invalid");
    }      
    Import imprt = new Import(address, location, null,
        new ExternalTypeRef(script, address), as, decls, withStar);
    addImport(imprt);
  }



  public void addTaglib(ErrorListener listener, Location location, String source, String namespace, String tagns)
  {
    ModuleStatement script = getModuleStatement();
    Address importing = null;
    try {
      importing = script.getAddress().resolve(source);
    } catch (ZoneInactiveException e) {
      listener.error(location, "Target's zone is inactive: '" + source + "'");
    }
    URL url = importing.getURL();
    TagLibrary lib = anvil.script.statements.taglib.Parser.parse(listener, url, location, namespace, tagns);
    if (lib != null) {
      _taglibs.addLibrary(lib);
    }
  }

 
  public anvil.script.statements.taglib.Tag getTag(String ns, String name)
  {
    anvil.script.statements.taglib.Tag tag = _taglibs.getTag(ns, name);
    if (tag != null) {
      return tag;
    }
    return super.getTag(ns, name);
  }


  protected void onImport(TemplateParser parser, Tag tag)
  {
    String href     = tag.getValue("href");
    String module   = tag.getValue("module");
    String from     = tag.getValue("from");
    String as       = tag.getValue("as");
    String entities = tag.getValue("entities");
    String taglib   = tag.getValue("taglib");
    String tagns    = tag.getValue("ns");
   
    Location location = parser.getLocation();
    Name[] decls = null;
    boolean star = false;
   
    if (entities != null) {
      entities = entities.trim();
      if (entities.equals("*")) {
        star = true;
      } else {
        decls = Grammar.parseImportNames(parser, location, entities);
      }
    }
   
    if (as != null) {
      if (star) {
        parser.error(location, "Syntax error: 'as' and '*' may not be used together");
      }
      as = as.trim();
      if (!Grammar.isValidIdentifier(as)) {
        parser.error(location, "Identifier '" + as + "' is invalid");
        as = null;
      }      
    }
   
    if (href != null) {
      href = href.trim();
      addHrefImport(parser, location, href, as, decls, star);
     
    } else if (from != null) {
      Name name = Grammar.parseDottedName(parser, location, from);
      if (as != null) {
        name.setAs(as);
      }
      addEntityImport(parser, location, name, decls, star);
     
    } else if (module != null) {
      Name name = Grammar.parseDottedName(parser, location, module);
      if (as != null) {
        name.setAs(as);
      }
      addEntityImport(parser, location, name, decls, star);

    }
    
    if ((taglib != null) && (tagns == null)) {
      parser.error(location, "Attribute 'taglib' given but 'ns' is missing");
     
    } else if ((taglib == null) && (tagns != null)) {
      parser.error(location, "Attribute 'ns' given but 'taglib' is missing");
     
    } else if ((taglib != null) && (tagns != null)) {
      if (star || decls != null) {
        parser.error(location, "Import statement declaring tag library must not contain '*'�or 'entities' attribute");
      } else {
        addTaglib(parser, location, taglib.trim(), as, tagns.trim());
      }
    }
   
  }



  protected void onVar(TemplateParser parser, Tag tag)
  {
    Location location = parser.getLocation();
    String name = tag.getValue("name");
    String value = tag.getValue("value");
    if (name == null) {
      parser.error(location, "Attribute 'name' missing from variable type");
      return ;
    }
    if (!Grammar.isValidIdentifier(name)) {
      parser.error(location, "Attribute 'name' is not valid identifier");
      return;
    }
    Expression expr = null;
    if (value != null) {
      expr = Grammar.parseExpression(value, location, parser);
    }
    if (tag.contains("static")) {
      declare(location, name, expr, parser.getDocument(), true);
    } else {
      declare(location, name, expr, parser.getDocument());
    }
  }


  protected void onConst(TemplateParser parser, Tag tag)
  {
    Location location = parser.getLocation();
    String name = tag.getValue("name");
    String value = tag.getValue("value");
    if (name == null) {
      parser.error(location, "Attribute 'name' missing from constant type");
      return;
    }
    if (!Grammar.isValidIdentifier(name)) {
      parser.error(location, "Attribute 'name' is not valid identifier");
      return;
    }
    if (value == null) {
      parser.error(location, "Attribute 'value' missing from constant type");
      return;
    }
    Expression expr = null;
    if (value != null) {
      expr = Grammar.parseExpression(value, location, parser);
    }
    declare(new ConstantVariableStatement(location, this, name, expr, parser.getDocument()));
  }


  protected void onNamespace(TemplateParser parser, int type, Tag tag)
  {
    Location location = parser.getLocation();
    String str = tag.get("name");
    if (str == null) {
      parser.error(parser.getLocation(), "Attribute 'name' missing from namepace");
      NamespaceStatement ns = new NamespaceStatement(location, this);
      ns.setName("ns$"+ns.hashCode());
      parser.push(ns);
      ns.parse(parser, tag);
    } else {
      NamespaceStatement ns = null;
      Name name = Grammar.parseDottedName(parser, location, str);
      int n = name.size();
      DefinitionStatement scope = this;
      for(int i=0; i<n; i++) {
        String part = name.get(i);
        ns = new NamespaceStatement(location, scope);
        ns.setName(part);
        Type declared = scope.lookupDeclaration(part);
        if (declared == null) {
          ns = new NamespaceStatement(location, scope);
          ns.setName(part);
          scope.declare(ns);
        } else if (declared.getType() == Type.NAMESPACE) {
          ns = (NamespaceStatement)declared;
        } else {
          parser.error(location, "Entity '"+name+"' already declared");
          ns = new NamespaceStatement(location, scope);
          ns.setName(part);
        }
        parser.push(ns);
        ns.parse(parser, tag);
        scope = ns;
      }
      if (ns != null) {
        ns.setPopLevel(n);
      }
    }
  }
 

  protected void onFunction(TemplateParser parser, int type, Tag tag)
  {
    FunctionStatement function = new FunctionStatement(this, parser.getLocation());
    function.parse(parser, tag);
    parser.push(function);
    String name = function.getName();
    if (name != null) {
      if (lookupDeclaration(name) == null) {
        declare(function);
      } else {
        parser.error(parser.getLocation(), "Entity '" + name + "' is already declared");
      }
    }
  } 
 

  protected void onClass(TemplateParser parser, int type, Tag tag)
  {
    ClassStatement clazz = new ClassStatement(this, parser.getLocation());
    parser.push(clazz);
    clazz.parse(parser, tag);
    String name = clazz.getName();
    if (name != null) {
      if (lookupDeclaration(name) == null) {
        declare(clazz);
      } else {
        parser.error(parser.getLocation(), "Entity '" + name + "' is already declared");
      }
    }     
  }


  public boolean onTag(TemplateParser parser, int type, Tag tag)
  {
    switch(type) {
    case ST_IMPORT:
      onImport(parser, tag);
      return true;

    default:
      return super.onTag(parser, type, tag);
    }

  }



}
TOP

Related Classes of anvil.script.statements.DefinitionStatement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.