Package anvil.script.expression

Source Code of anvil.script.expression.LinkNode

/*
* $Id: LinkNode.java,v 1.39 2002/09/16 08:05:05 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.expression;

import anvil.Location;
import anvil.core.Any;
import anvil.core.LangModule;
import anvil.core.Modules;
import anvil.core.reflect.Reflection;
import anvil.codec.Code;
import anvil.script.compiler.ByteCompiler;
import anvil.ErrorListener;
import anvil.script.CompilableFunction;
import anvil.script.Context;
import anvil.script.Import;
import anvil.script.Imported;
import anvil.script.Type;
import anvil.script.InterfaceType;
import anvil.script.VariableType;
import anvil.script.LocalVariableType;
import anvil.script.ConstantVariableType;
import anvil.script.StaticVariableType;
import anvil.script.MethodType;
import anvil.script.MemberVariableType;
import anvil.script.Name;
import anvil.script.NamespaceType;
import anvil.script.ClassType;
import anvil.script.Scope;
import anvil.script.ReferenceResolver;
import anvil.script.ReflectedJava;
import anvil.script.NativeJava;
import anvil.script.Grammar;
import anvil.script.Synthetic;
import anvil.script.statements.Statement;
import anvil.script.statements.FunctionStatement;
import anvil.script.statements.ClassStatement;
import anvil.script.statements.LocalVariableStatement;
import anvil.script.statements.ModuleStatement;
import anvil.script.parser.ParserBaseConstants;
import anvil.server.Zone;
import java.io.IOException;
import java.util.ArrayList;

/**
* class LinkNode
*
* @author: Jani Lehtim�ki
*/
public class LinkNode extends Node implements ReferenceResolver
{

  public static final int GET      = 0;
  public static final int ASSIGN   = 1;
  public static final int DECLARE  = 2;
  public static final int NEW      = 3;
  public static final int SUPER    = 4;

  protected ModuleStatement _script;
  protected Statement       _statement;
  protected Location        _location;
  protected Name            _name;
  protected int             _index = 0;
  protected Parent          _args;
  protected int             _role;

