0001: /*
0002: * $Id: LinkNode.java,v 1.39 2002/09/16 08:05:05 jkl Exp $
0003: *
0004: * Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
0005: *
0006: * Use is subject to license terms, as defined in
0007: * Anvil Sofware License, Version 1.1. See LICENSE
0008: * file, or http://njet.org/license-1.1.txt
0009: */
0010: package anvil.script.expression;
0011:
0012: import anvil.Location;
0013: import anvil.core.Any;
0014: import anvil.core.LangModule;
0015: import anvil.core.Modules;
0016: import anvil.core.reflect.Reflection;
0017: import anvil.codec.Code;
0018: import anvil.script.compiler.ByteCompiler;
0019: import anvil.ErrorListener;
0020: import anvil.script.CompilableFunction;
0021: import anvil.script.Context;
0022: import anvil.script.Import;
0023: import anvil.script.Imported;
0024: import anvil.script.Type;
0025: import anvil.script.InterfaceType;
0026: import anvil.script.VariableType;
0027: import anvil.script.LocalVariableType;
0028: import anvil.script.ConstantVariableType;
0029: import anvil.script.StaticVariableType;
0030: import anvil.script.MethodType;
0031: import anvil.script.MemberVariableType;
0032: import anvil.script.Name;
0033: import anvil.script.NamespaceType;
0034: import anvil.script.ClassType;
0035: import anvil.script.Scope;
0036: import anvil.script.ReferenceResolver;
0037: import anvil.script.ReflectedJava;
0038: import anvil.script.NativeJava;
0039: import anvil.script.Grammar;
0040: import anvil.script.Synthetic;
0041: import anvil.script.statements.Statement;
0042: import anvil.script.statements.FunctionStatement;
0043: import anvil.script.statements.ClassStatement;
0044: import anvil.script.statements.LocalVariableStatement;
0045: import anvil.script.statements.ModuleStatement;
0046: import anvil.script.parser.ParserBaseConstants;
0047: import anvil.server.Zone;
0048: import java.io.IOException;
0049: import java.util.ArrayList;
0050:
0051: /**
0052: * class LinkNode
0053: *
0054: * @author: Jani Lehtimäki
0055: */
0056: public class LinkNode extends Node implements ReferenceResolver {
0057:
0058: public static final int GET = 0;
0059: public static final int ASSIGN = 1;
0060: public static final int DECLARE = 2;
0061: public static final int NEW = 3;
0062: public static final int SUPER = 4;
0063:
0064: protected ModuleStatement _script;
0065: protected Statement _statement;
0066: protected Location _location;
0067: protected Name _name;
0068: protected int _index = 0;
0069: protected Parent _args;
0070: protected int _role;
0071:
0072: public LinkNode(Statement stmt, Location location, Name name,
0073: Parent args, int role) {
0074: super ();
0075: _script = stmt.getModuleStatement();
0076: _statement = stmt;
0077: _location = location;
0078: _name = name;
0079: _args = args;
0080: _role = role;
0081: }
0082:
0083: public LinkNode(Statement stmt, Location location, Name name) {
0084: super ();
0085: _script = stmt.getModuleStatement();
0086: _statement = stmt;
0087: _location = location;
0088: _name = name;
0089: _args = null;
0090: _role = GET;
0091: }
0092:
0093: public void setRole(int role) {
0094: _role = role;
0095: }
0096:
0097: public int typeOf() {
0098: return Node.EXPR_LINK;
0099: }
0100:
0101: public boolean isConstant() {
0102: return false;
0103: }
0104:
0105: public Node optimize() {
0106: if (_args != null) {
0107: _args.optimize();
0108: }
0109: return this ;
0110: }
0111:
0112: public String toString() {
0113: return toString(true);
0114: }
0115:
0116: public String toString(boolean withArgs) {
0117: StringBuffer buffer = new StringBuffer(32);
0118: _name.toString(0, buffer);
0119: if (withArgs && _args != null) {
0120: buffer.append(_args.toString());
0121: }
0122: return buffer.toString();
0123: }
0124:
0125: protected Parent consumeArgs() {
0126: Parent p = _args;
0127: _args = null;
0128: return p;
0129: }
0130:
0131: public boolean hasArgs() {
0132: return (_args != null);
0133: }
0134:
0135: protected String consumeSymbol() {
0136: if (_index < _name.size()) {
0137: return _name.get(_index++);
0138: } else {
0139: return null;
0140: }
0141: }
0142:
0143: protected String peekSymbol() {
0144: if (_index < _name.size()) {
0145: return _name.get(_index);
0146: } else {
0147: return null;
0148: }
0149: }
0150:
0151: protected int peekKind() {
0152: if (_index < _name.size()) {
0153: return _name.getKind(_index);
0154: } else {
0155: return 0;
0156: }
0157: }
0158:
0159: protected int symbolsLeft() {
0160: return _name.size() - _index;
0161: }
0162:
0163: protected boolean hasMoreSymbols() {
0164: return _index < _name.size();
0165: }
0166:
0167: protected void checkArguments(ErrorListener context,
0168: CompilableFunction function) {
0169: Parent args = _args;
0170: boolean hassplices = args.hasSplices();
0171: boolean hasnamed = args.hasNamedParameters();
0172: int n = args.childs();
0173: if (hasnamed) {
0174: if (hassplices) {
0175: context
0176: .error(_location,
0177: "Splices and named parameters cannot be used together");
0178: } else {
0179: ArrayList fixed = new ArrayList();
0180: int min = function.getMinimumParameterCount();
0181: int max = function.getParameterCount();
0182: boolean[] consumed = new boolean[n];
0183: int p = 0;
0184: for (int i = 0; i < max; i++) {
0185: int argtype = function.getParameterType(i);
0186: String argname = function.getParameterName(i);
0187: Any argdefault = function.getParameterDefault(i);
0188: switch (argtype) {
0189: case CompilableFunction.PARAMETER_CONTEXT:
0190: break;
0191: case CompilableFunction.PARAMETER_ARRAY:
0192: case CompilableFunction.PARAMETER_ANYLIST:
0193: case CompilableFunction.PARAMETER_LIST:
0194: case CompilableFunction.PARAMETER_REST:
0195: break;
0196: default: {
0197: Node node = null;
0198: int index = args.findNamedIndex(argname);
0199: if (index == -1) {
0200: while (p < n) {
0201: if (!consumed[p]) {
0202: Node child = args.getChild(p);
0203: if (child.typeOf() != EXPR_NAMED) {
0204: node = child;
0205: consumed[p++] = true;
0206: break;
0207: }
0208: }
0209: p++;
0210: }
0211: } else {
0212: if (!consumed[index]) {
0213: consumed[index] = true;
0214: node = ((NamedNode) args
0215: .getChild(index)).getChild();
0216: } else {
0217: context
0218: .error(
0219: _location,
0220: "Named parameter '"
0221: + argname
0222: + "' appears more than once");
0223: }
0224: }
0225: if (node != null) {
0226: fixed.add(node);
0227: } else {
0228: if (fixed.size() < min) {
0229: context.error(_location,
0230: "Couldn't match for parameter #"
0231: + i + " '" + argname
0232: + "'");
0233: } else {
0234: fixed.add(new ConstantNode(argdefault));
0235: }
0236: }
0237: }
0238: break;
0239: }
0240: }
0241: for (int i = 0; i < n; i++) {
0242: if (!consumed[i]) {
0243: Node node = args.getChild(i);
0244: if (node.typeOf() == EXPR_NAMED) {
0245: NamedNode named = (NamedNode) node;
0246: context.error(_location,
0247: "Supplied named parameter #"
0248: + (i + 1) + " with name '"
0249: + named.getName()
0250: + "' was not matched");
0251: node = named.getChild();
0252: }
0253: fixed.add(node);
0254: }
0255: }
0256: _args = new ExpressionList((Node[]) fixed
0257: .toArray(new Node[fixed.size()]));
0258: }
0259: } else {
0260: if (!hassplices) {
0261: if (n < function.getMinimumParameterCount()) {
0262: context.error(_location,
0263: "Too few parameters in call to '"
0264: + function + "'");
0265: }
0266: }
0267: }
0268: }
0269:
0270: protected Type lookupLibrary(ErrorListener context) {
0271: Zone zone = _script.getAddress().getZone();
0272: Modules modules = zone.getModules();
0273: Type type = modules.lookupDeclaration(_name.get(_index - 1));
0274: if (type != null) {
0275: return type;
0276: }
0277:
0278: StringBuffer libname = new StringBuffer(32);
0279: int i = _index;
0280: int length = _name.size();
0281: int foundIndex = -1;
0282: Scope foundScope = null;
0283: libname.append(_name.get(i - 1));
0284: while (i <= length) {
0285: String name = libname.toString();
0286: Scope scope = zone.findJava(name);
0287: if (scope != null) {
0288: foundIndex = i;
0289: foundScope = scope;
0290: }
0291: if (i >= length) {
0292: break;
0293: }
0294: libname.append('.');
0295: libname.append(_name.get(i));
0296: i++;
0297: }
0298: if (foundIndex != -1) {
0299: _index = foundIndex;
0300: return foundScope;
0301: }
0302: return null;
0303: }
0304:
0305: protected Node explicitThisConstruct(ErrorListener listener,
0306: ClassType classtype) {
0307:
0308: ClassType context = _statement.getClassStatement();
0309:
0310: if (!hasMoreSymbols()) {
0311: return new ThisNode(context, classtype);
0312: }
0313:
0314: Type type = classtype.lookupDeclaration(peekSymbol());
0315: if (type == null) {
0316: listener.error(_location, "Undefined entity '" + _name
0317: + "'");
0318: return null;
0319: }
0320: switch (type.getType()) {
0321: case Type.METHOD: {
0322: MethodType method = (MethodType) type;
0323:
0324: consumeSymbol();
0325: if (hasMoreSymbols()) {
0326: //methodname
0327: return new DelegateNode(
0328: new ThisNode(context, classtype), method);
0329: } else {
0330: if (hasArgs()) {
0331: //methodname(...)
0332: checkArguments(listener, method);
0333: return new StaticInvokeNode(classtype, context,
0334: method, consumeArgs());
0335: } else {
0336: //methodname
0337: return new DelegateNode(new ThisNode(context,
0338: classtype), method);
0339: }
0340: }
0341: }
0342:
0343: case Type.MEMBER_VARIABLE: {
0344: MemberVariableType member = (MemberVariableType) type;
0345: consumeSymbol();
0346: return new MemberVariableNode(classtype, context, member);
0347: }
0348:
0349: case Type.CONSTANT_VARIABLE: {
0350: String symbol = consumeSymbol();
0351: if (_role != GET) {
0352: listener.error(_location,
0353: "Attempting to assign to constant '" + symbol
0354: + "'");
0355: }
0356: return new ConstantVariableNode((ConstantVariableType) type);
0357: }
0358:
0359: case Type.STATIC_VARIABLE: {
0360: consumeSymbol();
0361: return new StaticVariableNode((StaticVariableType) type);
0362: }
0363:
0364: case Type.IMPORT: {
0365: listener
0366: .error(_location,
0367: "Imported entities are not available from explicit 'this' construct");
0368: return null;
0369: }
0370:
0371: default: {
0372: return new ThisNode(context, classtype);
0373: }
0374: }
0375: }
0376:
0377: protected Node classConstruct(ErrorListener listener, Scope scope) {
0378: if (!hasMoreSymbols()) {
0379: return new TypeNode(scope);
0380: }
0381:
0382: if (peekKind() == ParserBaseConstants.THIS) {
0383: if (scope.getType() == Type.CLASS) {
0384: consumeSymbol();
0385: return explicitThisConstruct(listener,
0386: (ClassType) scope);
0387: } else {
0388: listener.error(_location, "Left of 'this' in '" + _name
0389: + "' does not point into class");
0390: }
0391: }
0392:
0393: String symbol = peekSymbol();
0394: Type type = scope.lookupDeclaration(symbol);
0395: if (type == null) {
0396: return new TypeNode(scope);
0397: }
0398: switch (type.getType()) {
0399: case Type.CLASS:
0400: case Type.INTERFACE: {
0401: consumeSymbol();
0402: if (hasMoreSymbols()) {
0403: return classConstruct(listener, (Scope) type);
0404: } else {
0405: return new TypeNode(type);
0406: }
0407: }
0408:
0409: case Type.MEMBER_VARIABLE:
0410: case Type.METHOD:
0411: case Type.INTERFACE_METHOD:
0412: case Type.FUNCTION:
0413: case Type.CONSTRUCTOR: {
0414: consumeSymbol();
0415: return new TypeNode(type);
0416: }
0417:
0418: case Type.STATIC_VARIABLE: {
0419: consumeSymbol();
0420: return new StaticVariableNode((StaticVariableType) type);
0421: }
0422:
0423: case Type.CONSTANT_VARIABLE: {
0424: consumeSymbol();
0425: if (_role != GET) {
0426: listener.error(_location,
0427: "Attempting to assign to constant '" + symbol
0428: + "'");
0429: }
0430: return new ConstantVariableNode((ConstantVariableType) type);
0431: }
0432:
0433: case Type.IMPORT: {
0434: listener
0435: .error(_location,
0436: "Imported entities are not available from explicit class construct");
0437: return null;
0438: }
0439:
0440: default: {
0441: return new TypeNode(scope);
0442: }
0443: }
0444: }
0445:
0446: protected Type followImports(ErrorListener listener, Type type) {
0447: while (type.getType() == Type.IMPORT) {
0448: Imported imported = (Imported) type;
0449: if (imported.getModule() != _script) {
0450: listener.error(_location, "Attempting to refer to '"
0451: + imported + "' in another module");
0452: return null;
0453: }
0454: type = imported.getPointedType();
0455: }
0456: return type;
0457: }
0458:
0459: protected Node onFunction(ErrorListener listener, Type type) {
0460: if (type instanceof FunctionStatement) {
0461: FunctionStatement function = (FunctionStatement) type;
0462: if (function.getContext() != null) {
0463: if (hasArgs()) {
0464: return new InlinedCallNode(_statement
0465: .getFunctionStatement(), function,
0466: consumeArgs());
0467: } else {
0468: return new InlinedFunctionNode(_statement
0469: .getFunctionStatement(), function);
0470: }
0471: }
0472: }
0473: if (hasMoreSymbols()) {
0474: return new TypeNode((CompilableFunction) type);
0475: //functioname[.field...]
0476: } else {
0477: if (hasArgs()) {
0478: //functioname(...)
0479: CompilableFunction function = (CompilableFunction) type;
0480: checkArguments(listener, function);
0481: return new CallNode(function, consumeArgs());
0482: } else {
0483: //functioname
0484: return new TypeNode((CompilableFunction) type);
0485: }
0486: }
0487: }
0488:
0489: protected Node construct(ErrorListener listener, Scope scope) {
0490: String symbol = peekSymbol();
0491: Type type;
0492: if (scope != null) {
0493: consumeSymbol();
0494: type = scope.lookupDeclaration(symbol);
0495: if (type == null) {
0496: listener.error(_location, "Entity '" + _name
0497: + "' is undeclared");
0498: return null;
0499: }
0500:
0501: } else {
0502: switch (_role) {
0503: case DECLARE: {
0504: consumeSymbol();
0505: FunctionStatement function = _statement
0506: .getFunctionStatement();
0507: type = function.lookupDeclaration(symbol);
0508: if (type == null) {
0509: type = function.declare(symbol);
0510: }
0511: }
0512: break;
0513:
0514: case ASSIGN: {
0515: consumeSymbol();
0516: type = _statement.lookupAnyDeclaration(symbol);
0517: if (type == null) {
0518: consumeSymbol();
0519: FunctionStatement function = _statement
0520: .getFunctionStatement();
0521: if (function != null) {
0522: type = function.declare(symbol);
0523: } else {
0524: listener.error(_location, "Entity '" + _name
0525: + "' is undeclared");
0526: return null;
0527: }
0528: }
0529: }
0530: break;
0531:
0532: default: {
0533: type = _statement.lookupAnyDeclaration(symbol);
0534: if (type == null) {
0535: type = LangModule.__module__
0536: .lookupDeclaration(symbol);
0537: if (type == null) {
0538: consumeSymbol();
0539: type = lookupLibrary(listener);
0540: if (type == null) {
0541: listener.error(_location, "Entity '"
0542: + _name + "' is undeclared");
0543: return null;
0544: }
0545: symbol = type.getName();
0546:
0547: } else {
0548: type = LangModule.__module__;
0549: symbol = type.getName();
0550:
0551: }
0552: } else {
0553: consumeSymbol();
0554: }
0555: }
0556: break;
0557: }
0558:
0559: }
0560:
0561: type = followImports(listener, type);
0562: if (type == null) {
0563: return null;
0564: }
0565:
0566: if (type instanceof ReflectedJava) {
0567: if (type instanceof Reflection) {
0568: return new JavaClassNode(type.getName());
0569: } else {
0570: return new JavaClassNode(type.getParent().getName());
0571: }
0572: }
0573:
0574: switch (type.getType()) {
0575: case Type.MODULE:
0576: case Type.NAMESPACE: {
0577: if (!hasMoreSymbols()) {
0578: return new TypeNode(type);
0579: }
0580: return construct(listener, (Scope) type);
0581: }
0582:
0583: case Type.INTERFACE:
0584: case Type.CLASS: {
0585: return classConstruct(listener, (Scope) type);
0586: }
0587:
0588: case Type.GLOBAL_NAMESPACE: {
0589: return GlobalNamespaceNode.INSTANCE;
0590: }
0591:
0592: case Type.SYSTEM_NAMESPACE: {
0593: return new NamespaceNode((NamespaceType) type);
0594: }
0595:
0596: case Type.FUNCTION: {
0597: return onFunction(listener, type);
0598: }
0599:
0600: case Type.INTERFACE_METHOD: {
0601: return new TypeNode(type);
0602: }
0603:
0604: case Type.METHOD: {
0605: MethodType method = (MethodType) type;
0606: ClassStatement context = _statement.getClassStatement();
0607:
0608: if (type instanceof FunctionStatement) {
0609: FunctionStatement function = (FunctionStatement) type;
0610: if (function.getContext() != null) {
0611: if (hasArgs()) {
0612: return new InlinedCallNode(_statement
0613: .getFunctionStatement(), function,
0614: consumeArgs());
0615: } else {
0616: return new InlinedFunctionNode(_statement
0617: .getFunctionStatement(), function);
0618: }
0619: }
0620: }
0621: if (hasMoreSymbols()) {
0622: return new TypeNode(type);
0623: } else {
0624: Grammar.checkInstanceAmbiguity(listener, _location,
0625: context, method);
0626: if (hasArgs()) {
0627: //methodname(...)
0628: checkArguments(listener, method);
0629: return new StaticInvokeNode(method.getClassType(),
0630: context, method, consumeArgs());
0631: } else {
0632: //methodname
0633: return new DelegateNode(new ThisNode(context,
0634: method.getClassType()), method);
0635: }
0636: }
0637: }
0638:
0639: case Type.CONSTRUCTOR: {
0640: if (!hasMoreSymbols()) {
0641: if (hasArgs()) {
0642: listener
0643: .error(_location,
0644: "Trying to call constructor '"
0645: + type + "'");
0646: return null;
0647: }
0648: }
0649: return new TypeNode(type);
0650: }
0651:
0652: case Type.CONSTANT_VARIABLE: {
0653: if (_role != GET) {
0654: listener.error(_location,
0655: "Attempting to assign to constant '" + symbol
0656: + "'");
0657: }
0658: return new ConstantVariableNode((ConstantVariableType) type);
0659: }
0660:
0661: case Type.STATIC_VARIABLE: {
0662: return new StaticVariableNode((StaticVariableType) type);
0663: }
0664:
0665: case Type.MEMBER_VARIABLE: {
0666: ClassStatement context = _statement.getClassStatement();
0667: MemberVariableType member = (MemberVariableType) type;
0668: Grammar.checkInstanceAmbiguity(listener, _location,
0669: context, member);
0670: return new MemberVariableNode(context, member);
0671: }
0672:
0673: case Type.FUNCTION_PARAMETER:
0674: case Type.LOCAL_VARIABLE: {
0675: FunctionStatement context = _statement
0676: .getFunctionStatement();
0677: if (type.getParent() != context) {
0678: return new EscapedVariableNode(symbol,
0679: (LocalVariableStatement) type, context);
0680: } else {
0681: return new VariableNode((LocalVariableStatement) type);
0682: }
0683: }
0684: }
0685:
0686: return null;
0687: }
0688:
0689: protected Node super Construct(ErrorListener context) {
0690: consumeSymbol();
0691: ClassType classtype = _statement.getClassStatement();
0692: boolean in_method = (_statement.getFunctionStatement() != null);
0693:
0694: if (classtype == null) {
0695: context.error(_location,
0696: "Cannot use 'super' outside the scope of class");
0697: return null;
0698: }
0699:
0700: if (classtype.getBase() == null) {
0701: context.error(_location,
0702: "Cannot use 'super' in classes without base class");
0703: return null;
0704: }
0705:
0706: if ((symbolsLeft() == 0) && hasArgs() && in_method) {
0707: if (_role != SUPER) {
0708: context
0709: .error(
0710: _location,
0711: "Superclass constructor invoke must appear as first statement in the body of constructor");
0712: return null;
0713: }
0714:
0715: ClassType base = classtype.getBaseClass();
0716: CompilableFunction constructor = base.getConstructor();
0717: if (constructor == null) {
0718: context.error(_location, "Base class '" + base
0719: + "' does not have constructor");
0720: return null;
0721: }
0722: checkArguments(context, constructor);
0723: return new ConstructorInvokeNode(classtype, consumeArgs());
0724: }
0725:
0726: if (symbolsLeft() < 1) {
0727: context.error(_location, "Invalid use of 'super'.");
0728: return null;
0729: }
0730:
0731: String symbol = consumeSymbol();
0732: Type type = classtype.lookupInheritedDeclaration(symbol);
0733: if (type == null) {
0734: context
0735: .error(_location, "Undefined entity '" + _name
0736: + "'");
0737: return null;
0738: }
0739:
0740: switch (type.getType()) {
0741: case Type.INTERFACE_METHOD: {
0742: context.error(_location,
0743: "Illegal access to interface method with 'super'");
0744: return null;
0745: }
0746:
0747: case Type.METHOD:
0748: if (!hasArgs()) {
0749: return new TypeNode(type);
0750: }
0751: if (_statement.isStaticRegion()) {
0752: context.error(_location, "Attempting to invoke '"
0753: + type + "' from static region");
0754: }
0755: MethodType ctor = (MethodType) type;
0756: checkArguments(context, ctor);
0757: return new SuperInvokeNode(ctor, consumeArgs());
0758:
0759: case Type.FUNCTION:
0760: if (!hasArgs()) {
0761: return new TypeNode(type);
0762: }
0763: CompilableFunction function = (CompilableFunction) type;
0764: checkArguments(context, function);
0765: return new CallNode(function, consumeArgs());
0766:
0767: case Type.CONSTANT_VARIABLE:
0768: return new ConstantVariableNode((ConstantVariableType) type);
0769:
0770: case Type.STATIC_VARIABLE:
0771: return new StaticVariableNode((StaticVariableType) type);
0772:
0773: case Type.MEMBER_VARIABLE:
0774: if (_statement.isStaticRegion()) {
0775: context.error(_location,
0776: "Attempting to refer to member variable '"
0777: + type + "' from static region");
0778: }
0779: if (!in_method) {
0780: break;
0781: }
0782: return new MemberVariableNode(null,
0783: (MemberVariableType) type);
0784:
0785: case Type.IMPORT:
0786: context
0787: .error(_location,
0788: "Imported entities may not be referred with 'super'");
0789: return null;
0790:
0791: default:
0792: break;
0793: }
0794: context.error(_location, "Invalid use of 'super'");
0795: return null;
0796: }
0797:
0798: protected Node newConstruct(ErrorListener listener, ClassType target) {
0799:
0800: if (!hasMoreSymbols()) {
0801: listener.error(_location,
0802: "Syntax error: class name expected after 'new'");
0803: return null;
0804: }
0805:
0806: Type type;
0807: String symbol;
0808:
0809: if (peekKind() == ParserBaseConstants.MODULE) {
0810: consumeSymbol();
0811: type = _script;
0812: } else {
0813: symbol = consumeSymbol();
0814: type = _statement.lookupAnyDeclaration(symbol);
0815: if (type == null) {
0816: type = LangModule.__module__.lookupDeclaration(symbol);
0817: if (type == null) {
0818: type = lookupLibrary(listener);
0819: }
0820: }
0821: }
0822:
0823: while (true) {
0824:
0825: if (type == null) {
0826: listener.error(_location, "Entity '"
0827: + _name.toString(1) + "' is undeclared");
0828: return null;
0829: }
0830:
0831: type = followImports(listener, type);
0832: if (type == null) {
0833: return null;
0834: }
0835:
0836: if (type instanceof ReflectedJava) {
0837: if (type instanceof Reflection) {
0838: return new JavaClassNode(type.getName());
0839: } else {
0840: return new JavaClassNode(type.getParent().getName());
0841: }
0842: }
0843:
0844: switch (type.getType()) {
0845: case Type.MODULE:
0846: case Type.NAMESPACE: {
0847: if (hasMoreSymbols()) {
0848: symbol = consumeSymbol();
0849: type = ((Scope) type).lookupDeclaration(symbol);
0850: break;
0851: }
0852: listener.error(_location, "Entity '"
0853: + _name.toString(1) + "' is not a class");
0854: return null;
0855: }
0856:
0857: case Type.CLASS: {
0858: ClassType clazz = (ClassType) type;
0859: if (hasMoreSymbols()) {
0860: symbol = consumeSymbol();
0861: type = clazz.lookupDeclaration(symbol);
0862: break;
0863: }
0864: if (!hasArgs()) {
0865: listener.error(_location,
0866: "Syntax error: argument list expected after '"
0867: + _name.toString(1) + "'");
0868: return null;
0869: }
0870: CompilableFunction constructor = clazz.getConstructor();
0871: if (constructor == null) {
0872: listener.error(_location, "Class '" + clazz
0873: + "' does not have constructor");
0874: return null;
0875: }
0876: ClassType context = _statement.getClassStatement();
0877: checkArguments(listener, constructor);
0878: Grammar.checkInstanceAccess(listener, _location,
0879: _statement, clazz);
0880: //Grammar.checkInstanceAmbiguity(listener, _location, context, clazz);
0881: return new NewNode(context, clazz, constructor,
0882: consumeArgs());
0883: }
0884:
0885: default:
0886: listener.error(_location, "Entity '"
0887: + _name.toString(1) + "' is not a class");
0888: return null;
0889: }
0890: }
0891: }
0892:
0893: protected Node doLink(ErrorListener listener) {
0894: ClassType classtype;
0895: switch (peekKind()) {
0896: case ParserBaseConstants.SYMBOL: {
0897: String symbol = peekSymbol();
0898: if (symbol.equals("__FILE__")) {
0899: consumeSymbol();
0900: if (_role != GET) {
0901: listener
0902: .error(_location,
0903: "Pseudo variable '__FILE__' can only be referred");
0904: }
0905: return new ConstantNode(Any.create(_location.getURL()
0906: .toString()));
0907: } else if (symbol.equals("__LINE__")) {
0908: consumeSymbol();
0909: if (_role != GET) {
0910: listener
0911: .error(_location,
0912: "Pseudo variable '__LINE__' can only be referred");
0913: }
0914: return new ConstantNode(Any.create(_location.getLine()));
0915: }
0916: }
0917: case ParserBaseConstants.STATIC:
0918: // symbol
0919: return construct(listener, null);
0920:
0921: case ParserBaseConstants.MODULE:
0922: // module
0923: consumeSymbol();
0924: if (!hasMoreSymbols()) {
0925: return new TypeNode(_script);
0926: }
0927: return construct(listener, _script);
0928:
0929: case ParserBaseConstants.CLASS:
0930: // class
0931: consumeSymbol();
0932: classtype = _statement.getClassStatement();
0933: if (classtype != null) {
0934: return classConstruct(listener, classtype);
0935: } else {
0936: listener.error(_location,
0937: "Cannot use 'class' outside classes");
0938: return null;
0939: }
0940:
0941: case ParserBaseConstants.FUNCTION: {
0942: // function
0943: consumeSymbol();
0944: FunctionStatement function = _statement
0945: .getFunctionStatement();
0946: if (function != null) {
0947: return onFunction(listener, function);
0948: } else {
0949: listener.error(_location,
0950: "Cannot use 'function' outside functions");
0951: return null;
0952: }
0953: }
0954:
0955: case ParserBaseConstants.THIS:
0956: case ParserBaseConstants.DOT:
0957: // this
0958: // <dot> <symbol> ...
0959: consumeSymbol();
0960: classtype = _statement.getClassStatement();
0961: if (classtype != null) {
0962: if (_statement.isStaticRegion()) {
0963: listener.error(_location,
0964: "Cannot use 'this' in static region");
0965: }
0966: if (hasMoreSymbols()) {
0967: return explicitThisConstruct(listener, classtype);
0968: //return construct(listener, classtype);
0969: } else {
0970: return ThisNode.INSTANCE;
0971: }
0972: } else {
0973: listener.error(_location,
0974: "Cannot use 'this' outside classes");
0975: return null;
0976: }
0977:
0978: case ParserBaseConstants.SUPER:
0979: // super.method(...)
0980: return super Construct(listener);
0981:
0982: case ParserBaseConstants.NEW:
0983: // new ...
0984: consumeSymbol(); // new
0985: return newConstruct(listener, null);
0986:
0987: }
0988: return null;
0989: }
0990:
0991: public Node link(ErrorListener listener) {
0992: Node node = doLink(listener);
0993: if (node == null) {
0994: node = ConstantNode.UNDEFINED;
0995: }
0996: if (node instanceof TypeNode) {
0997: Type type = ((TypeNode) node).getType();
0998: if (type instanceof Synthetic) {
0999: listener.error(_location,
1000: "Cannot refer to synthetic entities");
1001: node = ConstantNode.UNDEFINED;
1002: }
1003: }
1004: if (hasMoreSymbols()) {
1005: while (hasMoreSymbols()) {
1006: if (symbolsLeft() == 1 && hasArgs()) {
1007: // *.symbol(...)
1008: Parent args = consumeArgs();
1009: if (args.hasNamedParameters()) {
1010: listener
1011: .error(_location,
1012: "Named parameters are ignored in anonymous invokes");
1013: }
1014: node = new InvokeNode(node, consumeSymbol(), args);
1015: } else {
1016: // *.symbol
1017: node = new AttributeNode(node, consumeSymbol());
1018: }
1019: }
1020: } else {
1021: // *.(...)
1022: if (hasArgs()) {
1023: Parent args = consumeArgs();
1024: if (args.hasNamedParameters()) {
1025: listener
1026: .error(_location,
1027: "Named parameters are ignored in anonymous calls");
1028: }
1029: node = new DynamicCallNode(node, args);
1030: }
1031: }
1032: return node;
1033: }
1034:
1035: public String getReference() {
1036: return toString();
1037: }
1038:
1039: public Location getLocation() {
1040: return _location;
1041: }
1042:
1043: public Type resolveReference(ErrorListener listener) {
1044: Type type;
1045: if (peekKind() == ParserBaseConstants.MODULE) {
1046: consumeSymbol();
1047: type = _script;
1048: } else {
1049: String symbol = peekSymbol();
1050: type = _statement.lookupAnyDeclaration(symbol);
1051: if (type == null) {
1052: type = LangModule.__module__.lookupDeclaration(symbol);
1053: if (type == null) {
1054: consumeSymbol();
1055: type = lookupLibrary(listener);
1056: } else {
1057: type = LangModule.__module__;
1058: symbol = type.getName();
1059: }
1060: } else {
1061: consumeSymbol();
1062: }
1063: }
1064:
1065: while (true) {
1066:
1067: if (type == null) {
1068: listener.error(_location, "Entity '" + _name
1069: + "' is undeclared");
1070: return null;
1071: }
1072:
1073: type = followImports(listener, type);
1074: if (type == null) {
1075: return null;
1076: }
1077:
1078: switch (type.getType()) {
1079: case Type.MODULE:
1080: case Type.CLASS:
1081: case Type.INTERFACE:
1082: case Type.NAMESPACE: {
1083: if (hasMoreSymbols()) {
1084: type = ((Scope) type)
1085: .lookupDeclaration(consumeSymbol());
1086: break;
1087: } else {
1088: return type;
1089: }
1090: }
1091:
1092: default: {
1093: if (hasMoreSymbols()) {
1094: listener.error(_location, "Entity '" + _name
1095: + "' is undeclared");
1096: }
1097: return type;
1098: }
1099: }
1100: }
1101: }
1102:
1103: public Any eval() {
1104: return Any.UNDEFINED;
1105: }
1106:
1107: public void compile(ByteCompiler context, int operation) {
1108: context.getCode().aconst_null();
1109: }
1110:
1111: }
|