package org.antlr.symtab;

import org.antlr.v4.runtime.ParserRuleContext;

import java.util.List;
import java.util.Map;

/** A symbol representing a collection of data like a struct or class.
 *  Each member has a slot number indexed from 0 and we track data fields
 *  and methods with different slot sequences. A DataAggregateSymbol
 *  can also be a member of an aggregate itself (nested structs, ...).
 */
public abstract class DataAggregateSymbol extends SymbolWithScope implements MemberSymbol, Type {
	protected ParserRuleContext defNode;
	protected int nextFreeFieldSlot = 0;  // next slot to allocate

	public DataAggregateSymbol(String name) {
		super(name);
	}

	public void setDefNode(ParserRuleContext defNode) {
		this.defNode = defNode;
	}

	public ParserRuleContext getDefNode() {
		return defNode;
	}

	@Override
	public void define(Symbol sym) throws IllegalArgumentException {
		if ( !(sym instanceof MemberSymbol) ) {
			throw new IllegalArgumentException(
				"sym is "+sym.getClass().getSimpleName()+" not MemberSymbol"
			);
		}
		super.define(sym);
		setSlotNumber(sym);
	}

	@Override
	public List<MemberSymbol> getSymbols() {
		return (List<MemberSymbol>)super.getSymbols();
	}

	@Override
	public Map<String, ? extends MemberSymbol> getMembers() {
		return (Map<String, ? extends MemberSymbol>)super.getMembers();
	}

	/** get the number of fields defined specifically in this class */
	public int getNumberOfDefinedFields() {
		int n = 0;
		for (MemberSymbol s : getSymbols()) {
			if ( s instanceof FieldSymbol ) {
				n++;
			}
		}
		return n;
	}

	/** get the total number of fields visible to this class */
	public int getNumberOfFields() {
		int n = 0;
		if ( getParentScope() instanceof DataAggregateSymbol ) {
			DataAggregateSymbol parentScope = (DataAggregateSymbol)getParentScope();
			n += parentScope.getNumberOfFields();
		}
		n += getNumberOfDefinedFields();
		return n;
	}


	public void setSlotNumber(Symbol sym) {
		if ( sym instanceof FieldSymbol) {
			FieldSymbol fsym = (FieldSymbol)sym;
			fsym.slot = nextFreeFieldSlot++;
		}
	}

	@Override
	public int getSlotNumber() {
		return -1; // class definitions do not yield either field or method slots; they are just nested
	}
}

@@ -68,16 +68,44 @@
 ntext;%0A%0A
+import java.util.ArrayList;%0A
 import j
@@ -1938,16 +1938,599 @@
  n;%0A%09%7D%0A%0A
+%09public List%3C? extends FieldSymbol%3E getDefinedFields() %7B%0A%09%09List%3CFieldSymbol%3E fields = new ArrayList%3C%3E();%0A%09%09for (MemberSymbol s : getSymbols()) %7B%0A%09%09%09if (s instanceof FieldSymbol) %7B%0A%09%09%09%09fields.add((FieldSymbol)s);%0A%09%09%09%7D%0A%09%09%7D%0A%09%09return fields;%0A%09%7D%0A%0A%09public List%3C? extends FieldSymbol%3E getFields() %7B%0A%09%09List%3CFieldSymbol%3E fields = new ArrayList%3C%3E();%0A%09%09if ( getParentScope() instanceof DataAggregateSymbol ) %7B%0A%09%09%09DataAggregateSymbol parentScope = (DataAggregateSymbol)getParentScope();%0A%09%09%09fields.addAll( parentScope.getFields() );%0A%09%09%7D%0A%09%09fields.addAll( getDefinedFields() );%0A%09%09return fields;%0A%09%7D%0A
 %0A%09public

add getFields