#ifndef __Node_h
#define __Node_h

#define ApplicationClasses			\
  className(Node			)	\
  className(Variable			)	\
  className(GlobalVariable		)	\
  className(LocalVariable		)	\
  className(ReceiverVariable		)	\
  className(StateVariable		)	\
  className(RemoteVariable		)	\
  className(BlockNode			)	\
  className(VariableNode		)	\
  className(ReturnNode			)	\
  className(SelfNode			)	\
  className(SuperNode			)	\
  className(ClassNode			)

#define ApplicationMethods							\
  method(oop	, parent,(void)						,0)	\
  method(int	, level,(void)						,0)	\
  method(int	, offset,(void)						,0)	\
  method(int	, exports,(void)					,0)	\
  method(int	, exportNLR,(void)					,0)	\
  method(int	, exportSelf,(void)					,0)	\
  method(int	, exportOuter,(void)					,0)	\
  method(oop	, print,(void)						,0)	\
  method(oop	, printOnIndent,(oop stream, int indent)		,0)	\
  method(oop	, addKeywordArgument,(oop keyword, oop argument)	,0)	\
  method(oop	, addArgument,(oop argument)				,0)	\
  method(oop	, addMessage,(oop message)				,0)	\
  method(oop	, beVariadic,(void)					,0)	\
  method(int	, variadic,(void)					,0)	\
  method(oop	, withClassSequence,(oop clazz, oop sequence)		,0)	\
  method(oop	, outputStream,(void)					,0)	\
  method(oop	, typeName,(void)					,0)	\
  method(oop	, name,(void)						,0)	\
  method(oop	, mangledName,(void)					,0)	\
  method(oop	, mangledSlot,(oop slotName)				,0)	\
  method(oop	, superclass,(void)					,0)	\
  method(oop	, slots,(void)						,0)	\
  method(oop	, predeclared,(void)					,0)	\
  method(oop	, receiver,(void)					,0)	\
  method(oop	, selector,(void)					,0)	\
  method(oop	, cascade,(void)					,0)	\
  method(oop	, setClass,(oop classNode)				,0)	\
  method(oop	, getClass,(void)					,0)	\
  method(oop	, fork,(void)						,0)	\
  method(oop	, addBlock,(oop blockNode)				,0)	\
  method(oop	, addReceiver,(oop node)				,0)	\
  method(oop	, addCascade,(oop sendNode)				,0)	\
  method(oop	, translationUnit,(void)				,0)	\
  method(oop	, arguments,(void)					,0)	\
  method(oop	, sequence,(void)					,0)	\
  method(oop	, super,(oop super)					,0)	\
  method(oop	, super,(void)						,0)	\
  method(int	, isReturn,(void)					,0)	\
  method(int	, hasReturn,(void)					,0)	\
  method(int	, isOpenBlock,(void)					,0)	\
  method(int	, arity,(void)						,0)	\
  method(int	, location,(void)					,0)	\
  method(int	, tag,(void)						,0)	\
  method(int	, maxStack,(void)					,0)	\
  method(int	, pushStack,(void)					,0)	\
  method(oop	, popStack,(void)					,0)	\
  method(oop	, popStack,(int n)					,0)	\
  method(oop	, ensureReturn,(void)					,0)	\
  method(oop	, ensureBlockReturn,(void)				,0)	\
  method(oop	, declare,(oop name, oop node)				,0)	\
  method(oop	, declareClass,(oop classNode)				,0)	\
  method(oop	, exportFrom,(oop encoder)				,0)	\
  method(int	, isExported,(void)					,0)	\
  method(int	, nextExportOffset,(void)				,0)	\
  method(oop	, noteExportNLR,(void)					,0)	\
  method(oop	, noteExportSelf,(void)					,0)	\
  method(oop	, noteExportOuter,(void)				,0)	\
  method(oop	, noteNLR,(void)					,0)	\
  method(oop	, exported,(void)					,0)	\
  method(oop	, exportedTo,(oop encoder)				,0)	\
  method(oop	, lookup,(oop name)					,0)	\
  method(oop	, lookupFree,(oop name)					,0)	\
  method(oop	, lookupOrNil,(oop name)				,0)	\
  method(oop	, lookupClass,(oop name)				,0)	\
  method(oop	, mangleSelector,(oop name)				,0)	\
  method(oop	, declareSelector,(oop name)				,0)	\
  method(oop	, lookupSelector,(oop name)				,0)	\
  method(oop	, mangleVariable,(oop name)				,0)	\
  method(oop	, declareLocal,(oop name)				,0)	\
  method(oop	, declareGlobal,(oop name)				,0)	\
  method(oop	, lookupVariable,(oop name)				,0)	\
  method(oop	, declareLiteral,(oop literalNode)			,0)	\
  method(oop	, encode,(oop encoder)					,0)	\
  method(oop	, encode,(oop encoder, oop receiver)			,0)	\
  method(oop	, encodeForBlock,(oop encoder)				,0)	\
  method(oop	, encodeLvalue,(oop encoder)				,0)	\
  method(oop	, encodeIn,(oop program)				,0)	\
  method(oop	, encodeVariable,(oop name)				,0)	\
  method(oop	, gen,(oop unit)					,0)	\
  method(oop	, genLvalue,(oop unit)					,0)	\
  method(oop	, genByte,(oop unit)					,0)	\
  method(oop	, genWord,(oop unit)					,0)	\
  method(oop	, genPrototype,(oop unit, oop clazz)			,0)	\
  method(oop	, genBody,(oop unit, oop encoder)			,0)	\
  method(oop	, genSend,(oop unit, int receiverLoc, int resultLoc)	,0)	\
  method(oop	, genDefinition,(oop unit)				,0)	\
  method(oop	, genDefinitions,(void)					,0)	\
  method(oop	, genDeclarationIn,(oop unit)				,0)	\
  method(oop	, genImplementationIn,(oop unit)			,0)	\
  method(oop	, genImplementation,(oop unit)				,0)	\
  method(oop	, genImplementations,(void)				,0)	\
  method(oop	, genInitialisation,(oop unit)				,0)	\
  method(oop	, genInitialisation,(oop unit, oop clazz)		,0)	\
  method(oop	, genInitialisations,(void)				,0)	\
  method(oop	, genInitialisationIn,(oop unit)			,0)	\
  method(oop	, compile,(void)					,0)