  public LinkNode(Statement stmt, Location location, Name name, Parent args, int role)
  {
    super();
    _script    = stmt.getModuleStatement();
    _statement = stmt;
    _location  = location;
    _name      = name;
    _args      = args;
    _role      = role;
  }
 
 
  public LinkNode(Statement stmt, Location location, Name name)
  {
    super();
    _script    = stmt.getModuleStatement();
    _statement = stmt;
    _location  = location;
    _name      = name;
    _args      = null;
    _role      = GET;
 
 
 
  public void setRole(int role)
  {
    _role = role;
  }
 
 
  public int typeOf()
  {
    return Node.EXPR_LINK;
  }


  public boolean isConstant()
  {
    return false;
  }

 
  public Node optimize()
  {
    if (_args != null) {
      _args.optimize();
    }
    return this;
  }


  public String toString()
  {
    return toString(true);
  }
 

  public String toString(boolean withArgs)
  {
    StringBuffer buffer = new StringBuffer(32);
    _name.toString(0, buffer);
    if (withArgs && _args != null) {
      buffer.append(_args.toString());
    }
    return buffer.toString();
  }
 

  protected Parent consumeArgs()
  {
    Parent p = _args;
    _args = null;
    return p;
  }

 
  public boolean hasArgs()
  {
    return (_args != null);
  }

 
  protected String consumeSymbol()
  {
    if (_index < _name.size()) {
      return _name.get(_index++);
    } else {
      return null;
    }
  }


  protected String peekSymbol()
  {
    if (_index < _name.size()) {
      return _name.get(_index);
    } else {
      return null;
   
  }
 

  protected int peekKind()
  {
    if (_index < _name.size()) {
      return _name.getKind(_index);
    } else {
      return 0;
   
  }
   

  protected int symbolsLeft()
  {
    return _name.size() - _index;
  }


  protected boolean hasMoreSymbols()
  {
    return _index < _name.size();
 

 
  protected void checkArguments(ErrorListener context, CompilableFunction function)
  {
    Parent args = _args;
    boolean hassplices = args.hasSplices();
    boolean hasnamed = args.hasNamedParameters();
    int n = args.childs();
    if (hasnamed) {
      if (hassplices) {
        context.error(_location, "Splices and named parameters cannot be used together");
      } else {
        ArrayList fixed = new ArrayList();
        int min = function.getMinimumParameterCount();
        int max = function.getParameterCount();
        boolean[] consumed = new boolean[n];
        int p = 0;
        for(int i=0; i<max; i++) {
          int argtype = function.getParameterType(i);
          String argname = function.getParameterName(i);
          Any argdefault = function.getParameterDefault(i);
          switch(argtype) {
          case CompilableFunction.PARAMETER_CONTEXT:
            break;
          case CompilableFunction.PARAMETER_ARRAY:
          case CompilableFunction.PARAMETER_ANYLIST:
          case CompilableFunction.PARAMETER_LIST:
          case CompilableFunction.PARAMETER_REST:
            break;
          default:
            {
              Node node = null;
              int index = args.findNamedIndex(argname);
              if (index == -1) {
                while(p<n) {
                  if (!consumed[p]) {
                    Node child = args.getChild(p);
                    if (child.typeOf() != EXPR_NAMED) {
                      node = child;
                      consumed[p++] = true;
                      break;
                    }
                  }
                  p++;
                }
              } else {
                if (!consumed[index]) {
                  consumed[index] = true;
                  node = ((NamedNode)args.getChild(index)).getChild();
                } else {
                  context.error(_location, "Named parameter '"+argname+"' appears more than once");
                }
              }
              if (node != null) {
                fixed.add(node);
              } else {
                if (fixed.size()<min) {
                  context.error(_location, "Couldn't match for parameter #"+i+" '"+argname+"'");
                } else {
                  fixed.add(new ConstantNode(argdefault));
                }
              }
            }
            break;
          }
        }
        for(int i=0; i<n; i++) {
          if (!consumed[i]) {
            Node node = args.getChild(i);
            if (node.typeOf() == EXPR_NAMED) {
              NamedNode named = (NamedNode)node;
              context.error(_location, "Supplied named parameter #"+(i+1)+" with name '"+named.getName()+"' was not matched");
              node = named.getChild();
            }
            fixed.add(node);
          }
        }
        _args = new ExpressionList((Node[])fixed.toArray(new Node[fixed.size()]));
      }
    } else {
      if (!hassplices) {
        if (n < function.getMinimumParameterCount()) {
          context.error(_location, "Too few parameters in call to '" + function + "'");
        }
      }
    }
  }
 

  protected Type lookupLibrary(ErrorListener context)
  {
    Zone zone = _script.getAddress().getZone();
    Modules modules = zone.getModules();
    Type type = modules.lookupDeclaration(_name.get(_index-1));
    if (type != null) {
      return type;
    }

    StringBuffer libname = new StringBuffer(32);
    int i = _index;
    int length = _name.size();
    int foundIndex = -1;
    Scope foundScope = null;
    libname.append(_name.get(i-1));
    while(i <= length) {
      String name = libname.toString();
      Scope scope = zone.findJava(name);
      if (scope != null) {
        foundIndex = i;
        foundScope = scope;
      }
      if (i >= length) {
        break;
      }
      libname.append('.');
      libname.append(_name.get(i));
      i++;
    }
    if (foundIndex != -1) {
      _index = foundIndex;
      return foundScope;
    }
    return null;
  }
 
 
  protected Node explicitThisConstruct(ErrorListener listener, ClassType classtype)
  {

    ClassType context = _statement.getClassStatement();
   
    if (!hasMoreSymbols()) {
      return new ThisNode(context, classtype);
    }
   
    Type type = classtype.lookupDeclaration(peekSymbol());
    if (type == null) {
      listener.error(_location, "Undefined entity '" + _name + "'");
      return null;
    }
    switch(type.getType()) {
    case Type.METHOD:
      {
        MethodType method = (MethodType)type;
       
        consumeSymbol();
        if (hasMoreSymbols()) {
          //methodname
          return new DelegateNode(new ThisNode(context, classtype), method);
        } else {
          if (hasArgs()) {
            //methodname(...)
            checkArguments(listener, method);
            return new StaticInvokeNode(classtype, context, method, consumeArgs());
          } else {
            //methodname
            return new DelegateNode(new ThisNode(context, classtype), method);
          }
        }
      }

    case Type.MEMBER_VARIABLE:
      {
        MemberVariableType member = (MemberVariableType)type;
        consumeSymbol();
        return new MemberVariableNode(classtype, context, member);
      }
     
    case Type.CONSTANT_VARIABLE:
      {
        String symbol = consumeSymbol();
        if (_role != GET) {
          listener.error(_location, "Attempting to assign to constant '"+symbol+"'");
        }
        return new ConstantVariableNode((ConstantVariableType)type);
      }

    case Type.STATIC_VARIABLE:
      {
        consumeSymbol();
        return new StaticVariableNode((StaticVariableType)type);
      }
     
    case Type.IMPORT:
      {
        listener.error(_location, "Imported entities are not available from explicit 'this' construct");
        return null;
      }
     
    default:
      {
        return new ThisNode(context, classtype);
      }
    }
  } 
 
 
  protected Node classConstruct(ErrorListener listener, Scope scope)
  {
    if (!hasMoreSymbols()) {
      return new TypeNode(scope);
    }

    if (peekKind() == ParserBaseConstants.THIS) {
      if (scope.getType() == Type.CLASS) {
        consumeSymbol();
        return explicitThisConstruct(listener, (ClassType)scope);
      } else {
        listener.error(_location, "Left of 'this' in '"+_name+"' does not point into class");
      }
    }

    String symbol = peekSymbol();
    Type type = scope.lookupDeclaration(symbol);
    if (type == null) {
      return new TypeNode(scope);
    }
    switch(type.getType()) {
    case Type.CLASS:
    case Type.INTERFACE:
      {
        consumeSymbol();
        if (hasMoreSymbols()) {
          return classConstruct(listener, (Scope)type);
        } else {
          return new TypeNode(type);
        }
      }

    case Type.MEMBER_VARIABLE:
    case Type.METHOD:
    case Type.INTERFACE_METHOD:
    case Type.FUNCTION:
    case Type.CONSTRUCTOR:
      {
        consumeSymbol();
        return new TypeNode(type);
      }

    case Type.STATIC_VARIABLE:
      {
        consumeSymbol();
        return new StaticVariableNode((StaticVariableType)type);
      }
         
    case Type.CONSTANT_VARIABLE:
      {
        consumeSymbol();
        if (_role != GET) {
          listener.error(_location, "Attempting to assign to constant '"+symbol+"'");
        }
        return new ConstantVariableNode((ConstantVariableType)type);
      }

    case Type.IMPORT:
      {
        listener.error(_location, "Imported entities are not available from explicit class construct");
        return null;
      }
     
    default:
      {
        return new TypeNode(scope);
      }
    }
  }


  protected Type followImports(ErrorListener listener, Type type)
  {
    while(type.getType() == Type.IMPORT) {
      Imported imported = (Imported)type;
      if (imported.getModule() != _script) {
        listener.error(_location, "Attempting to refer to '"+imported+"' in another module");
        return null;
      }
      type = imported.getPointedType();
    }
    return type;
  }


  protected Node onFunction(ErrorListener listener, Type type)
  {
    if (type instanceof FunctionStatement) {
      FunctionStatement function = (FunctionStatement)type;
      if (function.getContext() != null) {
        if (hasArgs()) {
          return new InlinedCallNode(_statement.getFunctionStatement(), function, consumeArgs());
        } else {
          return new InlinedFunctionNode(_statement.getFunctionStatement(), function);
        }
      }
    }
    if (hasMoreSymbols()) {
      return new TypeNode((CompilableFunction)type);
      //functioname[.field...]
    } else {
      if (hasArgs()) {
        //functioname(...)
        CompilableFunction function = (CompilableFunction)type;
        checkArguments(listener, function);
        return new CallNode(function, consumeArgs());
      } else {
        //functioname
        return new TypeNode((CompilableFunction)type);
      }
    }
  }

  protected Node construct(ErrorListener listener, Scope scope)
  {
    String symbol = peekSymbol();
    Type type;
    if (scope != null) {
      consumeSymbol();
      type = scope.lookupDeclaration(symbol);
      if (type == null) {
        listener.error(_location, "Entity '" + _name + "' is undeclared");
        return null;
      }
       
    } else {
      switch(_role) {
      case DECLARE:
        {
          consumeSymbol();
          FunctionStatement function = _statement.getFunctionStatement();
          type = function.lookupDeclaration(symbol);
          if (type == null) {
            type = function.declare(symbol);
          }
        }
        break;
       
      case ASSIGN:
        {
          consumeSymbol();
          type = _statement.lookupAnyDeclaration(symbol);
          if (type == null) {
            consumeSymbol();
            FunctionStatement function = _statement.getFunctionStatement();
            if (function != null) {
              type = function.declare(symbol);
            } else {
              listener.error(_location, "Entity '" + _name + "' is undeclared");
              return null;
            }
          }
        }
        break;
       
      default:
        {
          type = _statement.lookupAnyDeclaration(symbol);
          if (type == null) {
            type = LangModule.__module__.lookupDeclaration(symbol);
            if (type == null) {
              consumeSymbol();
              type = lookupLibrary(listener);
              if (type == null) {
                listener.error(_location, "Entity '" + _name + "' is undeclared");
                return null;
              }
              symbol = type.getName();

            } else {
              type = LangModule.__module__;
              symbol = type.getName();

            }
          } else {
            consumeSymbol();
          }
        }
        break;
      }
     
    }

    type = followImports(listener, type);
    if (type == null) {
      return null;
    }
   
    if (type instanceof ReflectedJava) {
      if (type instanceof Reflection) {
        return new JavaClassNode(type.getName());
      } else {
        return new JavaClassNode(type.getParent().getName());
      }
    }

    switch(type.getType()) {
    case Type.MODULE:
    case Type.NAMESPACE: 
      {
        if (!hasMoreSymbols()) {
          return new TypeNode(type);
        }
        return construct(listener, (Scope)type);
      }
     
    case Type.INTERFACE:
    case Type.CLASS: 
      {
        return classConstruct(listener, (Scope)type);
      }
     
    case Type.GLOBAL_NAMESPACE:
      {
        return GlobalNamespaceNode.INSTANCE;
      }

    case Type.SYSTEM_NAMESPACE:
      {
        return new NamespaceNode((NamespaceType)type);
      }

    case Type.FUNCTION:
      {
        return onFunction(listener, type);
      }
     
    case Type.INTERFACE_METHOD:
      {
        return new TypeNode(type);
      }

    case Type.METHOD:
      {
        MethodType method = (MethodType)type;
        ClassStatement context = _statement.getClassStatement();

        if (type instanceof FunctionStatement) {
          FunctionStatement function = (FunctionStatement)type;
          if (function.getContext() != null) {
            if (hasArgs()) {
              return new InlinedCallNode(_statement.getFunctionStatement(), function, consumeArgs());
            } else {
              return new InlinedFunctionNode(_statement.getFunctionStatement(), function);
            }
          }
        }
        if (hasMoreSymbols()) {
          return new TypeNode(type);
        } else {
          Grammar.checkInstanceAmbiguity(listener, _location, context, method);
          if (hasArgs()) {
            //methodname(...)
            checkArguments(listener, method);
            return new StaticInvokeNode(method.getClassType(), context, method, consumeArgs());
          } else {
            //methodname
            return new DelegateNode(new ThisNode(context, method.getClassType()), method);
          }
        }
      }
     
    case Type.CONSTRUCTOR:
      {
        if (!hasMoreSymbols()) {
          if (hasArgs()) {
            listener.error(_location, "Trying to call constructor '"+type+"'");
            return null;
          }
        }
        return new TypeNode(type);
      }

    case Type.CONSTANT_VARIABLE:
      {
        if (_role != GET) {
          listener.error(_location, "Attempting to assign to constant '"+symbol+"'");
        }
        return new ConstantVariableNode((ConstantVariableType)type);
      }
   
    case Type.STATIC_VARIABLE:
      {
        return new StaticVariableNode((StaticVariableType)type);
      }

    case Type.MEMBER_VARIABLE:
      {
        ClassStatement context = _statement.getClassStatement();
        MemberVariableType member = (MemberVariableType)type;
        Grammar.checkInstanceAmbiguity(listener, _location, context, member);
        return new MemberVariableNode(context, member);
      }

    case Type.FUNCTION_PARAMETER:
    case Type.LOCAL_VARIABLE:
      {
        FunctionStatement context = _statement.getFunctionStatement();
        if (type.getParent() != context) {
          return new EscapedVariableNode(symbol, (LocalVariableStatement)type, context);
        } else {
          return new VariableNode((LocalVariableStatement)type);
        }   
      }
    }
   
    return null;
  }


  protected Node superConstruct(ErrorListener context)
  {
    consumeSymbol();
    ClassType classtype = _statement.getClassStatement();
    boolean in_method = (_statement.getFunctionStatement() != null);

    if (classtype == null) {
      context.error(_location, "Cannot use 'super' outside the scope of class");
      return null;
    }

    if (classtype.getBase() == null) {
      context.error(_location, "Cannot use 'super' in classes without base class");
      return null;
    }

    if ((symbolsLeft() == 0) && hasArgs() && in_method) {
      if (_role != SUPER) {
        context.error(_location, "Superclass constructor invoke must appear as first statement in the body of constructor");
        return null;
      }
    
      ClassType base = classtype.getBaseClass();
      CompilableFunction constructor = base.getConstructor();
      if (constructor == null) {
        context.error(_location, "Base class '"+base+"' does not have constructor");
        return null;
      }
      checkArguments(context, constructor);
      return new ConstructorInvokeNode(classtype, consumeArgs());
    }
   
    if (symbolsLeft() < 1) {
      context.error(_location, "Invalid use of 'super'.");
      return null;
    }
   
    String symbol = consumeSymbol();
    Type type = classtype.lookupInheritedDeclaration(symbol);
    if (type == null) {
      context.error(_location, "Undefined entity '"+_name+"'");
      return null;
    }
   
    switch(type.getType()) {
    case Type.INTERFACE_METHOD:
      {
        context.error(_location, "Illegal access to interface method with 'super'");
        return null;
      }
     
    case Type.METHOD:
      if (!hasArgs()) {
        return new TypeNode(type);
      }
      if (_statement.isStaticRegion()) {
        context.error(_location, "Attempting to invoke '"+type+"' from static region");
      }
      MethodType ctor = (MethodType)type;
      checkArguments(context, ctor);
      return new SuperInvokeNode(ctor, consumeArgs());

    case Type.FUNCTION:
      if (!hasArgs()) {
        return new TypeNode(type);
      }
      CompilableFunction function = (CompilableFunction)type;
      checkArguments(context, function);
      return new CallNode(function, consumeArgs());

    case Type.CONSTANT_VARIABLE:
      return new ConstantVariableNode((ConstantVariableType)type);
 
    case Type.STATIC_VARIABLE:
      return new StaticVariableNode((StaticVariableType)type);
     
    case Type.MEMBER_VARIABLE:
      if (_statement.isStaticRegion()) {
        context.error(_location, "Attempting to refer to member variable '"+type+"' from static region");
      }
      if (!in_method) {
        break;
      }
      return new MemberVariableNode(null, (MemberVariableType)type);
    
    case Type.IMPORT:
      context.error(_location, "Imported entities may not be referred with 'super'");
      return null;
     
    default:
      break;
    }
    context.error(_location, "Invalid use of 'super'");
    return null;
  }


 
  protected Node newConstruct(ErrorListener listener, ClassType target)
  {

    if (!hasMoreSymbols()) {
      listener.error(_location, "Syntax error: class name expected after 'new'");
      return null;
    }

    Type type;
    String symbol;
   
    if (peekKind() == ParserBaseConstants.MODULE) {
      consumeSymbol();
      type = _script;   
    } else {
      symbol = consumeSymbol();
      type = _statement.lookupAnyDeclaration(symbol);
      if (type == null) {
        type = LangModule.__module__.lookupDeclaration(symbol);
        if (type == null) {
          type = lookupLibrary(listener);
        }
      }
    }
   
    while(true) {
   
      if (type == null) {
        listener.error(_location, "Entity '" + _name.toString(1) + "' is undeclared");
        return null;
      }
     
      type = followImports(listener, type);
      if (type == null) {
        return null;
      }

      if (type instanceof ReflectedJava) {
        if (type instanceof Reflection) {
          return new JavaClassNode(type.getName());
        } else {
          return new JavaClassNode(type.getParent().getName());
        }
      }
     
      switch(type.getType()) {
      case Type.MODULE:
      case Type.NAMESPACE:
        {
          if (hasMoreSymbols()) {
            symbol = consumeSymbol();
            type = ((Scope)type).lookupDeclaration(symbol);
            break;
          }
          listener.error(_location, "Entity '" + _name.toString(1) + "' is not a class");
          return null;
        }

      case Type.CLASS:
        {
          ClassType clazz = (ClassType)type;
          if (hasMoreSymbols()) {
            symbol = consumeSymbol();
            type = clazz.lookupDeclaration(symbol);
            break;
          }
          if (!hasArgs()) {
            listener.error(_location, "Syntax error: argument list expected after '"+_name.toString(1)+"'");
            return null;
          }
          CompilableFunction constructor = clazz.getConstructor();
          if (constructor == null) {
            listener.error(_location, "Class '" + clazz + "' does not have constructor");
            return null;
          }
          ClassType context = _statement.getClassStatement();
          checkArguments(listener, constructor);
          Grammar.checkInstanceAccess(listener, _location, _statement, clazz);
          //Grammar.checkInstanceAmbiguity(listener, _location, context, clazz);
          return new NewNode(context, clazz, constructor, consumeArgs());
        }

      default:
        listener.error(_location, "Entity '" + _name.toString(1) + "' is not a class");
        return null;
      }
    }
  }


  protected Node doLink(ErrorListener listener)
  {
    ClassType classtype;
    switch(peekKind()) {
    case ParserBaseConstants.SYMBOL:
      {
        String symbol = peekSymbol();
        if (symbol.equals("__FILE__")) {
          consumeSymbol();
          if (_role != GET) {
            listener.error(_location, "Pseudo variable '__FILE__' can only be referred");
          }
          return new ConstantNode(Any.create(_location.getURL().toString()));
        } else if (symbol.equals("__LINE__")) {
          consumeSymbol();
          if (_role != GET) {
            listener.error(_location, "Pseudo variable '__LINE__' can only be referred");
          }
          return new ConstantNode(Any.create(_location.getLine()));
        }
      }
    case ParserBaseConstants.STATIC:
      // symbol
      return construct(listener, null);
     
    case ParserBaseConstants.MODULE:
      // module
      consumeSymbol();
      if (!hasMoreSymbols()) {
        return new TypeNode(_script);
      }
      return construct(listener, _script);
     
    case ParserBaseConstants.CLASS:
      // class
      consumeSymbol();
      classtype = _statement.getClassStatement();
      if (classtype != null) {
        return classConstruct(listener, classtype);
      } else {
        listener.error(_location, "Cannot use 'class' outside classes");
        return null;
      }
     
    case ParserBaseConstants.FUNCTION:
      {
        // function
        consumeSymbol();
        FunctionStatement function = _statement.getFunctionStatement();
        if (function != null) {
          return onFunction(listener, function);
        } else {
          listener.error(_location, "Cannot use 'function' outside functions");
          return null;
        }     
      }

    case ParserBaseConstants.THIS:
    case ParserBaseConstants.DOT:
      // this
      // <dot> <symbol> ...
      consumeSymbol();
      classtype = _statement.getClassStatement();
      if (classtype != null) {
        if (_statement.isStaticRegion()) {
          listener.error(_location, "Cannot use 'this' in static region");
        }
        if (hasMoreSymbols()) {
          return explicitThisConstruct(listener, classtype);
          //return construct(listener, classtype);
        } else {
          return ThisNode.INSTANCE;
        }
      } else {
        listener.error(_location, "Cannot use 'this' outside classes");
        return null;
      }
     
    case ParserBaseConstants.SUPER:
      // super.method(...)
      return superConstruct(listener);

    case ParserBaseConstants.NEW:
      // new ...
      consumeSymbol(); // new
      return newConstruct(listener, null);

    }
    return null;
  }

 
  public Node link(ErrorListener listener)
  {
    Node node = doLink(listener);
    if (node == null) {
      node = ConstantNode.UNDEFINED;
    }
    if (node instanceof TypeNode) {
      Type type = ((TypeNode)node).getType();
      if (type instanceof Synthetic) {
        listener.error(_location, "Cannot refer to synthetic entities");
        node = ConstantNode.UNDEFINED;
      }
    }
    if (hasMoreSymbols()) {
      while(hasMoreSymbols()) {
        if (symbolsLeft()==1 && hasArgs()) {
          // *.symbol(...)
          Parent args = consumeArgs();
          if (args.hasNamedParameters()) {
            listener.error(_location, "Named parameters are ignored in anonymous invokes");
          }
          node = new InvokeNode(node, consumeSymbol(), args);
        } else {
          // *.symbol
          node = new AttributeNode(node, consumeSymbol());
        }
      }
    } else {
      // *.(...)
      if (hasArgs()) {
        Parent args = consumeArgs();
        if (args.hasNamedParameters()) {
          listener.error(_location, "Named parameters are ignored in anonymous calls");
        }
        node = new DynamicCallNode(node, args);
      }
    }
    return node;
  }

 
 
  public String getReference()
  {
    return toString();
  }


  public Location getLocation()
  {
    return _location;
  }


  public Type resolveReference(ErrorListener listener)
  {
    Type type;
    if (peekKind() == ParserBaseConstants.MODULE) {
      consumeSymbol();
      type = _script;
    } else {
      String symbol = peekSymbol();
      type = _statement.lookupAnyDeclaration(symbol);
      if (type == null) {
        type = LangModule.__module__.lookupDeclaration(symbol);
        if (type == null) {
          consumeSymbol();
          type = lookupLibrary(listener);
        } else {
          type = LangModule.__module__;
          symbol = type.getName();
        }
      } else {
        consumeSymbol();
      }
    }

    while(true) {

      if (type == null) {
        listener.error(_location, "Entity '" + _name + "' is undeclared");
        return null;
      }

      type = followImports(listener, type);
      if (type == null) {
        return null;
      }

      switch(type.getType()) {
      case Type.MODULE:
      case Type.CLASS:
      case Type.INTERFACE:
      case Type.NAMESPACE:
        {
          if (hasMoreSymbols()) {
            type = ((Scope)type).lookupDeclaration(consumeSymbol());
            break;
          } else {
            return type;
          }
        }
       
      default:
        {
          if (hasMoreSymbols()) {
            listener.error(_location, "Entity '" + _name + "' is undeclared");
          }
          return type;
        }
      }
    }
  }


  public Any eval()
  {
    return Any.UNDEFINED;
  }


  public void compile(ByteCompiler context, int operation)
  {
    context.getCode().aconst_null();
  }

}
TOP

Related Classes of anvil.script.expression.LinkNode

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.