#ifndef _SYMTAB_H_
#define _SYMTAB_H_ 1

#include <wchar.h>

extern int debug_scope;

#ifdef OLD_VERSION
#define DATA void *
#define NO_DATA NULL
#else
#define DATA int
#define NO_DATA (-1)
#endif

// This library provides support routines for handling scoped symbol tables.

// Goals:
// 1) support multiple independent symbol tables per scope.
// 2) need to be able to check that a new name does
//    not already exist in this scope and this table.
// 3) support looking up a name in specific table,
//    and return entry from most recent scope including this one.

// Addendum: one of the things you need to be able to do with a symbol table
//           is look up a name and see whether it was declared in the current
//           scoping block or a parent block.  I'm sure I must have allowed
//           for this when I created this module but it was so long ago that
//           I've forgotten any details, so this is a reminder to myself to
//           check the interface and see how that would be done.  This is a
//           separate test from just creating a new ID in the current scope
//           and seeing if it succeeds or not depending on whether the name
//           was already declared in this scope.  I think.  Or maybe that is
//           sufficient and a separate test is not needed?

//           Also I need to check (on a language by language basis) whether
//           statements like "int fred = fred + 1;" are valid, i.e. the 'fred'
//           on the RHS coming from a parent scope.


// Scopes:
//    0 (base_level_scope) Would handle Imp %prim intrinsic routines known to compiler;
//        in C, perhaps things like __FUNCTION__ if they were variables rather than macros
//    1 for explicit declarations (eg externals) at top level before any nested scopes
//      - can replace something that was at level 0 (eg PRINTSTRING)
//        with an external call.
// 2..n first '{' takes us into scope level 2.

// This module does not define the symbol table format itself - that
// is managed by the caller's code - what we do here is assist in
// searching the symbol table while obeying scope rules.
// Actual symbol table entries are passed in and out as opaque "void *" objects.  NO. Now as DATA type which is being changed to "int" ...

extern int current_scope;  // Base scope is scope 0. Most recent scope (top level) is current_scope. Initially -1.

// This interface is under development and may change if we encounter
// problems during integration with my new C compiler...

// One pending change is to use StringPool indices instead of char *.  Faster too.

// There is no 'lookup only in a specific scope' call, as there appears
// to be no need for one yet.

// Initial interface used char * as the key.  However in some cases we want to use wchar_t * and
// in others, simply the stringpool index or an AST_LITERAL or one of many other (hopefully, tagged) DATA types.

// REMEMBER however that a stringpool index is not a 1:1 mapping from a string - the same string may have
// multiple occurances in the stringpool.  We do not enforce uniqueness (which although a useful property
//  is too complex or expensive to be worth implementing)

extern int add_entry(char *table_name, wchar_t *entry_name, DATA entry_data); // returns FALSE if already exists in this scope.
extern int add_entry_by_strpoolidx(char *table_name, DATA entry_name_strpoolidx, DATA entry_data); // returns FALSE if already exists in this scope.
// (Table is created on the fly if one doesn't already exist in the current top-level scope)

extern DATA lookup(char *table_name, wchar_t *entry_name);
extern DATA lookup_by_strpoolidx(char *table_name, DATA entry_name_strpoolidx);

extern int scope_level(char *table_name, wchar_t *entry_name);
extern int scope_level_by_strpoolidx(char *table_name, DATA entry_name_strpoolidx);

// to determine if an identifier is a variable or a typename (when it could be either)
// you can lookup in both tables and decide according to which lookup is the most
// recent scope (ie highest scope value).  Note that a 'not found' result is returned
// as scope -1.

// It might be useful to have a tag that can be added to a scope level
// in case it matters what type of scope was entered.  This should be
// separate from the explicit stucture stack such as in Imp where you
// have to keep track of begin/routine/start/cycle nesting.  Meanwhile, not.
extern void push_scope_level(void);
extern void pop_scope_level(void);

// NON-SCOPED TABLES:

int anonymous_table(void);

// This is primarily for record fields but written somewhat generically at the top level as this part of the code is target language independent.
// The procedure name is a bit verbose but the shorter names that I could think of were more easily confused with scoped tables.

typedef int TableIDX;

int add_entry_to_anonymous_table(TableIDX tableIDX,  wchar_t *entry_name, DATA entry_data);

#endif
