Package anvil.script.statements

Source Code of anvil.script.statements.FunctionStatement

/*
* $Id: FunctionStatement.java,v 1.18 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.core.Any;
import anvil.core.AnyClass;
import anvil.core.AnyTuple;
import anvil.codec.ExceptionHandler;
import anvil.codec.ClassRoom;
import anvil.codec.Field;
import anvil.codec.Method;
import anvil.codec.Code;
import anvil.codec.CodecConstants;
import anvil.codec.ConstantPool;
import anvil.codec.Target;
import anvil.codec.Source;
import anvil.codec.Switch;
import anvil.Location;
import anvil.doc.DocParser;
import anvil.doc.Doc;
import anvil.parser.Tag;
import anvil.ErrorListener;
import anvil.script.CompilableFunction;
import anvil.script.compiler.ByteCompiler;
import anvil.script.Context;
import anvil.script.Type;
import anvil.script.FunctionDispatcher;
import anvil.script.expression.Node;
import anvil.script.expression.Expression;
import anvil.script.expression.VariableNode;
import anvil.script.expression.ConstantNode;
import anvil.script.ParameterListDeclaration;
import anvil.script.parser.ExpressionParser;
import anvil.script.parser.TemplateParser;
import anvil.script.Module;
import anvil.script.StackFrame;
import anvil.script.Grammar;
import anvil.java.util.Hashlist;
import java.io.IOException;
import java.util.Enumeration;

/**
* class FunctionStatement
*
* @author: Jani Lehtim�ki
*/
public class FunctionStatement extends DefinitionStatement
  implements CompilableFunction, CodecConstants
{

  protected FunctionStatement _context;
  protected boolean           _synchronized = false;
  protected ParameterListDeclaration _parameters = null;
  protected BlockStatement    _block;
  protected ExceptionHandler  _handler;
  protected Switch            _switch;
  protected boolean           _escaped = false;
  protected int               _localcount = 0;
  protected int               _yieldcount = 0;
  protected String            _signature;
  protected int               _local_frame;
  protected VariableNode      _return_var = null;


  public FunctionStatement(DefinitionStatement parent, Location location)
  {
    super(parent, location);
    _block = new ImplicitBlockStatement(this, location);
  }
 

  public FunctionStatement(
      Location location,
      DefinitionStatement parent,
      FunctionStatement context,
      boolean sync,
      String name,
      String document,
      ParameterListDeclaration parameters)
  {
    super(
      parent,
      location, (context != null) ? context.getName() + '$' + name : name,
      DocParser.parseFunction(name, document));
    _context = context;
    _synchronized = sync;
    _parameters = parameters;
    _parameters.declareTo(this);
    _parameters.importDocuments(_document);
    _block = new ImplicitBlockStatement(this, location);
  }


  public String toString()
  {
    StringBuffer buffer = new StringBuffer(40);
    buffer.append(super.toString());
    buffer.append('(');
    if (_parameters != null) {
      _parameters.toString(buffer);
    } else {
      buffer.append("<unparsed>");
    }
    buffer.append(')');
    return buffer.toString();
  }


  public int typeOf()
  {
    return Statement.ST_FUNCTION;
  }



  public int getNextLocalSlot()
  {
    return _localcount++;
  }


  public Type lookupDeclaration(String name)
  {
    Type type = (Type)_types.get(name);
    if (type == null) {
      if (_context != null) {
        type = _context.lookupDeclaration(name);
      }
      if (type == null) {
        return super.lookupDeclaration(name);
      }
    }
    return type;
  }


  public LocalVariableStatement declare(String name)
  {
    LocalVariableStatement var = new LocalVariableStatement(getLocation(), this, name);
    declare(var);
    return var;
  }
 

  public ParameterStatement declareParameter(String name)
  {
    ParameterStatement param = new ParameterStatement(getLocation(), this, name);
    declare(param);
    return param;
 


  public boolean isStaticRegion()
  {
    return true;
  }


  public boolean isInnerFunction()
  {
    return _context != null;
  }
   

 
  public void parse(TemplateParser parser, Tag tag)
  {
    super.parse(parser, tag);
    String name = tag.getValue("name");
    if (name != null) {
      name = name.trim();
      if (!Grammar.isValidIdentifier(name)) {
        parser.error(getLocation(), "invalid function name: '"+name+"'");
      } else {
        _name = name;
      }
      _document = DocParser.parseFunction(_name, parser.getDocument());
    } else {
      parser.error(getLocation(), "function attribute 'name' not given");
    }
    _synchronized = tag.contains("synchronized");
    _parameters = parseParameters(parser, tag);
    _parameters.declareTo(this);
  }


  public boolean onTag(TemplateParser parser, int type, Tag tag)
  {
    switch(type) {
    case ST_ENDFUNCTION:
      parser.pop();
      return true;

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

  }


  public ParameterListDeclaration parseParameters(TemplateParser parser, Tag tag)
  {
    ParameterListDeclaration parameters = new ParameterListDeclaration();
    String params = tag.getValue("params");
    if (params != null) {
      ExpressionParser p = new ExpressionParser(parser, parser.getLocation(), params);
      p.parseParameterListDeclaration(parameters);
   
    } else {
      parameters.open();
      int n = tag.getLength();
      for(int i=0; i<n; i++) {
        String name = tag.getName(i);
        if (name.equalsIgnoreCase("param")) {

          String param = tag.getValue(i);
          Expression defaultexpr = null;

          if ((i<n-1) && tag.getName(i+1).equalsIgnoreCase("default")) {
            String def = tag.getValue(i+1);
            defaultexpr = Grammar.parseExpression(def, getLocation(), parser);
            i++;
          } else {
            if (parameters.hasDefaultValues()) {
              parser.error(getLocation(), "Parameters with default values must appear last");
              defaultexpr = null;
            }
          }

          if (Grammar.isValidIdentifier(param)) {
            if (parameters.isDeclared(param)) {
              parser.error(getLocation(), "Entity '"+param+"' is already declared");
            } else {
              parameters.add(param, defaultexpr);
            }
          } else {
            parser.error(getLocation(), "Parameter name '"+param+"' is invalid");
          }

        }
      }

      String rest = tag.getValue("rest");
      if (rest != null) {
        rest = rest.trim();
        if (!Grammar.isValidIdentifier(rest)) {
          parser.error(getLocation(), "Parameter '" + rest + "' is invalid");
        } else {
          if (parameters.isDeclared(rest)) {
            parser.error(getLocation(), "Entity '"+rest+"' is already declared");
          } else {
            parameters.add(PARAMETER_REST, rest, Any.EMPTY_TUPLE, null);
          }
        }
      }
      parameters.close();
    }
   
    return parameters;
  }



  public void check(ErrorListener context)
  {
    _parameters.check(context);
    _block.check(context);
    _block.eliminate(context);
  }


  public void markEscaped()
  {
    _escaped = true;
  }


  public boolean isEscaped()
  {
    return _escaped;
  }


  public int addYieldState()
  {
    return ++_yieldcount;
  }


  public boolean isGenerator()
  {
    return _yieldcount > 0;
  }
 

  public String name()
  {
    return "function";
  }


  public String getName()
  {
    return _name;
  }


  public String getDescriptor()
  {
    return "f_" + _name;
  }

 
  public int getType()
  {
    return FUNCTION;
  }


  public FunctionStatement getContext()
  {
    return _context;
  }
 

  public Doc getDocument()
  {
    return _document;
  }
 
  
  public Statement getChildStatement()
  {
    return _block;
  }  


  public int getMinimumParameterCount()
  {
    return _parameters.minSize();
  }


  public int getParameterCount()
  {
    return _parameters.size();
  }


  public String getParameterName(int index)
  {
    return _parameters.getName(index);
  }
  

  public int getParameterType(int index)
  {
    return _parameters.getType(index);
  }
 

  public Any getParameterDefault(int index)
  {
    return _parameters.getDefault(index);
  }


  public Doc getParameterDoc(int index)
  {
    return _parameters.getDoc(index);
  }


  public Any getAttribute(String name)
  {
    return null;
  }


  public FunctionDispatcher getDispatcher(Context context)
  {
    return null;
  }

  public Any execute(Context context, Any[] parameters)
  {
    return execute(context, null, parameters);
  }

  public Any execute(Context context, Any self, Any[] parameters)
  {
    return null;
  }

  public Any execute(Context context, Any self)
  {
    return null;
  }

  public Any execute(Context context, Any self, Any param1)
  {
    return null;
  }

  public Any execute(Context context, Any self, Any param1, Any param2)
  {
    return null;
  }

  public Any execute(Context context, Any self, Any param1, Any param2, Any param3)
  {
    return null;
  }

  public Any execute(Context context, Any self, Any param1, Any param2, Any param3, Any param4)
  {
    return null;
  }


  public int getFrameIndex()
  {
    return _local_frame;
  }


  public String getSignature()
  {
    if (_signature == null) {
      StringBuffer buffer = new StringBuffer();
      buffer.append('(');
      buffer.append("Lanvil/script/Context;");
      int n = _parameters.size();
      for(int i=1; i<n; i++) {
        buffer.append("Lanvil/core/Any;");
      }
      buffer.append(")Lanvil/core/Any;");
      _signature = buffer.toString();
    }
    return _signature;
 
 

  public void compileDescriptor(ByteCompiler context)
  {
    _parameters.compileDescriptor(context);
  }
 

  public void compile(ByteCompiler context)
  {
    ClassRoom clazz = context.getClassRoom();
    Field typefield = clazz.createField("f_"+_name, "Lanvil/script/Function;", ACC_PUBLIC|ACC_STATIC);
    clazz.createField("F_"+_name, "Lanvil/core/Any;", ACC_PUBLIC|ACC_STATIC);
    Method method = clazz.createMethod("f_"+_name, getSignature(), ACC_PUBLIC|ACC_FINAL|ACC_STATIC|(_synchronized?ACC_SYNCHRONIZED:0));
    compileBody(context, method, typefield);
  }


  public void compileBody(ByteCompiler context, Method method, Field typefield)
  {
    ClassRoom clazz = context.getClassRoom();
    ConstantPool pool = clazz.getPool();
    Code code = method.getCode();
    boolean is_method = (getType() != FUNCTION);
    boolean is_generator = (_yieldcount > 0);
   
    context.pushCode(code);
    int l_context = code.addLocal();
   
    Enumeration enum = _types.elements();
    while(enum.hasMoreElements()) {
      Object obj = enum.nextElement();
      if (obj instanceof ParameterStatement) {
        ((ParameterStatement)obj).compileInit(context);
      }
    }
   
    if (is_generator) {
      enum = _types.elements();
      while(enum.hasMoreElements()) {
        Object obj = enum.nextElement();
        if (obj instanceof LocalVariableStatement) {
          ((LocalVariableStatement)obj).markEscaped();
        }
      }

      int generatorclazz = pool.addClass("anvil/script/Generator");
      _local_frame = code.addLocal();
      code.anew(generatorclazz);
      code.dup();
      code.aload_first();
      code.getstatic(pool.addFieldRef(context.TYPE_MODULE, "_module", "Lanvil/script/compiler/CompiledModule;"));
      if (is_method) {
        code.self();
      } else {
        code.aconst_null();
      }
      code.getstatic(typefield);
      code.iconst(_localcount);
      code.iconst(getLocation().getLine());
      code.invokespecial(pool.addMethodRef(generatorclazz, "<init>",
        "(Lanvil/script/Context;Lanvil/script/Module;Lanvil/core/AnyClass;Lanvil/script/Function;II)V"));
      code.astore(_local_frame);
      enum = _types.elements();

      enum = _types.elements();
      while(enum.hasMoreElements()) {
        Object obj = enum.nextElement();
        if (obj instanceof LocalVariableStatement) {
          ((LocalVariableStatement)obj).compile(context);
        }
      }

      code.aload(_local_frame);
      code.invokevirtual(pool.addMethodRef(generatorclazz, "getWrapper", "()Lanvil/core/Any;"));
      code.areturn();
      context.popCode();

      Method method2;
      if (is_method) {
        method2 = clazz.createMethod("h_"+_name, "(Lanvil/script/Context;Lanvil/script/Generator;)Lanvil/core/Any;", ACC_PUBLIC|(_synchronized?ACC_SYNCHRONIZED:0));
      } else {
        method2 = clazz.createMethod("h_"+_name, "(Lanvil/script/Context;Lanvil/script/Generator;)Lanvil/core/Any;", ACC_PUBLIC|ACC_FINAL|ACC_STATIC|(_synchronized?ACC_SYNCHRONIZED:0));
      }
      code = method2.getCode();
      code.addLocal();
      _local_frame = code.addLocal();
      code.addLocals(2);
      context.pushCode(code);

      code.aload(_local_frame);
      code.invokevirtual(pool.addMethodRef("anvil/script/Generator", "getState", "()I"));
      _switch = code.select();
      for(int i=0; i<=_yieldcount; i++) {
        _switch.addCase(i);
      }
      _switch.end();
      _switch.bindCase(0);
      _block.compile(context);
      _switch.bindDefault();
      code.aload(_local_frame);
      code.invokevirtual(pool.addMethodRef("anvil/script/Generator", "setClosedState", "()V"));
      code.getstatic(pool.addFieldRef(context.TYPE_ANY, "UNDEFINED", "Lanvil/core/Any;"));
      code.areturn();
     
    } else {

      _local_frame = code.addLocal();

      _return_var = new VariableNode(declare("return$"+hashCode()));
      //_return_var.compile(context, ConstantNode.UNDEFINED);
      //code.pop();
     
      code.aload(l_context);
      code.getstatic(pool.addFieldRef(context.TYPE_MODULE, "_module", "Lanvil/script/compiler/CompiledModule;"));
      if (is_method) {
        code.self();
      }
      code.getstatic(typefield);
      code.iconst(_escaped ? _localcount : 0);
      code.iconst(getLocation().getLine());
      code.iconst(_escaped);
      code.invokevirtual(pool.addMethodRef("anvil/script/StackFrameStack", "push",
        is_method ?
          "(Lanvil/script/Module;Lanvil/core/AnyClass;Lanvil/script/Function;IIZ)Lanvil/script/StackFrame;" :
          "(Lanvil/script/Module;Lanvil/script/Function;IIZ)Lanvil/script/StackFrame;"
        ));
      code.astore(_local_frame);

      ExceptionHandler handler = code.startExceptionHandler(true);
      _handler = handler;
      {
        enum = _types.elements();
        while(enum.hasMoreElements()) {
          Object obj = enum.nextElement();
          if (obj instanceof LocalVariableStatement) {
            ((LocalVariableStatement)obj).compile(context);
          }
        }
       
        _block.compile(context);
        handler.callFinally();
        if (getType() == CONSTRUCTOR) {
          code.self();
        } else {
          _return_var.compile(context, Node.GET);
          //code.aload(_return_var);
          //code.getstatic(pool.addFieldRef(context.TYPE_ANY, "UNDEFINED", "Lanvil/core/Any;"));
        }
        code.areturn();
      }
      handler.endTry();
      handler.endProtectedRegion();

      handler.startCatch(0);
      {
        int l_thrown = code.addLocal();
        code.astore(l_thrown);
        handler.callFinally();
        code.aload(l_thrown);
        code.athrow();
      }
      handler.endCatches();

      handler.startFinally();
      {
        int l_ret = code.addLocal();
        code.astore(l_ret);
        code.aload(l_context);
        code.invokevirtual(pool.addMethodRef("anvil/script/StackFrameStack", "pop", "()V"));
        code.ret(l_ret);
      }
      handler.endFinally();
      handler.end();
    }
   
    context.popCode();
  }



  public int getTypeRef(ConstantPool pool)
  {
    return pool.addMethodRef(_parent.getTypeRef(pool),
      getDescriptor(), getSignature());
  }


  public void bindYieldState(int state)
  {
    if (_switch != null) {
      _switch.bindCase(state);
    }
  }

  public boolean callFinalizer()
  {
    if (_handler != null) {
      _handler.callFinally();
    }
    return false;
  }


  public VariableNode getReturnVariable()
  {
    return _return_var;
  }



}
TOP

Related Classes of anvil.script.statements.FunctionStatement

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.