Package anvil.script.statements

Source Code of anvil.script.statements.SwitchStatement

/*
* $Id: SwitchStatement.java,v 1.27 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.ErrorListener;
import anvil.Location;
import anvil.codec.Code;
import anvil.codec.ConstantPool;
import anvil.codec.Source;
import anvil.codec.Target;
import anvil.codec.Switch;
import anvil.parser.Tag;
import anvil.ErrorListener;
import anvil.script.compiler.ByteCompiler;
import anvil.script.Context;
import anvil.script.expression.Node;
import anvil.script.expression.Expression;
import anvil.script.expression.VariableNode;
import anvil.script.parser.TemplateParser;
import anvil.script.Grammar;
import anvil.java.util.BindingEnumeration;
import anvil.java.util.Hashlist;
import anvil.java.util.Holder;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.ArrayList;

/**
* class SwitchStatement
*
* @author: Jani Lehtim�ki
*/
public class SwitchStatement extends ScopedStatement implements Labeled
{
  public static final Any DEFAULT_MARKER =  new Any()
  {
    public int hashCode()
    {
      return System.identityHashCode(this);
    }
    public boolean equals(Object obj)
    {
      return this == obj;
    }
  };
 

  public static int ON_SWITCH = 0;
  public static int ON_CASE = 1;
  public static int ON_DEFAULT = 2;

  private Expression   _expression = null;
  private VariableNode _switch;
  private ArrayList    _cases     = new ArrayList();
  private Hashlist     _jumptable = new Hashlist();
  private Case         _currentCase = null;
  private Case         _defaultCase = null;
  private int          _state = ON_SWITCH;
  private String       _label = null;
  private Source       _startscope;
  private Source       _endscope;
  private boolean      _allconstant = true;


  public SwitchStatement(Statement parent, Location location)
  {
    super(parent, location);
  }


  public SwitchStatement(Statement parent, Location location, Expression expression, String label)
  {
    super(parent, location);
    _expression = expression;
    _label = label;
  }


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


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


  public String getLabel()
  {
    return _label;
  }
 
 
  public Case getCase(Any key)
  {
    if (_allconstant) {
      return (Case)_jumptable.get(key);
    }
    return null;
  }
 

  public Case getDefault()
  {
    return _defaultCase;
  }
   
 

  public void parse(TemplateParser parser, Tag tag)
  {
    String s = tag.getValue("expr");
    if (s == null) {
      s = tag.getValue("by");
    }
    _expression = Grammar.parseExpression(s, getLocation(), parser);
    _label = parseLabel(parser, tag);
  }


  public BlockStatement getBlockStatement()
  {
    if (_currentCase != null) {
      return _currentCase.getBlock();
    } else {
      return null;
    }
  } 
  

  public Statement getChildStatement()
  {
    if (_currentCase != null) {
      return _currentCase.getBlock();
    } else {
      return null;
    }
  }  


  public Case onCase(ErrorListener listener, Expression expr)
  {
    _state = ON_CASE;
    _currentCase = new Case(expr, new ImplicitBlockStatement(this, getLocation()));
    _cases.add(_currentCase);
    return _currentCase;
  }
 

  private Case onCase(TemplateParser parser, Tag tag)
  {
    String s = tag.getValue("value");
    if (s == null) {
      s = tag.getValue("of");
    }
    Expression value = Grammar.parseExpression(s, parser.getLocation(), parser);
    return onCase(parser, value);
  }


  public Case onDefault(ErrorListener listener, Location location)
  {
    if (_defaultCase != null) {
      listener.error(location, "Default already declared");
    }
    _state = ON_DEFAULT;
    _defaultCase = new Case(null, new ImplicitBlockStatement(this, location));
    _currentCase = _defaultCase;
    _cases.add(_defaultCase);
    return _currentCase;
  }


  public boolean onTag(TemplateParser parser, int type, Tag tag)
  {
    switch(type) {
    case Statement.ST_ENDSWITCH:
      parser.pop();
      break;

    case Statement.ST_ENDCASE:
      if (_state == ON_CASE) {
        _state = ON_SWITCH;
      } else {
        return false;
      }
      break;

    case Statement.ST_ENDDEFAULT:
      if (_state == ON_DEFAULT) {
        _state = ON_SWITCH;
      } else {
        return false;
      }
      break;

    case ST_CASE:
      onCase(parser, tag);
      break;

    case ST_DEFAULT:
      onDefault(parser, parser.getLocation());
      break;
     
    case ST_TAG:
      if (_state == ON_SWITCH) {
        return true;
      }

    default:
      if (_state != ON_SWITCH) {
        return super.onTag(parser, type, tag);
      } else {
        return false;
      }

    }

    return true;
  }


  public void onCharacters(TemplateParser parser, String cdata)
  {
    if (_state != ON_SWITCH) {
      super.onCharacters(parser, cdata);
    }
  }