#include "oop.h"


struct Environment : Dictionary
{
  className(Environment);

  oop mParent;

  Environment(oop parent= 0);

  virtual oop declare(oop name, oop node);
  virtual oop lookupOrNil(oop name);
  virtual oop lookup(oop name);
};


struct TranslationUnit : Environment
{
  className(TranslationUnit);

  oop mOutputStream;
  oop mSelectors;

  TranslationUnit(void);

  virtual oop outputStream(void);

  virtual oop declare(oop name, oop node);
  virtual oop declareClass(oop classNode);
  virtual oop declareSelector(oop name);
  virtual oop declareGlobal(oop name);

  virtual oop lookup(oop name);
  virtual oop lookupClass(oop name);
  virtual oop lookupSelector(oop name);

  virtual oop mangleSelector(oop name);
  virtual oop mangleVariable(oop name);

  virtual oop genDefinitions(void);
  virtual oop genInitialisations(void);
};


struct Encoder : Object
{
  className(Encoder);

  oop mTranslationUnit;
  oop mEnvironment;
  oop mLiterals;
  int mLocation;
  int mMaxStack;
  oop mBlocks;
  oop mParent;
  int mLevel;
  oop mImports;
  int mExports;
  int mExportSelf;
  int mExportNLR;
  int mExportOuter;
  oop mClass;

  Encoder(oop unit, oop parent);

