Package macromedia.asc.semantics

Source Code of macromedia.asc.semantics.ConfigurationEvaluator

/*
*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You 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 macromedia.asc.semantics;

import static macromedia.asc.embedding.avmplus.RuntimeConstants.TYPE_boolean;
import static macromedia.asc.embedding.avmplus.RuntimeConstants.TYPE_int;
import static macromedia.asc.embedding.avmplus.RuntimeConstants.TYPE_number;
import static macromedia.asc.embedding.avmplus.RuntimeConstants.TYPE_double;
import static macromedia.asc.embedding.avmplus.RuntimeConstants.TYPE_decimal;
import static macromedia.asc.embedding.avmplus.RuntimeConstants.TYPE_string;
import static macromedia.asc.embedding.avmplus.RuntimeConstants.TYPE_uint_external;
import static macromedia.asc.parser.Tokens.*;

import java.util.HashSet;

import macromedia.asc.embedding.ErrorConstants;
import macromedia.asc.parser.*;
import macromedia.asc.util.Context;
import macromedia.asc.util.IntegerPool;
import macromedia.asc.util.Namespaces;
import macromedia.asc.util.ObjectList;
import macromedia.asc.util.NumberConstant;

public class ConfigurationEvaluator implements Evaluator, ErrorConstants {

  private boolean fold_expressions = false;

    private boolean top_level = false;
   
    private HashSet<String> config_namespaces = new HashSet<String>();
   
  private ObjectValue getBooleanObjectValue(Context cx, boolean b)
  {
    if( b )
    {
      return cx.booleanTrue();
    }
    else
    {
      return cx.booleanFalse();
    }
  }
  public boolean checkFeature(Context cx, Node node) {
    return true;
  }

  public Value evaluate(Context cx, Node node) {
    return null;
  }

  public Value evaluate(Context cx, IncrementNode node) {
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  public Value evaluate(Context cx, DeleteExpressionNode node) {
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  public Value evaluate(Context cx, IdentifierNode node) {
    return new ReferenceValue(cx, null, node.name, cx.publicNamespace());
  }

  public Value evaluate(Context cx, InvokeNode node) {
    node.args.evaluate(cx, this);
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  public Value evaluate(Context cx, ThisExpressionNode node) {
    return null;
  }

  public Value evaluate(Context cx, QualifiedIdentifierNode node) {
    Value result = null;

    Value val = node.qualifier != null ? node.qualifier.evaluate(cx, this) : null;
    AttributeListNode attrs = ((node.qualifier instanceof AttributeListNode) ? (AttributeListNode)node.qualifier : null);
        if( attrs != null && attrs.items != null && attrs.items.size() == 1)
        {
          // We are probably in a variable definition
          val = attrs.items.at(0).evaluate(cx, this);
        ReferenceValue ref = val instanceof ReferenceValue ? (ReferenceValue)val : null;
        if( ref != null )
        {
          Slot s = ref.getSlot(cx);
          if( s != null && s.getObjectValue() != null && s.getObjectValue().isConfigNS() )
          {
            ReferenceValue temp = new ReferenceValue(cx, null, node.name, s.getObjectValue());
            temp.setPosition(node.qualifier.getPosition());
            result = temp;
           
          }
        }
        }
        else if( val instanceof ReferenceValue )
        {
          ReferenceValue ref = (ReferenceValue)val;
          Slot s = ref.getSlot(cx);
          if ( s != null && s.getObjectValue() != null && s.getObjectValue().isConfigNS() )
          {
            ReferenceValue temp = new ReferenceValue(cx, null, node.name, s.getObjectValue());
            temp.setPosition(node.getPosition());
            result = temp;
          }
        }
    return result;
  }

  public Value evaluate(Context cx, QualifiedExpressionNode node) {
    return null// Should this do anything?
  }

  public Value evaluate(Context cx, LiteralBooleanNode node) {
        return getBooleanObjectValue(cx, node.value);
  }

  public Value evaluate(Context cx, LiteralNumberNode node) {
        TypeValue[] type = new TypeValue[1];
        node.numericValue = cx.getEmitter().getValueOfNumberLiteral( node.value, type, node.numberUsage);
        node.type = type[0];
        return new ObjectValue(node.value, node.type);
  }

  public Value evaluate(Context cx, LiteralStringNode node) {
    return new ObjectValue(node.value, cx.stringType());
  }

  public Value evaluate(Context cx, LiteralNullNode node) {
    return null;
  }

  public Value evaluate(Context cx, LiteralRegExpNode node) {
    return null;
  }

  public Value evaluate(Context cx, LiteralXMLNode node) {
    return null;
  }

  public Value evaluate(Context cx, FunctionCommonNode node) {
    node.signature.evaluate(cx, this);
   
    ConfigurationBuilder config_bui = new ConfigurationBuilder();
    ObjectValue scope = new ObjectValue(cx, config_bui, null);
    cx.pushScope(scope);
   
    node.body.evaluate(cx, this);
   
    cx.popScope();
   
    return null;
  }

  public Value evaluate(Context cx, ParenExpressionNode node) {
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  public Value evaluate(Context cx, ParenListExpressionNode node) {
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  private void evalArrayOrObjectArgList(Context cx, ArgumentListNode list)
  {
    if( list != null )
    {
      for ( int i = list.size()-1; i > 0; --i)
      {
        Node n = list.items.at(i);
        ListNode l = n instanceof ListNode ? (ListNode)n : null;
        if( l != null && l.size()==2 && l.items.at(0).isConfigurationName() )
        {
          Value config_val = l.items.at(0).evaluate(cx, this);
         
          if( config_val != null && config_val.isReference() && ((ReferenceValue)config_val).isConfigRef())
          {
            ReferenceValue r = (ReferenceValue)config_val;
                  Value v = config_val.getValue(cx);
                  if( v == null )
                  {
                    cx.error(r.getPosition(), kError_UnfoundProperty, r.name);
                  }
                  else
                  {
                      Boolean b = toBoolean(cx, (ObjectValue)r.getValue(cx));
                      if( b != null && b.booleanValue())
                      {
                        list.items.set(i, l.items.at(1));
                      }
                      else
                      {
                        list.items.remove(i);
                      }
                  }
          }
        }
      }
    }
  }
  public Value evaluate(Context cx, LiteralObjectNode node) {
    if( node.fieldlist!= null )
    {
      evalArrayOrObjectArgList(cx, node.fieldlist);
      node.fieldlist.evaluate(cx, this);
    }
    return null;
  }

  public Value evaluate(Context cx, LiteralFieldNode node) {
        node.name = evalAndFold(cx, node.name);
        node.value = evalAndFold(cx, node.value);
    return null;
  }

  public Value evaluate(Context cx, LiteralArrayNode node) {
    if( node.elementlist != null )
    {
      evalArrayOrObjectArgList(cx, node.elementlist);
      node.elementlist.evaluate(cx, this);
    }
    return null;
  }
 
  public Value evaluate(Context cx, LiteralVectorNode node) {
    node.type.evaluate(cx, this);
    if( node.elementlist != null )
    {
      evalArrayOrObjectArgList(cx, node.elementlist);
      node.elementlist.evaluate(cx, this);
    }
    return null;
  }

  public Value evaluate(Context cx, SuperExpressionNode node) {
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  public Value evaluate(Context cx, SuperStatementNode node) {
    node.call.evaluate(cx, this);
    return null;
  }

  public Value evaluate(Context cx, MemberExpressionNode node) {
    if( node.base != null )
    {
      node.base = evalAndFold(cx, node.base);
    }
    Value val = node.selector.evaluate(cx, this);
    return val;
  }

  public Value evaluate(Context cx, CallExpressionNode node) {
    if( node.args != null ) node.args.evaluate(cx, this);
    return null;
  }

  public Value evaluate(Context cx, GetExpressionNode node) {
        Value val = node.expr.evaluate(cx,this);
    return val;
  }

    public Value evaluate(Context cx, ApplyTypeExprNode node)
    {
        return null;
    }
   
    public Value evaluate(Context cx, SetExpressionNode node) {
    node.args.evaluate(cx, this);
    return null;
  }

  private Boolean toBoolean(Context cx, ObjectValue obj)
  {
    Boolean ret = null;
    TypeInfo ti = obj.getType(cx);
    TypeValue tv = ti != null ? ti.getTypeValue() : null;
    if ( tv != null )
    {
      if( tv == cx.booleanType() )
      {
        ret = obj.booleanValue() ? Boolean.TRUE : Boolean.FALSE;
      }
      else if( tv == cx.stringType() )
      {
        String s = obj.getValue();
        if( s == null || "".equals(s) )
          ret = Boolean.FALSE;
        else
          ret = Boolean.TRUE;
      }
      else if( isNumericType(cx, tv) )
      {
                TypeValue[] type = new TypeValue[1];
                double d = cx.getEmitter().getValueOfNumberLiteral( obj.getValue(), type, obj.getNumberUsage()).doubleValue();
                if( Double.isNaN(d) || d == 0.0 )
                  ret = Boolean.FALSE;
                else
                  ret = Boolean.TRUE;
      }
    }
    return ret;
  }

  private String toString(Context cx, ObjectValue obj)
  {
    String ret = null;
    TypeInfo ti = obj.getType(cx);
    TypeValue tv = ti != null ? ti.getTypeValue() : null;
    if ( tv != null )
    {
      if( tv == cx.booleanType() )
      {
        ret = obj.booleanValue() ? "true" : "false";
      }
      else if( tv == cx.stringType() )
      {
        ret = obj.getValue();
      }
      else if( isNumericType(cx, tv) )
      {
                TypeValue[] type = new TypeValue[1];
                NumberConstant v = cx.getEmitter().getValueOfNumberLiteral( obj.getValue(), type, obj.getNumberUsage());
                ret = v.toString();
      }
    }
    return ret;
  }

  private Double toNumber(Context cx, ObjectValue obj)
  {
    Double ret = null;
    TypeInfo ti = obj.getType(cx);
    TypeValue tv = ti != null ? ti.getTypeValue() : null;
    if ( tv != null )
    {
      if( tv == cx.booleanType() )
      {
        ret = new Double(obj.booleanValue() ? 1 : 0);
      }
      else if( tv == cx.stringType() || isNumericType(cx, tv))
      {
                TypeValue[] type = new TypeValue[1];
                try
                {
                  ret = cx.getEmitter().getValueOfNumberLiteral( obj.getValue(), type, obj.getNumberUsage()).doubleValue();
                }
                catch(NumberFormatException nfe)
                {
                  // must not be a number
                }
      }
    }
    return ret;
  }
 
  private Integer toInt(Context cx, ObjectValue obj)
  {
    Integer i = null;
    Double d = toNumber(cx, obj);
    if( d != null )
    {
      if( d.isInfinite() || d.isNaN() || d.doubleValue() == 0.0 )
        i = IntegerPool.getNumber(0);
      else
        i = IntegerPool.getNumber((int)d.doubleValue());
    }
    return i;
  }

  private Long toUInt(Context cx, ObjectValue obj)
  {
    Long l = null;
    Double d = toNumber(cx, obj);
    if( d != null )
    {
      if( d.isInfinite() || d.isNaN() || d.doubleValue() == 0.0 )
        l = new Long(0);
      else
        l = new Long((long)d.doubleValue());
    }
    return l;
  }
 
  public Value evaluate(Context cx, UnaryExpressionNode node) {
    Value val = null;
    if( fold_expressions )
    {
      Value expr_val = node.expr.evaluate(cx, this);
     
      Node new_expr = foldRefValue(cx, expr_val);
      if( new_expr != null )
      {
        node.expr = new_expr;
        expr_val = node.expr.evaluate(cx, this);
      }
     
      if( expr_val != null && expr_val.hasValue() )
      {
        ObjectValue expr_ov = (ObjectValue)expr_val;
       
        switch( node.op )
        {
        case NOT_TOKEN:
          Boolean b = toBoolean(cx, expr_ov);
          if( b != null )
            val = getBooleanObjectValue(cx, !b);
          break;
        }
      }
    }
    else
    {
      node.expr = evalAndFold(cx, node.expr);
    }
    return val;
  }

  public Value evaluate(Context cx, BinaryExpressionNode node) {
    Value val = null;
    if( fold_expressions )
    {
      Value lhs_val = node.lhs.evaluate(cx, this);
      Value rhs_val = node.rhs.evaluate(cx, this);
     
      Node new_lhs = foldRefValue(cx, lhs_val);
      Node new_rhs = foldRefValue(cx, rhs_val);
      if( new_lhs != null )
      {
        node.lhs = new_lhs;
        lhs_val = node.lhs.evaluate(cx, this);
      }
      if( new_rhs != null )
      {
        node.rhs = new_rhs;
        rhs_val = node.rhs.evaluate(cx, this);
      }
     
      if( lhs_val != null && rhs_val != null && lhs_val.hasValue() && rhs_val.hasValue() )
      {
        ObjectValue lhs_ov = (ObjectValue)lhs_val;
        ObjectValue rhs_ov = (ObjectValue)rhs_val;
       
        TypeValue lt = lhs_ov.getType(cx).getTypeValue();
        TypeValue rt = rhs_ov.getType(cx).getTypeValue();
       
        switch(node.op)
        {
        case PLUS_TOKEN:
          if( isNumericType(cx, lt) && isNumericType(cx, rt) )
          {
                      TypeValue[] type = new TypeValue[1];
                      double ld = cx.getEmitter().getValueOfNumberLiteral( lhs_ov.getValue(), type, node.numberUsage).doubleValue();
                      double rd = cx.getEmitter().getValueOfNumberLiteral( rhs_ov.getValue(), type, node.numberUsage).doubleValue();
                      double d = 0.0/0;
                      d = ld + rd;
                      val = new ObjectValue(Double.toString(d), cx.numberType());
          }
          else if( lt == cx.stringType() || rt == cx.stringType() )
          {
                      String ls = toString(cx, lhs_ov);
                      String rs = toString(cx, rhs_ov);
                      val = new ObjectValue(ls+rs,cx.stringType());
          }
          break;
              case MINUS_TOKEN:
              case MULT_TOKEN:
              case DIV_TOKEN:
              case MODULUS_TOKEN:
                if( isNumericType(cx, lt) && isNumericType(cx, rt) )
                {
                      TypeValue[] type = new TypeValue[1];
                      double ld = cx.getEmitter().getValueOfNumberLiteral( lhs_ov.getValue(), type, node.numberUsage).doubleValue();
                      double rd = cx.getEmitter().getValueOfNumberLiteral( rhs_ov.getValue(), type, node.numberUsage).doubleValue();
                      double d = 0.0/0;
                      switch( node.op )
                      {
                      case MINUS_TOKEN:
                          d = ld-rd;
                          break;
                      case MULT_TOKEN:
                          d = ld*rd;
                          break;
                      case DIV_TOKEN:
                          d = ld/rd;
                          break;
                      case MODULUS_TOKEN:
                          d = ld%rd;
                          break;
                      }
                      val = new ObjectValue(Double.toString(d), cx.numberType());
                      break;
                }
        case LOGICALOR_TOKEN:
        {
          Boolean b = toBoolean(cx, lhs_ov);
          Boolean b2 = toBoolean(cx, rhs_ov);
          if( b != null && b2 != null )
          {
            val = getBooleanObjectValue(cx, b.booleanValue() || b2.booleanValue());
          }
          break;
        }
        case LOGICALAND_TOKEN:
        {
          Boolean b = toBoolean(cx, lhs_ov);
          Boolean b2 = toBoolean(cx, rhs_ov);
          if( b != null && b2 != null )
          {
            val = getBooleanObjectValue(cx, b.booleanValue() && b2.booleanValue());
          }
          break;
        }
        case EQUALS_TOKEN:
        case NOTEQUALS_TOKEN:
        {
          Boolean b = compare(cx, lhs_ov, rhs_ov);
          if( b != null )
            if( node.op == NOTEQUALS_TOKEN)
              val = getBooleanObjectValue(cx, !b.booleanValue());
            else
              val = getBooleanObjectValue(cx, b.booleanValue());
          break;
        }
       
        case LESSTHAN_TOKEN:
        case GREATERTHANOREQUALS_TOKEN:
        {
          String less_result = lessthan(cx, lhs_ov, rhs_ov);
          Boolean b = null;
          if( node.op == LESSTHAN_TOKEN )
          {
            if( less_result == UNDEFINED || less_result == FALSE )
              b = Boolean.FALSE;
            else
              b = Boolean.TRUE ;
          }
          else
          {
            if( less_result == UNDEFINED || less_result == TRUE )
              b = Boolean.FALSE;
            else
              b = Boolean.TRUE;
          }
          if( b != null )
            val = getBooleanObjectValue(cx, b.booleanValue());
          break;
        }
       
        case LESSTHANOREQUALS_TOKEN:
        case GREATERTHAN_TOKEN:
        {
          String less_result = lessthan(cx, rhs_ov, lhs_ov);
          Boolean b = null;
          if( node.op == LESSTHANOREQUALS_TOKEN )
          {
            if( less_result == UNDEFINED || less_result == TRUE )
              b = Boolean.FALSE;
            else
              b = Boolean.TRUE ;
          }
          else
          {
            if( less_result == UNDEFINED || less_result == FALSE )
              b = Boolean.FALSE;
            else
              b = Boolean.TRUE;
          }
          if( b != null )
            val = getBooleanObjectValue(cx, b.booleanValue());
          break;
        }
       
        case LEFTSHIFT_TOKEN:
        case RIGHTSHIFT_TOKEN:
        {
          Integer li  = toInt(cx, lhs_ov);
          Integer ri = toInt(cx, rhs_ov) ;
          if( li != null && ri != null )
          {
            ri = ri & 0x1F;
            if( node.op == LEFTSHIFT_TOKEN )
              val = new ObjectValue(String.valueOf(li << ri), cx.intType());
            else
              val = new ObjectValue(String.valueOf(li >> ri), cx.intType());
          }
          break;
        }
        case UNSIGNEDRIGHTSHIFT_TOKEN:
        {
          Long ll  = toUInt(cx, lhs_ov);
          Long rl = toUInt(cx, rhs_ov);
          if( ll != null && rl != null )
          {
            rl = rl & 0x1F;
            val = new ObjectValue(String.valueOf(ll >>> rl), cx.intType());
          }
          break;
        }
       
        case BITWISEAND_TOKEN:
        case BITWISEXOR_TOKEN:
        case BITWISEOR_TOKEN:
        {
          Integer li = toInt(cx, lhs_ov);
          Integer ri = toInt(cx, rhs_ov);
          if( li != null && ri != null )
          {
            int result = 0;
            switch(node.op)
            {
            case BITWISEAND_TOKEN:
              result = li & ri;
              break;
            case BITWISEOR_TOKEN:
              result = li | ri;
              break;
            case BITWISEXOR_TOKEN:
              result = li ^ ri;
              break;
            }
            val = new ObjectValue(String.valueOf(result), cx.intType());
          }
        }
        }

      }
    }
    else
    {
      node.lhs = evalAndFold(cx, node.lhs);
      node.rhs = evalAndFold(cx, node.rhs);
    }
    return val;
  }

  static final String UNDEFINED = "undefined";
  static final String TRUE = "true";
  static final String FALSE = "false";
 
  private String lessthan(Context cx, ObjectValue lhs, ObjectValue rhs)
  {
    Double ld = toNumber(cx, lhs);
    Double rd = toNumber(cx, rhs);
   
    if( ld != null && rd != null )
    {
      if( ld.isNaN() || rd.isNaN() )
        return UNDEFINED;
     
      if( ld.doubleValue() == rd.doubleValue() )
        return FALSE;
     
      if( ld.isInfinite() )
      {
        if( ld.doubleValue() > 0)
          return FALSE;
        else
          return TRUE;
      }
     
      if( rd.isInfinite() )
      {
        if( rd.doubleValue() < 0 )
          return FALSE;
        else
          return TRUE;
      }
     
      if( ld.doubleValue() < rd.doubleValue() )
        return TRUE;
      else
        return FALSE;
    }
    return null;
  }
 
  private Boolean compare(Context cx, ObjectValue lhs, ObjectValue rhs)
  {
    if( lhs!= null && lhs.hasValue() && rhs != null && rhs.hasValue() )
    {
      if( lhs == rhs )
        return Boolean.TRUE;
     
      TypeValue rhs_type = rhs.getType(cx).getTypeValue();
      TypeValue lhs_type = lhs.getType(cx).getTypeValue();
     
      if( lhs_type == rhs_type )
      {
        if( lhs_type == cx.stringType() )
        {
          return lhs.getValue().equals(toString(cx, rhs));
        }
        else if( lhs_type == cx.booleanType() )
        {
          Boolean b1 = toBoolean(cx, lhs);
          Boolean b2 = toBoolean(cx, rhs);
          if( b1.booleanValue() == b2.booleanValue() )
            return Boolean.TRUE;
          else
            return Boolean.FALSE;
        }
        else if( isNumericType(cx, lhs_type) )
        {
          Double d1 = toNumber(cx, lhs);
          Double d2 = toNumber(cx, rhs);
          if( d1.doubleValue() == d2.doubleValue() )
            return Boolean.TRUE;
          else
            return Boolean.FALSE;
        }
      }
      else
      {
        if( (isNumericType(cx,lhs_type) && isNumericType(cx, rhs_type)) ||
          (isNumericType(cx, lhs_type) && rhs_type == cx.stringType()) ||
          (lhs_type == cx.stringType() && isNumericType(cx, rhs_type)) ||
          lhs_type == cx.booleanType() || rhs_type == cx.booleanType() )
        {
          Double d1 = toNumber(cx, lhs);
          Double d2 = toNumber(cx, rhs);
          if( d1 != null && d2 != null && d1.doubleValue() == d2.doubleValue() )
            return Boolean.TRUE;
          else
            return Boolean.FALSE;
        }
      }
    }
    return Boolean.FALSE;
  }
 
  private ObjectValue numberObjVal(Context cx, double d)
  {
    return new ObjectValue(String.valueOf(d), cx.numberType());
  }
 
  private boolean isNumericType(Context cx, TypeValue typeval)
  {
    return (typeval == cx.numberType() || typeval == cx.intType() || typeval == cx.uintType());
  }
  public Value evaluate(Context cx, ConditionalExpressionNode node) {
    node.condition = evalAndFold(cx, node.condition);
    node.thenexpr = evalAndFold(cx, node.thenexpr);
    node.elseexpr = evalAndFold(cx, node.elseexpr);
    return null;
  }

  public Value evaluate(Context cx, ArgumentListNode node) {
      for (int i = 0, size = node.items.size(); i < size; i++)
        {
          Node n = node.items.get(i);
            Node temp = null;
            if (n != null)
            {
                temp = evalAndFold(cx, n);
                if( temp != n )
                    node.items.set(i, temp);
            }
        }
      return null;
  }

  public Value evaluate(Context cx, ListNode node) {
    Value val = null;
    for( int i = 0, size = node.items.size(); i < size; ++i)
    {
      Node n = node.items.at(i);
      val = n.evaluate(cx, this);
      Node temp = foldRefValue(cx, val);
      if( temp != null )
      {
        node.items.set(i, temp);
        val = temp.evaluate(cx, this);
      }
    }
    return val;
  }

  public Value evaluate(Context cx, StatementListNode node) {
        NodeFactory nodeFactory = cx.getNodeFactory();

        if( node.config_attrs != null )
        {
          node.config_attrs.evaluate(cx, this);
        if( node.config_attrs.compileDefinition == false)
          node.items.clear();
        node.config_attrs = null;
        }

        for (int i = 0, size = node.items.size(); i < size; ++i)
        {
          Node n = node.items.at(i);
          if( n != null && n.isDefinition() )
          {
            DefinitionNode def = (DefinitionNode)n;
            if( def.attrs != null )
            {
              def.attrs.evaluate(cx, this);
             
              if( !def.attrs.compileDefinition )
              {
                node.items.set(i,nodeFactory.emptyStatement());
                        removeMetaData(cx, def, node, i);
                continue;
              }
            }
               
                boolean old_toplevel = top_level;
                if( !( def instanceof ConfigNamespaceDefinitionNode || def instanceof VariableDefinitionNode) )
                    top_level = false;
         
                def.evaluate(cx, this);
               
                top_level = old_toplevel;
               
          if( def instanceof VariableDefinitionNode )
          {
            VariableDefinitionNode vardef = (VariableDefinitionNode)def;
            if( vardef.list.items.size() == 0 )
                    {
                        removeMetaData(cx, vardef, node, i);
              node.items.set(i, nodeFactory.emptyStatement());
                    }
          }
          }
            else if ( n instanceof StatementListNode )
            {
                StatementListNode stmt = (StatementListNode)n;
                if( stmt.config_attrs != null )
                {
                    stmt.config_attrs.evaluate(cx, this);
                    if( stmt.config_attrs.compileDefinition )
                    {
                        // Look for previous Metadata/DocComments if the stmtlist starts with a definition
                        DefinitionNode def;
                        if( (def = startsWithDefinition(cx, stmt)) != null )
                        {
                            for( int m = i-1; m >= 0; --m)
                            {
                                Node temp = node.items.at(m);
                                if( temp instanceof MetaDataNode)
                                {
                                    MetaDataNode metadata = (MetaDataNode)temp;
                                    metadata.def = def;
                                    def.addMetaDataNode(metadata);
                                }
                                else if( !(temp instanceof IncludeDirectiveNode || temp instanceof EmptyStatementNode) )
                                {
                                    break;
                                }
                            }
                        }
                        if( stmt.last() instanceof MetaDataNode && ((def = findNextDefinition(cx, node, i+1))!= null))
                        {
                            for( int m = stmt.items.size()-1; m >= 0; --m)
                            {
                                Node temp = stmt.items.at(m);
                                if( temp instanceof MetaDataNode )
                                {
                                    MetaDataNode metadata = (MetaDataNode)temp;
                                    metadata.def = def;
                                    def.addMetaDataNode(metadata);
                                }
                                else if( !(temp instanceof IncludeDirectiveNode || temp instanceof EmptyStatementNode) )
                                {
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        node.items.set(i, nodeFactory.emptyStatement());
                    }
                    stmt.config_attrs = null;
                }
                n = node.items.at(i);
                Node temp = evalAndFold(cx, n);
                if( temp != n )
                    node.items.set(i, temp);
            }
            else
          {
               
                boolean old_topLevel = top_level;
                if( !(n instanceof StatementListNode) )
                {
                   
                    top_level = false;
                }
               
            Node temp = evalAndFold(cx, n);
            if( temp != n )
              node.items.set(i, temp);
               
                if( !(n instanceof StatementListNode) )
                {
                    top_level = old_topLevel;
                }
          }
        }
       
        return null;
  }

    // Helper function to clean up the metadata nodes that had pointed
    // to a removed defintion.
    private void removeMetaData(Context cx, DefinitionNode def, StatementListNode list, int def_index)
    {
        if( def.metaData != null )
        {
            NodeFactory nf = cx.getNodeFactory();
            for( int i = def_index-1; i >= 0; --i )
            {
                Node temp = list.items.at(i);
                MetaDataNode meta = temp instanceof MetaDataNode ? (MetaDataNode)temp : null;
                if( meta != null && meta.def == def )
                {
                    list.items.set(i, nf.emptyStatement());
                    meta.def = null;
                }
                else if( !(temp instanceof IncludeDirectiveNode) )
                {
                    break;
                }
               
            }
            def.metaData = null;
        }       
    }

    // Returns the next definition node in the list starting from start
    // This skips over metadata, comments, etc, to find the next definition node
    // returns null if a definition is not found.
    private DefinitionNode findNextDefinition(Context cx, StatementListNode list, int start)
    {
        DefinitionNode def = null;
        for( int i =start, l=list.items.size(); i < l; ++i)
        {
            Node n = list.items.at(i);
            if( n instanceof MetaDataNode || n instanceof IncludeDirectiveNode )
            {
                continue;
            }
            if( n instanceof DefinitionNode )
            {
                def = (DefinitionNode)n;
            }
            break;
        }
        return def;
    }

    // Returns the first definition node if the list starts with a definition
    // This skips over metadata, comments, etc, to find the first definition node
    // returns null if the list does not start with a definition.
    private DefinitionNode startsWithDefinition(Context cx, StatementListNode list)
    {
        return findNextDefinition(cx, list, 0);
    }

    private Node evalAndFold(Context cx, Node n)
    {
      Node ret = n;
        if( n != null )
        {
          Value val = n.evaluate(cx, this);
          ret = foldRefValue(cx, val);
          if( ret == null )
            ret = n;
        }
        return ret;
    }

    // Generates a new literal node if val is a reference to a configuration variable
    private Node foldRefValue(Context cx, Value val)
    {
        Node ret = null;
       
        ReferenceValue ref_val = val instanceof ReferenceValue ? (ReferenceValue)val : null;
       
        if( ref_val != null )
        {
            if( ref_val.isConfigRef() )
            {
              Value v = ref_val.getValue(cx);
              if( v == null )
              {
                cx.error(ref_val.getPosition(), kError_UnfoundProperty, ref_val.name);
              }
              else
              {
                  ret = literalFromValue(cx, v);
              }
                if( ret != null )
                  ret.evaluate(cx, this);
            }
        }
       
        return ret;
    }

    private Node literalFromValue(Context cx, Value val)
    {
        Node ret = null;
       
        if( val instanceof ObjectValue )
        {
            ObjectValue obj_val = val instanceof ObjectValue ? (ObjectValue)val : null;
           
            if( obj_val != null )
            {
                Node literal_node = null;
                switch(obj_val.getType(cx).getTypeId())
                {
                    case TYPE_string:
                        literal_node = cx.getNodeFactory().literalString(obj_val.getValue());
                        break;
                    case TYPE_boolean:
                        literal_node = cx.getNodeFactory().literalBoolean(obj_val.booleanValue());
                        break;
                    case TYPE_number:
                    case TYPE_int:
                    case TYPE_uint_external:
                    case TYPE_decimal:
                    case TYPE_double:
                        literal_node = cx.getNodeFactory().literalNumber(obj_val.getValue());
                        break;
                }
                ret = literal_node;
            }
        }
        return ret;
    }
   
  public Value evaluate(Context cx, EmptyElementNode node) {
    return null;
  }

  public Value evaluate(Context cx, EmptyStatementNode node) {
    return null;
  }

  public Value evaluate(Context cx, ExpressionStatementNode node) {
    Value val;
    val = node.expr.evaluate(cx, this);
    Node temp = foldRefValue(cx, val);
    if( temp != null )
    {
      node.expr = temp;
      val = temp.evaluate(cx, this);
    }
    return val;
  }

  public Value evaluate(Context cx, LabeledStatementNode node) {
    node.label = evalAndFold(cx, node.label);
    node.statement = evalAndFold(cx, node.statement);
    return null;
  }

  public Value evaluate(Context cx, IfStatementNode node) {
    node.condition = evalAndFold(cx, node.condition);
    node.thenactions = evalAndFold(cx, node.thenactions);
    node.elseactions = evalAndFold(cx, node.elseactions);
    return null;
  }

  public Value evaluate(Context cx, SwitchStatementNode node) {
    node.expr = evalAndFold(cx, node.expr);
        if( node.statements != null)
            node.statements.evaluate(cx, this);
    return null;
  }

  public Value evaluate(Context cx, CaseLabelNode node) {
    node.label = evalAndFold(cx, node.label);
    return null;
  }

  public Value evaluate(Context cx, DoStatementNode node) {
    node.expr = evalAndFold(cx, node.expr);
    node.statements = evalAndFold(cx, node.statements);
    return null;
  }

  public Value evaluate(Context cx, WhileStatementNode node) {
    node.expr = evalAndFold(cx, node.expr);
    node.statement = evalAndFold(cx, node.statement);
    return null;
  }

  public Value evaluate(Context cx, ForStatementNode node) {
    node.initialize = evalAndFold(cx, node.initialize);
    node.test = evalAndFold(cx, node.test);
    node.increment = evalAndFold(cx, node.increment);
    node.statement = evalAndFold(cx, node.statement);
    return null;
  }

  public Value evaluate(Context cx, WithStatementNode node) {
    node.expr = evalAndFold(cx, node.expr);
    node.statement = evalAndFold(cx, node.statement);
    return null;
  }

  public Value evaluate(Context cx, ContinueStatementNode node) {
    return null;
  }

  public Value evaluate(Context cx, BreakStatementNode node) {
    return null;
  }

  public Value evaluate(Context cx, ReturnStatementNode node) {
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  public Value evaluate(Context cx, ThrowStatementNode node) {
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  public Value evaluate(Context cx, TryStatementNode node) {
    if( node.tryblock != null )
      node.tryblock.evaluate(cx, this);
    if(node.catchlist != null)
      node.catchlist.evaluate(cx, this);
    if( node.finallyblock != null )
      node.finallyblock.evaluate(cx, this);
    return null;
  }

  public Value evaluate(Context cx, CatchClauseNode node) {
    if( node.parameter != null )
      node.parameter = evalAndFold(cx, node.parameter);
    if( node.statements != null )
      node.statements.evaluate(cx, this);
    return null;
  }

  public Value evaluate(Context cx, FinallyClauseNode node) {
    if( node.default_catch != null )
      node.default_catch.evaluate(cx, this);
    if( node.statements != null )
      node.statements.evaluate(cx, this);
    return null;
  }

  public Value evaluate(Context cx, UseDirectiveNode node) {
    // TODO use number pragmas
    return null;
  }

  public Value evaluate(Context cx, IncludeDirectiveNode node) {
    return null;
  }

  public Value evaluate(Context cx, ImportNode node) {
    return null;
  }

  public Value evaluate(Context cx, MetaDataNode node) {
        this.evaluate(cx, node.data);
        return null;
  }

  public Value evaluate(Context cx, DocCommentNode node) {
    return null;
  }

  public Value evaluate(Context cx, ImportDirectiveNode node) {
    return null;
  }

  public Value evaluate(Context cx, AttributeListNode node) {
    ObjectValue obj = null;
    for( int i = 0, size = node.items.size(); i < size; ++i )
    {
      Node n = node.items.at(i);
          Value val1 = n.evaluate(cx,this);
 
            obj = ((val1 instanceof ObjectValue) ? (ObjectValue)val1 : null);
            if( obj!=null )
            {
                if( i == size-1 &&
                    obj.getType(cx).getTypeValue() == cx.booleanType()  )
                {
                    node.compileDefinition = obj.booleanValue();
                    node.items.removeLast();
                }
            }
    }
    return null;
  }

  public Value evaluate(Context cx, VariableDefinitionNode node) {
    node.list.evaluate(cx, this);
    for( int i = node.list.items.size()-1 ; i >= 0; --i )
    {
      Node n = node.list.items.at(i);
      if( n instanceof VariableBindingNode )
      {
        VariableBindingNode var_bind = (VariableBindingNode)n;
        if(var_bind.ref != null && var_bind.ref.isConfigRef() )
                {
          node.list.items.removeLast();
                }
      }
    }
    return null;
  }

  public Value evaluate(Context cx, VariableBindingNode node) {
        Value val = node.variable.identifier.evaluate(cx,this);
        ReferenceValue ref = ((val instanceof ReferenceValue) ? (ReferenceValue)val : null);
       
        if( ref != null && ref.isConfigRef() )
        {
            if( !isTopLevel() )
            {
                cx.error(node.pos(), kError_InvalidConfigLocation);
                return null;
            }

        ObjectValue obj = cx.scope();
        Builder bui = obj.builder;
        Namespaces hasNamespaces = obj.hasNames(cx, GET_TOKEN, ref.name, ref.namespaces);
        if( hasNamespaces == null )
        {
                int var_id, slot_id;
                var_id  = bui.Variable(cx,obj);
                // TODO: does the type of the slot matter?
                slot_id = bui.ExplicitVar(cx,obj,ref.name,ref.namespaces,cx.noType(),-1,-1,var_id);
                Slot slot = obj.getSlot(cx,slot_id);
                if( node.kind != Tokens.CONST_TOKEN)
                {
                  cx.error(node.attrs.pos(),kError_NonConstConfigVar );
                }
                slot.setConst(true);
            if( node.initializer == null )
            {
                  cx.error(node.pos(), kError_NonConstantConfigInit);
            }
            else
            {
              // Turn on constant folding for expressions. 
              boolean old_fold = fold_expressions;
              fold_expressions = true;
                  Value init_val = node.initializer.evaluate(cx, this);
                  fold_expressions = old_fold;
                  if( init_val == null || !init_val.hasValue() )
                  {
                    cx.error(node.initializer.pos(), kError_NonConstantConfigInit);
                  }
              slot.setValue(init_val);
            }
            node.ref = ref;
        }
            else
            {
                cx.error(node.variable.identifier.pos(), kError_ConflictingNameInNamespace, ref.name, ref.namespaces.at(0).name);
            }
        }
        else
        {
          node.initializer = evalAndFold(cx, node.initializer);
        }
    return null;
  }

  public Value evaluate(Context cx, UntypedVariableBindingNode node) {
    // not used
    return null;
  }

  public Value evaluate(Context cx, TypedIdentifierNode node) {
    return node.identifier.evaluate(cx, this);
  }

  public Value evaluate(Context cx, TypeExpressionNode node) {
    return null;
  }

  public Value evaluate(Context cx, FunctionDefinitionNode node) {
    node.fexpr.evaluate(cx, this);
    return null;
  }

  public Value evaluate(Context cx, BinaryFunctionDefinitionNode node) {
    return null;
  }

  public Value evaluate(Context cx, FunctionNameNode node) {
    return null;
  }

  public Value evaluate(Context cx, FunctionSignatureNode node) {
    if( node.parameter != null ) node.parameter.evaluate(cx, this);
    if( node.result != null ) node.result.evaluate(cx, this);
    return null;
  }

  public Value evaluate(Context cx, ParameterNode node) {
    node.init = evalAndFold(cx, node.init);
    return null;
  }

  public Value evaluate(Context cx, ParameterListNode node) {
    for( int i = 0, size = node.items.size(); i < size; ++i )
    {
      ParameterNode n = node.items.at(i);
      n.evaluate(cx, this);
    }
     
    return null;
  }

  public Value evaluate(Context cx, RestExpressionNode node) {
    return null;
  }

  public Value evaluate(Context cx, RestParameterNode node) {
    return null;
  }

  public Value evaluate(Context cx, InterfaceDefinitionNode node) {
    return this.evaluate(cx, (ClassDefinitionNode)node);
  }

  public Value evaluate(Context cx, ClassDefinitionNode node) {
    ConfigurationBuilder config_bui = new ConfigurationBuilder();
    ObjectValue scope = new ObjectValue(cx, config_bui, null);
    cx.pushScope(scope);

    if( node.statements != null )node.statements.evaluate(cx, this);
   
    cx.popScope();
   
    return null;
  }

  public Value evaluate(Context cx, BinaryClassDefNode node) {
    return null;
  }

  public Value evaluate(Context cx, BinaryInterfaceDefinitionNode node) {
    return null;
  }

  public Value evaluate(Context cx, ClassNameNode node) {
    return null;
  }

  public Value evaluate(Context cx, InheritanceNode node) {
    return null;
  }

    private boolean isTopLevel()
    {
        return top_level;
    }
   
  public Value evaluate(Context cx, ConfigNamespaceDefinitionNode node) {
       
        if( !isTopLevel() )
        {
            cx.error(node.pos(), kError_InvalidConfigLocation);
            return null;
        }
        Namespaces namespaces = new Namespaces();
        ObjectList<String> namespace_ids = new ObjectList<String>();
        // can use public since the ConfigurationScopes won't exist after this evaluator.
        namespaces.push_back(cx.publicNamespace());

        // Get the current object and its builder

        ObjectValue obj = cx.scope();
        Builder     bui = obj.builder;

        int slot_id = -1;

        Namespaces hasNamespaces = obj.hasNames(cx,GET_TOKEN,node.name.name,namespaces);
        if( hasNamespaces == null )
        {
            int var_id;
            var_id  = bui.Variable(cx,obj);
            slot_id = bui.ExplicitVar(cx,obj,node.name.name,namespaces,cx.noType(),-1,-1,var_id);

            Slot s = obj.getSlot(cx,slot_id);

            String name = cx.debugName("",node.name.name,namespace_ids,EMPTY_TOKEN);
            ObjectValue ns = cx.getNamespace(name.intern(),Context.NS_INTERNAL);
            if( ns instanceof NamespaceValue )
          {
              ((NamespaceValue)ns).config_ns = true;
          }
            s.setObjectValue(ns);

            s.setConst(true);
           
            config_namespaces.add(node.name.name);
        }

        return null;
  }
  public Value evaluate(Context cx, NamespaceDefinitionNode node) {
        if( config_namespaces.contains(node.name.name) )
            cx.error(node.pos(), kError_ShadowedConfigNamespace, node.name.name);
        return null;
  }

  public Value evaluate(Context cx, PackageDefinitionNode node) {
    return null;
  }

  public Value evaluate(Context cx, PackageIdentifiersNode node) {
    return null;
  }

  public Value evaluate(Context cx, PackageNameNode node) {
    return null;
  }

  public Value evaluate(Context cx, ProgramNode node) {
    // Create a config builder and scope
    ConfigurationBuilder config_bui = new ConfigurationBuilder();
    ObjectValue scope = new ObjectValue(cx, config_bui, null);
    cx.pushScope(scope);
   
        top_level = true;
       
    // Only have to eval statements since this is run before hoisting
    node.statements.evaluate(cx, this);
 
        top_level = false;
       
    cx.popScope();
    return null;
  }

  public Value evaluate(Context cx, BinaryProgramNode node) {
    return null;
  }

  public Value evaluate(Context cx, ErrorNode node) {
    return null;
  }

  public Value evaluate(Context cx, ToObjectNode node) {
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  public Value evaluate(Context cx, LoadRegisterNode node) {
    return null;
  }

  public Value evaluate(Context cx, StoreRegisterNode node) {
    return null;
  }

  public Value evaluate(Context cx, RegisterNode node) {
    return null;
  }

  public Value evaluate(Context cx, HasNextNode node) {
    return null;
  }

  public Value evaluate(Context cx, BoxNode node) {
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  public Value evaluate(Context cx, CoerceNode node) {
    node.expr = evalAndFold(cx, node.expr);
    return null;
  }

  public Value evaluate(Context cx, PragmaNode node) {
    node.list.evaluate(cx, this);
    return null;
  }

  public Value evaluate(Context cx, PragmaExpressionNode node) {
    return null;
  }

  public Value evaluate(Context cx, DefaultXMLNamespaceNode node) {
    return null;
  }
    public Value evaluate(Context cx, UsePrecisionNode node)
    {
        return null;
    }

    public Value evaluate(Context cx, UseNumericNode node)
    {
        return null;
    }

    public Value evaluate(Context cx, UseRoundingNode node)
    {
        return null;
    }


}
TOP

Related Classes of macromedia.asc.semantics.ConfigurationEvaluator

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.