package slangc.model; import slangc.api.Reporter; import slangc.bytecode.FieldSignature; import slangc.parser.Branch; import slangc.parser.ErrorType; import slangc.parser.Node; import slangc.parser.NodeType; public class FieldModel extends MemberModel implements ExpressionOwner, StorageSlot { private Branch slotSource; private TypeModel baseStorageType; private ExpressionModel initialisation; private LocalStorageModel upvalueReference; private boolean isEnum = false; public FieldModel(UserTypeModel owner, String name, Branch source, Branch slotSource) { super(owner, name, source); this.slotSource = slotSource; baseStorageType = owner.resolveTypeReference(source.getSubnode(1)); //if (baseStorageType == null) { // sourceFile.annotate(ErrorType.INTERNAL_ERROR, "Can't find storage type for field"); //} if (hasInitialiser()) { initialisation = ExpressionModel.construct(this, slotSource.getSubnode(2)); } } public FieldModel(UserTypeModel owner, String name, Branch source) { super(owner, name, source); isEnum = true; } public FieldModel(UserTypeModel owner, String name, LocalStorageModel upvalueReference) { super(owner, name, null); this.upvalueReference = upvalueReference; baseStorageType = upvalueReference.getStorageType(); } public Node getNameNode() { return slotSource.getSubnode(0); } public String getName() { if (isEnum) { return super.getName(); } if (upvalueReference != null) { return upvalueReference.getName(); } return UserTypeModel.plainName(getNameNode()); } public int countAdditionalIndices() { if (isUpvalue()) { return 0; } Node n = getNameNode(); int i = 0; while (n.getNodeType() == NodeType.INDEXED_NAME) { n = ((Branch) n).getSubnode(0); i++; } return i; } public TypeModel getStorageType() { if (isEnum) { return getOwner(); } TypeModel effectiveType = baseStorageType; if (effectiveType == null) { return null; } for (int i = 0; i < countAdditionalIndices(); i++) { effectiveType = effectiveType.getOrCreateArrayInstance(); } return effectiveType; } @Override public MemberCategory getCategory() { return MemberCategory.FIELD; } public Branch getSlotSource() { return slotSource; } public boolean hasInitialiser() { if (isEnum) { return false; // Kind of does have an initialiser but is treated specially. } if (isUpvalue()) { return false; // Kind of does have an initialiser but is treated specially. } return getSlotSource().getNodeType() == NodeType.INITIALISED_SLOT; } //public TypeModel getStorageType() { // return baseStorageType; //} public ExpressionModel getInitialisationExpression() { return initialisation; } @Override public void dump(Reporter reporter, String indent, String incr) { super.dump(reporter, indent, incr); if (baseStorageType != null) { reporter.note("DUMP", indent + incr + "> Storage type is " + baseStorageType); } else { reporter.note("DUMP", "[no storage type information]"); } if (hasInitialiser()) { reporter.note("DUMP", indent + incr + "> Initialised with expression:"); initialisation.dump(reporter, indent + incr + incr, incr); } else { reporter.note("DUMP", indent + incr + "[this field is not initialised]"); } } //@Override public TypeModel getExpectedResult(ExpressionModel e) { return getStorageType(); } //@Override public InnerTypeScope getTypeScope() { return getOwner(); } //@Override public TypeModel resolveType(Node typeReference) { return ((UserTypeModel)getOwner()).resolveTypeReference(typeReference); } //@Override public MemberModel getMethodOrField() { return this; } //@Override public StorageSlot.Kind getSlotKind() { if (isStatic()) { return StorageSlot.Kind.STATIC_FIELD; } else { return StorageSlot.Kind.INSTANCE_FIELD; } } //@Override public Named lookupSimpleName(String name) { return getOwner().lookupSimpleName(name); } //@Override public MethodModel[] lookupSimpleMethod(String name) { return getOwner().lookupSimpleMethod(name); } @Override public int resolveExpressions() { if (hasInitialiser()) { return getInitialisationExpression().resolveExpressions(); } else { return 0; } } @Override public boolean isStatic() { if (isEnum) { // Enum fields are always static return true; } // Interface fields are assumed to be static if (getOwner().getTypeType() == TypeType.INTERFACE || getOwner().getTypeType() == TypeType.INTERFACE_TEMPLATE) { return true; } return super.isStatic(); } public boolean isEnumField() { return isEnum; } public boolean isUpvalue() { return upvalueReference != null; } public LocalStorageModel getUpvalueReference() { return upvalueReference; } @Override public int getFlags() { return super.getFlags() | (isUpvalue() ? (Flags.MASK_UPVALUE | Flags.MASK_SYNTHETIC | Flags.MASK_FINAL) : 0); } public FieldSignature getFieldSignature() { return new FieldSignature(getOwner().getTypeSignature(), isStatic(), getStorageType().getTypeSignature(), getName()); } }