  virtual oop translationUnit(void);
  virtual int location(void);
  virtual int maxStack(void);
  virtual oop parent(void);
  virtual int level(void);
  virtual int exports(void);
  virtual int exportNLR(void);
  virtual int exportSelf(void);
  virtual int exportOuter(void);

  virtual oop setClass(oop classNode);
  virtual oop getClass(void);
  virtual oop fork(void);

  virtual oop declareLiteral(oop node);
  virtual oop declareLocal(oop name);
  virtual oop declare(oop name, oop node);
  virtual oop lookup(oop name);
  virtual oop lookupFree(oop name);

  virtual int nextExportOffset(void);
  virtual oop noteExportNLR(void);
  virtual oop noteExportSelf(void);
  virtual oop noteExportOuter(void);

  virtual int pushStack(void);
  virtual oop popStack(void);
  virtual oop popStack(int n);

  virtual oop addBlock(oop blockNode);

  virtual oop genDefinitions(void);
  virtual oop genImplementations(void);
  virtual oop genInitialisations(void);
};


struct Variable : Object
{
  className(Variable);

  oop mName;
  oop mMangledName;

  Variable(oop name, oop mangled= 0);

  oop name(void);
  oop mangledName(void);

  virtual int operator ==(oop anObject);

  virtual int isOpenBlock(void);

  virtual oop gen(oop unit);

  virtual oop printOn(oop stream);
};

struct GlobalVariable : Variable
{
  className(GlobalVariable);

  GlobalVariable(oop name, oop mangled= 0);

  virtual int level(void);
};

struct LocalVariable : Variable
{
  className(LocalVariable);

  int mLevel;
  int mExported;
  int mOffset;

  LocalVariable(oop name, oop mangled, int level);

  virtual int level(void);
  virtual int isExported(void);
  virtual int offset(void);

  virtual oop exportFrom(oop encoder);
  virtual oop exportedTo(oop encoder);

  virtual oop gen(oop unit);
};


struct ReceiverVariable : Variable
{
  className(ReceiverVariable);

  oop mClass;

  ReceiverVariable(oop name, oop mangled, oop classNode);

  virtual oop getClass(void);

  virtual int level(void);
  virtual int isExported(void);
  virtual oop exported(void);

  virtual oop exportFrom(oop encoder);
  virtual oop exportedTo(oop encoder);

  virtual oop gen(oop unit);
};


struct RemoteReceiverVariable : Object
{
  className(RemoteReceiverVariable);

  oop mReceiverVariable;

  RemoteReceiverVariable(oop receiverVariable);

  virtual oop name(void);

  virtual int level(void);
  virtual int isExported(void);

  virtual oop gen(oop unit);
};


struct SelfNode : LocalVariable
{ 
  className(SelfNode);

  SelfNode(void);

  virtual oop exportFrom(oop encoder);
  virtual oop exportedTo(oop encoder);

  virtual oop gen(oop unit);
};


struct SuperNode : LocalVariable
{ 
  className(SuperNode);

  SuperNode(void);

  oop encode(oop encoder);
};


struct StateVariable : Object
{
  className(StateVariable);

  int mOffset;

  StateVariable(int offset);

  virtual oop gen(oop unit);

  virtual oop printOn(oop stream);
};


struct RemoteVariable : StateVariable
{
  className(RemoteVariable);

  int mLevel;

  RemoteVariable(int level, int offset);

  virtual int level(void);

  virtual oop gen(oop unit);

  virtual oop printOn(oop stream);
};


struct Node : Object
{
  className(Node);

  int	mLocation;

  Node(void);

  virtual int location(void);

  virtual int isOpenBlock(void);
  virtual int isReturn(void);

  virtual oop print(void);
  virtual oop printOnIndent(oop stream, int indent);
};


struct ListNode : OrderedCollection
{
  className(ListNode);