  public void check(ErrorListener context)
  {
    _expression.check(context);

    Iterator iter = _cases.iterator();
    while(iter.hasNext()) {
      ((Case)iter.next()).checkExpression(context);
    }

    iter = _cases.iterator();
    while(iter.hasNext()) {
      Case caze = (Case)iter.next();
      if (caze.isDefault()) {
        _jumptable.put(DEFAULT_MARKER, caze);
      } else {
        Any value = caze.getConstant();
        if (value != null) {
          if (_jumptable.containsKey(value)) {
            context.error(caze.getLocation(), "Case value duplicated");
          } else {
            _jumptable.put(value, caze);
         
        } else {
          _allconstant = false;
          _jumptable.clear();
          break;
        }
      }
    }
   
    iter = _cases.iterator();
    while(iter.hasNext()) {
      ((Case)iter.next()).check(context);
    }

    if (!_allconstant) {
      FunctionStatement function = getFunctionStatement();
      if (function.isGenerator()) {
        _switch = new VariableNode(function.declare("switch$"+hashCode()));
      }
    }
  }


  public Jumps eliminate(ErrorListener context)
  {
    Jumps jumps = new Jumps();
    Iterator iter = _cases.iterator();
    while(iter.hasNext()) {
      jumps.merge(((Case)iter.next()).eliminate(context));
    }
    if (_defaultCase != null) {
      jumps.setBlocked(!jumps.hasBreak() && !jumps.hasContinue());
    } else {
      jumps.setBlocked(false);
    }
    return jumps.shift();
  }


  public boolean isBlocked()
  {
    if (_defaultCase == null) {
      return false;
    }
    Iterator iter = _cases.iterator();
    while(iter.hasNext()) {
      if (!((Case)iter.next()).getBlock().isBlocked()) {
        return false;
      }
    }
    return true;
  }



  public Source getStartOfScope()
  {
    return _startscope;
  }
 

  public Source getEndOfScope()
  {
    return _endscope;
  }
 

  public void compile(ByteCompiler context)
  {
    Code code = context.getCode();
    ConstantPool pool = code.getPool();
    Target start = code.getTarget();
    _startscope = code.getSource();
    _endscope = code.getSource();
   
    if (_allconstant) {
      boolean allNumeric = true;
      Enumeration enum = _jumptable.keys();
      while(enum.hasMoreElements()) {
        Any key = (Any)enum.nextElement();
        if (key != DEFAULT_MARKER) {
          if (!key.isInt()) {
            allNumeric = false;
            break;
          }
        }
      }

      if (_expression.needLineNumbers()) {
        context.location(_expression.getLocation());
      }

      Switch select;

      if (allNumeric) {
        _expression.compile(context, Expression.GET);
        code.invokevirtual(pool.addMethodRef(context.TYPE_ANY, "toInt", "()I"));

        select = code.select();
        enum = _jumptable.keys();
        while(enum.hasMoreElements()) {
          Any key = (Any)enum.nextElement();
          if (key != DEFAULT_MARKER) {
            select.addCase(key.toInt());
          }
        }
        select.end();

        enum = _jumptable.keysAndElements();
        while(enum.hasMoreElements()) {
          Case caze = (Case)enum.nextElement();
          if (caze.isDefault()) {
            select.bindDefault();
          } else {
            select.bindCase(caze.getConstant().toInt());
          }       
          caze.compile(context);
        }

      } else {
        int slot = context.addSwitch(_jumptable.keys());
        code.getstatic(pool.addFieldRef(context.TYPE_MODULE, "_switch", "[Lanvil/java/util/Hashlist;"));
        code.iconst(slot);
        code.aaload();
        _expression.compile(context, Expression.GET);
        code.invokestatic(pool.addMethodRef("anvil/script/compiler/CompiledModule",
          "switchCase", "(Lanvil/java/util/Hashlist;Lanvil/core/Any;)I"));

        select = code.select();
        int size = _jumptable.size();
        if (_defaultCase != null) {
          size--;
        }
        for(int key=0; key<size; key++) {
          select.addCase(key);
        }
        select.end();

        int key = 0;
        enum = _jumptable.elements();
        while(enum.hasMoreElements()) {
          Case caze = (Case)enum.nextElement();
          if (caze.isDefault()) {
            select.bindDefault();
          } else {
            select.bindCase(key++);
          }
          caze.compile(context);
        }
      }

      if (_defaultCase == null) {
        select.bindDefault();
      }
 
    } else {
      FunctionStatement function = getFunctionStatement();
      boolean in_generator = function.isGenerator();
      int l_key = 0;
      if (in_generator) {
        _switch.compile(context, new Node() {
          public void compile(ByteCompiler context, int operation) {
            _expression.compile(context, Expression.GET);
          }
        });
        code.pop();
      } else {
        _expression.compile(context, Expression.GET);
        l_key = code.addLocal();
        code.astore(l_key);
      }
      int equalsmethod = pool.addMethodRef(context.TYPE_OBJECT, "equals", "(Ljava/lang/Object;)Z");

      Iterator iter = _cases.iterator();
      while(iter.hasNext()) {
        Case caze = (Case)iter.next();
        if (!caze.isDefault()) {
          Expression expression = caze.getExpression();
          if (in_generator) {
            _switch.compile(context, Expression.GET);
          } else {
            code.aload(l_key);
          }
          if (expression.isConstant()) {
            context.constant(expression.eval(), false);
          } else {
            expression.compile(context, Expression.GET);
          }
          code.invokevirtual(equalsmethod);
          caze.if_ne(code);
        }
      }
     
      Source isdefault = null;
      if (_defaultCase != null) {
        _defaultCase.go_to(code);
      } else {
        code.go_to(_endscope);
      }

      iter = _cases.iterator();
      while(iter.hasNext()) {
        Case caze = (Case)iter.next();
        caze.compile(context);
      }

      if (!in_generator) {
        code.endLocal(l_key);
      }
    }
    _endscope.bind();
    _startscope.bind(start);

  }


}
TOP

Related Classes of anvil.script.statements.SwitchStatement

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.