  static oop empty(void);
  static oop with(oop anObject);
  static oop with(oop a, oop b);
  static oop with(oop a, oop b, oop c);
  static oop with(oop a, oop b, oop c, oop d);

  virtual oop print(void);
  virtual oop printOnIndent(oop stream, int indent);
};


struct ProgramNode : ListNode
{
  className(ProgramNode);

  ProgramNode(void);

  virtual oop compile(void);
};


struct ClassNode : GlobalVariable
{
  className(ClassNode);

  oop mTypeName;
  oop mSuper;
  oop mSlots;
  oop mExports;

  ClassNode(oop name, oop super, oop slots);

  static oop withName(oop name);
  static oop withNameSlots(oop name, oop slots);
  static oop withNameSuper(oop name, oop super);
  static oop withNameSuperSlots(oop name, oop super, oop slots);

  virtual oop name(void);
  virtual oop typeName(void);
  virtual oop superclass(void);
  virtual oop slots(void);

  virtual oop predeclared(void);

  virtual int operator ==(oop anObject);

  virtual oop mangleSlot(oop slotName);

  virtual oop encodeIn(oop program);
  virtual oop encode(oop encoder);
  virtual oop encodeForBlock(oop encoder);

  virtual oop genDeclarationIn(oop unit);
  virtual oop genImplementationIn(oop unit);
  virtual oop genInitialisationIn(oop unit);

  virtual oop printOn(oop stream);
  virtual oop printOnIndent(oop stream, int indent);
};


struct ExecNode : Node
{
  className(ExecNode);

  oop	mEncoder;	// Encoder
  oop	mSequence;

  ExecNode(oop sequence);

  static oop withSequence(oop sequence);

  virtual oop encodeIn(oop unit);

  virtual oop genDeclarationIn(oop unit);
  virtual oop genImplementationIn(oop unit);
  virtual oop genInitialisationIn(oop unit);

  virtual oop printOn(oop stream);
  virtual oop printOnIndent(oop stream, int indent);
};


struct MethodNode : ExecNode
{
  className(MethodNode);

  oop mClass;
  oop mSelector;
  oop mArguments;
  int mVariadic;

  MethodNode(oop selector, oop arguments);

  static oop withSelector(oop selector);
  static oop withSelectorArgument(oop selector, oop argument);
  static oop withSelectorArguments(oop selector, oop arguments);

  virtual oop addKeywordArgument(oop keyword, oop argument);
  virtual oop withClassSequence(oop clazz, oop sequence);

  virtual oop beVariadic(void);
  virtual int variadic(void);

  virtual oop encodeIn(oop unit);

  virtual oop genDeclarationIn(oop unit);
  virtual oop genImplementationIn(oop unit);
  virtual oop genInitialisationIn(oop unit);

  virtual oop printOn(oop stream);
  virtual oop printOnIndent(oop stream, int indent);
};


struct SequenceNode : Node
{
  className(SequenceNode);

  oop	mTemporaries;
  oop	mStatements;

  SequenceNode(oop temporaries, oop statements);

  static oop empty(void);
  static oop withTemporaries(oop temporaries);
  static oop withStatements(oop statements);
  static oop withStatement(oop statement);
  static oop withTemporariesStatements(oop temporaries, oop statements);

  virtual int hasReturn(void);

  virtual oop ensureReturn(void);
  virtual oop ensureBlockReturn(void);

  virtual oop encode(oop encoder);

  virtual oop genBody(oop unit, oop encoder);

  virtual oop printOnIndent(oop stream, int indent);
};


struct BlockReturnNode : Node
{
  className(BlockReturnNode);

  oop mValue;

  BlockReturnNode(oop value);

  static oop withValue(oop value);

  virtual int isReturn(void);

  virtual oop encode(oop encoder);

  virtual oop gen(oop unit);

  virtual oop printOnIndent(oop stream, int indent);
};


struct ReturnNode : BlockReturnNode
{
  className(ReturnNode);

  int mLevel;

  ReturnNode(oop value);

  static oop withValue(oop value);

  virtual oop encode(oop encoder);

  virtual oop gen(oop unit);
};


struct AssignmentNode : Node
{
  className(AssignmentNode);

  oop mVariable;
  oop mValue;

  AssignmentNode(oop variable, oop value);

  oop encode(oop encoder);

  oop gen(oop unit);

  static oop withVariableValue(oop variable, oop value);
};


struct SendNode : Node
{
  className(SendNode);

  oop mReceiver;
  oop mSelector;
  oop mArguments;
  oop mCascade;
  oop mSuper;

  oop (SendNode::*mGenMacro)(oop unit);

  SendNode(oop selector, oop arguments);

  static oop withSelector(oop selector);
  static oop withSelectorArgument(oop receiver, oop arguments);

  virtual oop addReceiver(oop receiver);
  virtual oop addKeywordArgument(oop keyword, oop argument);
  virtual oop addArgument(oop argument);
  virtual oop addCascade(oop cascade);

  virtual oop receiver(void);
  virtual oop selector(void);
  virtual oop arguments(void);
  virtual oop cascade(void);

  virtual oop super(oop super);
  virtual oop super(void);

  virtual oop encodeMacro(oop encoder);
  virtual oop encode(oop encoder);

  virtual oop gen_add_(oop unit);
  virtual oop gen_sub_(oop unit);
  virtual oop gen_mul_(oop unit);
  virtual oop gen_div_(oop unit);
  virtual oop gen_mod_(oop unit);
  virtual oop gen_lt_(oop unit);
  virtual oop gen_le_(oop unit);
  virtual oop gen_eq_(oop unit);
  virtual oop gen_id_(oop unit);
  virtual oop gen_ni_(oop unit);
  virtual oop gen_ne_(oop unit);
  virtual oop gen_ge_(oop unit);
  virtual oop gen_gt_(oop unit);
  virtual oop gen_bitAnd_(oop unit);
  virtual oop gen_bitOr_(oop unit);
  virtual oop gen_bitXor_(oop unit);
  virtual oop gen_value(oop unit);
  virtual oop gen_and_(oop unit);
  virtual oop gen_or_(oop unit);
  virtual oop gen_ifTrue_(oop unit);
  virtual oop gen_ifFalse_(oop unit);
  virtual oop gen_ifTrue_ifFalse_(oop unit);
  virtual oop gen_ifFalse_ifTrue_(oop unit);
  virtual oop gen_whileTrue(oop unit);
  virtual oop gen_whileTrue_(oop unit);
  virtual oop gen_whileFalse(oop unit);
  virtual oop gen_whileFalse_(oop unit);
  virtual oop gen(oop unit);

  virtual oop printOnIndent(oop stream, int indent);
};


struct MessageNode : Node
{
  className(MessageNode);

  oop mSelector;
  oop mArguments;

  MessageNode(oop selector, oop arguments);

  static oop withSelector(oop selector);
  static oop withSelectorArgument(oop selector, oop argument);
  static oop withSelectorArguments(oop selector, oop arguments);

  virtual oop addKeywordArgument(oop keyword, oop argument);

  virtual oop encode(oop encoder, oop receiver);

  virtual oop gen(oop unit);
  virtual oop genSend(oop unit, int receiverLoc, int resultLoc);

  virtual oop printOnIndent(oop stream, int indent);
};


struct BlockNode : Node
{
  className(BlockNode);

  static int Tag;

  int mTag;
  oop mEncoder;
  oop mArguments;
  oop mSequence;

  BlockNode(oop arguments, oop sequence);

  static oop withArgumentsSequence(oop arguments, oop sequence);
  static oop withSequence(oop sequence);

  virtual oop arguments(void);
  virtual oop sequence(void);

  virtual int isOpenBlock(void);
  virtual int arity(void);

  virtual oop encode(oop encoder);

  virtual oop genDefinition(oop unit);
  virtual oop genImplementation(oop unit);
  virtual oop genInitialisation(oop unit);

  virtual oop genStatic(oop unit);
  virtual oop genFull(oop unit);
  virtual oop genNLR(oop unit);
  virtual oop gen(oop unit);
};


struct VariableNode : Node
{
  className(VariableNode);

  oop mName;
  int mLevel;
  oop mVariable;

  VariableNode(oop name);

  static oop withName(oop name);

  virtual oop name(void);

  virtual oop encodeLvalue(oop encoder);
  virtual oop encode(oop encoder);

  virtual oop gen(oop unit);
  virtual oop genLvalue(oop unit);

  virtual oop printOn(oop stream);
};


struct ConstantNode : Node
{
  className(ConstantNode);

  oop mValue;

  ConstantNode(oop value);
};


struct LiteralNode : Node
{
  className(LiteralNode);

  static int Tag;

  int mTag;

  LiteralNode(void);

  virtual int tag(void);

  virtual oop encode(oop encoder);

  virtual oop genDefinition(oop unit);
  virtual oop genInitialisation(oop unit);
  virtual oop gen(oop unit);
};


struct IntegerNode : LiteralNode
{
  className(IntegerNode);

  int mValue;

  IntegerNode(int value);

  static oop fromString(oop string);

  virtual oop encode(oop encoder);

  virtual oop genInitialisation(oop unit);
  virtual oop genByte(oop unit);
  virtual oop genWord(oop unit);

  virtual oop printOn(oop stream);
};


struct CharacterNode : LiteralNode
{
  className(CharacterNode);

  int mValue;

  CharacterNode(int value);

  static oop fromString(oop string);

  virtual oop encode(oop encoder);

  virtual oop genInitialisation(oop unit);

  virtual oop printOn(oop stream);
};


struct StringNode : LiteralNode
{
  className(StringNode);

  oop mValue;

  StringNode(oop value);

  static oop fromString(oop string);
  static oop unescape(oop string);

  virtual oop encode(oop encoder);

  virtual oop genInitialisation(oop unit);

  virtual oop printOn(oop stream);
};


struct SymbolNode : StringNode
{
  className(SymbolNode);

  SymbolNode(oop value);

  static oop fromString(oop string);

  virtual oop encode(oop encoder);

  virtual oop genInitialisation(oop unit);

  virtual oop printOn(oop stream);
};


struct ByteArrayNode : LiteralNode
{
  className(ByteArrayNode);

  oop mElements;

  ByteArrayNode(oop elements);

  static oop withElements(oop elements);

  oop encode(oop encoder);
  oop genInitialisation(oop unit);

  oop printOn(oop stream);
};


struct WordArrayNode : LiteralNode
{
  className(WordArrayNode);

  oop mElements;

  WordArrayNode(oop elements);

  static oop withElements(oop elements);

  oop encode(oop encoder);

  oop genDefinition(oop unit);
  oop genInitialisation(oop unit);

  oop printOn(oop stream);
};


struct ArrayNode : LiteralNode
{
  className(ArrayNode);

  oop mElements;

  ArrayNode(oop elements);

  static oop withElements(oop elements);

  oop encode(oop encoder);

  oop genDefinition(oop unit);
  oop genInitialisation(oop unit);

  oop printOn(oop stream);
};


#if 0

struct LeafNode : Node
{
  oop mName;

  LeafNode(oop name);

  virtual oop name(void);

  virtual oop printOn(oop stream);
};

#endif


struct ExternNode : Node
{
  className(ExternNode);

  oop	mCode;

  ExternNode(oop code);

  static oop withCode(oop code);

  virtual oop encode(oop encoder);

  virtual oop gen(oop unit);

  virtual oop printOn(oop stream);
};


#endif // __Node_h
