/*
 * Copyright (c) 1992-1993 Silicon Graphics, Inc.
 * Copyright (c) 1993 Fujitsu, Ltd.
 *
 * Permission to use, copy, modify, distribute, and sell this software and 
 * its documentation for any purpose is hereby granted without fee, provided
 * that (i) the above copyright notices and this permission notice appear in
 * all copies of the software and related documentation, and (ii) the names of
 * Silicon Graphics and Fujitsu may not be used in any advertising or
 * publicity relating to the software without the specific, prior written
 * permission of Silicon Graphics and Fujitsu.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
 *
 * IN NO EVENT SHALL SILICON GRAPHICS OR FUJITSU BE LIABLE FOR
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
 * OF THIS SOFTWARE.
 */

/*
 * Resolve names and do type-checking
 */

#include "err.h"
#include "expr-impl.h"
#include "list.h"
#include "table.h"
#include "table2.h"
#include <stdio.h>

struct Context {
    Symbol* in_symbol;
    Symbol* out_symbol;
    Expr* type_expr;
};

declareList(ContextList,Context)
implementList(ContextList,Context)

declareTable(CaseTable,long,long)
implementTable(CaseTable,long,long)

class Resolver {
public:
    Resolver(Expr* superclass, SymbolTable*, ErrorHandler*);
    virtual ~Resolver();

    Expr* superclass();
    SymbolTable* symbol_table();
    Scope* enter_scope(Identifier*);
    Scope* scope();
    void leave_scope();
    void push_context(Context*);
    void push_context(Symbol*, Expr* = nil);
    void push_context();
    Context* context();
    void symbol(Symbol*);
    void pop_context();
    void bind(Identifier*, Symbol*);
    Symbol* resolve(Identifier*);
    Symbol* new_symbol(Identifier*);
    ErrorHandler* handler();
    void undefined(Expr*, String*);
    void redefined(Identifier*);
    void symerr(Expr*, String*, const char* message);
    void error(Expr*, const char* message);
private:
    Expr* superclass_;
    SymbolTable* symbols_;
    ErrorHandler* handler_;
    ContextList* contexts_;

    Symbol* true_;
    Symbol* false_;
    Symbol* builtin_type(
	const char* name, const char* mapping, long kind, Boolean enter = true
    );
};

inline Expr* Resolver::superclass() { return superclass_; }

inline unsigned long key_to_hash(String& s) { return s.hash(); }

declareTable2(SymbolMap,Scope*,IdentString,Symbol*)
implementTable2(SymbolMap,Scope*,IdentString,Symbol*)

/* class Resolver */

Resolver::Resolver(Expr* superclass, SymbolTable* s, ErrorHandler* h) {
    superclass_ = superclass;
    symbols_ = s;
    handler_ = h;
    contexts_ = new ContextList(3);
    symbols_->enter_scope(nil);
    s->void_ = builtin_type("void", "void", 1);
    s->oneway_ = builtin_type("oneway", "void", 2, false);
    s->boolean_ = builtin_type("boolean", "Boolean", 3);
    s->char_ = builtin_type("char", "Char", 4);
    s->octet_ = builtin_type("octet", "Octet", 5);
    s->short_ = builtin_type("short", "Short", 6);
    s->ushort_ = builtin_type("unsigned_short", "UShort", 7, false);
    s->long_ = builtin_type("long", "Long", 8);
    s->ulong_ = builtin_type("unsigned_long", "ULong", 9, false);
    s->longlong_ = builtin_type("longlong", "LongLong", 10);
    s->ulonglong_ = builtin_type("unsigned_longlong", "ULongLong", 11, false);
    s->float_ = builtin_type("float", "Float", 12);
    s->double_ = builtin_type("double", "Double", 13);
    s->string_ = builtin_type("string", "string", 14);
    true_ = builtin_type("TRUE", "TRUE", 1);
    false_ = builtin_type("FALSE", "FALSE", 1);
}

Resolver::~Resolver() {
    handler_->destroy();
    delete contexts_;
}

SymbolTable* Resolver::symbol_table() { return symbols_; }

Scope* Resolver::enter_scope(Identifier* i) {
    return symbols_->enter_scope(i->string());
}

Scope* Resolver::scope() { return symbols_->scope(); }
void Resolver::leave_scope() { symbols_->leave_scope(); }

void Resolver::push_context(Context* c) {
    contexts_->prepend(*c);
}

void Resolver::push_context(Symbol* s, Expr* t) {
    Context c;
    c.in_symbol = s;
    c.out_symbol = nil;
    c.type_expr = t;
    contexts_->prepend(c);
}

void Resolver::push_context() {
    Context c;
    c.in_symbol = nil;
    c.out_symbol = nil;
    c.type_expr = nil;
    contexts_->prepend(c);
}

Context* Resolver::context() {
    Context* c;
    if (contexts_->count() == 0) {
	c = nil;
    } else {
	c = &contexts_->item_ref(0);
    }
    return c;
}

void Resolver::symbol(Symbol* s) {
    if (contexts_->count() != 0) {
	contexts_->item_ref(0).out_symbol = s;
    }
}

void Resolver::pop_context() {
    ContextList* list = contexts_;
    if (list->count() != 0) {
	Symbol* s = list->item_ref(0).out_symbol;
	list->remove(0);
	if (list->count() != 0) {
	    list->item_ref(0).out_symbol = s;
	}
    }
}

void Resolver::bind(Identifier* ident, Symbol* s) {
    symbols_->bind(ident->string(), s);
}

Symbol* Resolver::resolve(Identifier* ident) {
    return symbols_->resolve(ident->string());
}

Symbol* Resolver::new_symbol(Identifier* ident) {
    Scope* block = scope();
    Symbol* s = resolve(ident);
    if (s == nil || s->scope() != block) {
	s = new Symbol(block);
	bind(ident, s);
    } else {
	redefined(ident);
    }
    return s;
}

ErrorHandler* Resolver::handler() { return handler_; }

void Resolver::undefined(Expr* e, String* s) {
    symerr(e, s, "undefined");
}

void Resolver::redefined(Identifier* i) {
    symerr(i, i->string(), "redefined");
}

void Resolver::symerr(Expr* e, String* s, const char* message) {
    ErrorHandler* err = handler_;
    e->set_source_position(err);
    err->begin_error();
    err->put_chars("Symbol \"");
    err->put_string(*s);
    err->put_chars("\" ");
    err->put_chars(message);
    err->end();
}

void Resolver::error(Expr* e, const char* message) {
    ErrorHandler* err = handler_;
    e->set_source_position(err);
    err->error(message);
}

Symbol* Resolver::builtin_type(
    const char* name, const char* mapping, long kind, Boolean enter
) {
    IdentString* u = new IdentString(name);
    TypeName* t = new TypeName(handler_->position());
    t->builtin(u, new String(mapping), kind);
    Symbol* s = new Symbol(scope());
    s->typename(t);
    if (enter) {
	symbols_->bind(u, s);
    }
    return s;
}

/*
 * Create symbol table and resolver.
 */

SymbolTable* ExprKit::symbol_table() {
    return new SymbolTable;
}

Resolver* ExprKit::resolver(const ConfigInfo& cf) {
    return new Resolver(
	(cf.superclass == nil) ?
	    nil : forward_interface(ident(new String(cf.superclass))),
	cf.symbols, impl_->handler_
    );
}

/*
 * Resolve operations for different kinds of expressions.
 */

void ExprImpl::resolve(Resolver*) { }

void ExprImpl::resolve_list(ExprList* list, Resolver* r) {
    if (list != nil) {
	for (ListItr(ExprList) i(*list); i.more(); i.next()) {
	    i.cur()->resolve(r);
	}
    }
}

void RootExpr::resolve(Resolver* r) {
    Expr* e = r->superclass();
    if (e != nil) {
	e->resolve(r);
    }
    resolve_list(defs_, r);
}

void Module::resolve(Resolver* r) {
    Symbol* s = r->new_symbol(ident_);
    s->module(this);
    symbol_ = s;
    block_ = r->enter_scope(ident_);
    resolve_list(defs_, r);
    r->leave_scope();
}

void InterfaceDef::resolve(Resolver* r) {
    Boolean new_symbol = false;
    Symbol* s = r->resolve(ident_);
    InterfaceDef* i;
    if (s == nil) {
	new_symbol = true;
	s = new Symbol(r->scope());
	r->bind(ident_, s);
	i = nil;
    } else {
	i = s->interface();
    }
    symbol_ = s;
    if (i == nil) {
	info_ = new InterfaceInfo;
	info_->block = nil;
	info_->has_body = false;
	info_->generated_decl = false;
	info_->generated_body = false;
	info_->op_index = 0;
    } else {
	info_ = i->info_;
    }
    if (forward_) {
	if (new_symbol) {
	    s->interface(this);
	} else if (i == nil) {
	    r->redefined(ident_);
	}
    } else {
	if (!new_symbol) {
	    InterfaceDef* i = s->interface();
	    if (i == nil || !i->forward_) {
		r->redefined(ident_);
	    }
	}
	/*
	 * Still need to check:
	 *    Supertypes are interfaces
	 *    No redundant supertypes
	 */
	if (supertypes_ != nil) {
	    resolve_list(supertypes_, r);
	}
	info_->has_body = true;
	s->interface(this);
	r->push_context(s);
	info_->block = r->enter_scope(ident_);
	if (defs_ != nil) {
	    resolve_list(defs_, r);
	}
	r->leave_scope();
	r->pop_context();
    }
}

void Accessor::resolve(Resolver* r) {
    Symbol* sym;
    r->push_context();
    qualifier_->resolve(r);
    sym = r->context()->out_symbol;
    r->pop_context();
    if (sym != nil) {
	Scope* s = sym->inner_scope();
	if (s == nil) {
	    r->error(this, "Accessor is not a scope");
	} else {
	    symbol_ = r->symbol_table()->resolve_in_scope(s, string_);
	    if (symbol_ == nil) {
		r->undefined(this, string_);
	    } else {
		r->symbol(symbol_);
	    }
	}
    }
}

/*
 * Still need to check here that the constant's value is appropriate
 * for the declared type.
 */

void Constant::resolve(Resolver* r) {
    Symbol* s = r->new_symbol(ident_);
    s->constant(this);
    symbol_ = s;
    type_->resolve(r);
    value_->resolve(r);
}

void Unary::resolve(Resolver* r) {
    expr_->resolve(r);
}

void Binary::resolve(Resolver* r) {
    left_->resolve(r);
    right_->resolve(r);
}

void TypeName::resolve(Resolver* r) {
    Symbol* s = new Symbol(r->scope());
    s->typename(this);
    r->push_context(s);
    type_->resolve(r);
    Context* c = r->context();
    symbol_ = c->out_symbol;
    c->in_symbol = s;
    c->type_expr = type_;
    resolve_list(declarators_, r);
    r->pop_context();
    seq_ = false;
    if (symbol_ != nil && symbol_->tag() == Symbol::sym_sequence &&
	declarators_->count() == 1
    ) {
	Expr* d = declarators_->item(0);
	/* make sure declarator isn't array */
	s = d->symbol();
	if (s != nil && s->tag() == Symbol::sym_typedef) {
	    symbol_->sequence_type()->name(d);
	    seq_ = true;
	}
    }
}

void UnsignedType::resolve(Resolver* r) {
    r->push_context();
    type_->resolve(r);
    Symbol* type = r->context()->out_symbol;
    SymbolTable* t = r->symbol_table();
    if (type == t->short_type()) {
	symbol_ = t->ushort_type();
    } else if (type == t->long_type()) {
	symbol_ = t->ulong_type();
    } else if (type == t->longlong_type()) {
	symbol_ = t->ulonglong_type();
    } else {
	r->error(type_, "Bad type for unsigned");
    }
    r->symbol(symbol_);
    r->pop_context();
}

void Declarator::resolve(Resolver* r) {
    Context* c = r->context();
    if (c == nil) {
	r->handler()->internal("no context for declarator");
    }
    Symbol* s = r->new_symbol(ident_);
    symbol_ = s;
    element_type_ = c->type_expr;
    if (subscripts_ == nil) {
	s->copy_value(c->in_symbol);
    } else {
	s->array(this);
	r->symbol(s);
    }
}

void StructDecl::resolve(Resolver* r) {
    Symbol* s = r->new_symbol(ident_);
    symbol_ = s;
    s->struct_tag(this);
    block_ = r->enter_scope(ident_);
    resolve_list(members_, r);
    r->leave_scope();
    r->symbol(s);
}

void StructMember::resolve(Resolver* r) {
    type_->resolve(r);
    Symbol* s = new Symbol(r->scope());
    s->struct_member(this);
    symbol_ = s;
    r->push_context(s, type_);
    resolve_list(declarators_, r);
    r->pop_context();
}

void UnionDecl::resolve(Resolver* r) {
    Symbol* s = r->new_symbol(ident_);
    symbol_ = s;
    switch_type_ = switch_type(r);
    if (switch_type_ != nil) {
	case_table_ = new CaseTable(20);
	default_label_ = nil;
	s->union_tag(this);
	r->push_context(s);
	/*
	 * Create two scopes because generated C++ has extra scope:
	 *	struct { ... union { ... } }
	 */
	r->enter_scope(ident_);
	block_ = r->symbol_table()->enter_scope(new String("_U"));
	for (ListItr(CaseList) c(*cases_); c.more(); c.next()) {
	    c.cur()->resolve(r);
	}
	r->leave_scope();
	r->leave_scope();
	r->symbol(s);
	r->pop_context();
	check_cases(r);
	delete case_table_;
	case_table_ = nil;
    }
}

Symbol* UnionDecl::switch_type(Resolver* r) {
    r->push_context();
    type_->resolve(r);
    Symbol* type_sym = r->context()->out_symbol;
    r->pop_context();
    if (type_sym == nil) {
	return nil;
    }
    SymbolTable* t = r->symbol_table();
    if (type_sym != t->long_type() && type_sym != t->short_type() &&
	type_sym != t->ulong_type() && type_sym != t->ushort_type() &&
	type_sym != t->char_type() && type_sym != t->boolean_type() &&
	type_sym->enum_tag() == nil
    ) {
	r->error(type_, "Bad switch type for union");
	return nil;
    }
    return type_sym;
}

void UnionDecl::check_cases(Resolver* r) {
    unsigned long count = default_label_ ? 1 : 0;
    for (TableIterator(CaseTable) i(*case_table_); i.more(); i.next()) {
	++count;
    }
    unsigned long max = ~0; // long or unsigned long
    SymbolTable* t = r->symbol_table();
    if (switch_type_ == t->boolean_type()) {
	max = 2;
    } else if (switch_type_ == t->short_type() ||
	switch_type_ == t->ushort_type()
    ) {
	max = 1 << 16;
    } else if (switch_type_ == t->char_type()) {
	max = 1 << 8;
    } else {
	EnumDecl* enum_decl = switch_type_->enum_tag();
	if (enum_decl != nil) {
	    max = enum_decl->enums();
	}
    }
    if (count > max) {
	r->error(type_, "Maximum number of case labels exceeded");
    }
}

void CaseElement::resolve(Resolver* r) {
    resolve_list(labels_, r);
    r->push_context();
    element_->resolve(r);
    symbol_ = r->context()->out_symbol;
    r->pop_context();
}

void CaseLabel::resolve(Resolver* r) {
    value_->resolve(r);
}

void DefaultLabel::resolve(Resolver* r) {
    Context* context = r->context();
    if (context != nil && context->in_symbol != nil) {
	UnionDecl* union_decl = context->in_symbol->union_tag();
	if (union_decl != nil) {
	    if (!union_decl->default_label()) {
		union_decl->default_label(this);
	    } else {
		r->error(this, "Multiple default labels in switch");
	    }
	} else {
	    r->error(this, "Default label is not inside union");
	}
    }
}

void EnumDecl::resolve(Resolver* r) {
    Symbol* s = r->new_symbol(ident_);
    symbol_ = s;
    s->enum_tag(this);
    r->push_context(s);
    enums_ = 0;
    resolve_list(members_, r);
    r->pop_context();
}

void Enumerator::resolve(Resolver* r) {
    Symbol* s = r->new_symbol(ident_);
    symbol_ = s;
    s->enum_value_tag(this);
    EnumDecl* enum_decl = r->context()->in_symbol->enum_tag();
    decl_ = enum_decl;
    value_ = enum_decl->assign_value();
}

void SequenceDecl::resolve(Resolver* r) {
    type_->resolve(r);
    if (length_ != nil) {
	/* should check that the length expr evaluates to a constant */
	length_->resolve(r);
    }
    Scope* block = r->scope();
    Symbol* s = new Symbol(block);
    s->sequence_type(this);
    r->symbol(s);
    symbol_ = s;
    id_ = block->id + 1;
    block->id = id_;
}

void StringDecl::resolve(Resolver* r) {
    Symbol* s;
    if (length_ == nil) {
	s = r->symbol_table()->string_type();
    } else {
	/* should check that the length expr evaluates to a constant */
	length_->resolve(r);
	s = new Symbol(r->scope());
	s->string_type(this);
    }
    r->symbol(s);
    symbol_ = s;
}

void ExceptDecl::resolve(Resolver* r) {
    StructDecl::resolve(r);
    symbol_->except_type(this);
    Scope* s = r->scope();
    s->except_index += 1;
    index_ = s->except_index;
}

void Operation::resolve(Resolver* r) {
    Symbol* s = r->new_symbol(ident_);
    s->operation(this);
    compute_index(r);
    r->push_context();
    type_->resolve(r);
    r->pop_context();
    symbol_ = s;
    if (params_ != nil) {
	block_ = r->enter_scope(ident_);
	resolve_list(params_, r);
	r->leave_scope();
    }
    if (exceptions_ != nil) {
	r->push_context(s);
	resolve_list(exceptions_, r);
	r->pop_context();
    }
    if (attributes_ != nil) {
	/*
	 * Right now, the only way the attributes list can be non-nil
	 * is if oneway was specified.
	 */
	oneway_ = true;
	check_oneway(r);
    }
    compute_indirect();
}

void AttrOp::resolve(Resolver* r) {
    if (params_ == nil) {
	/* get operation */
	Operation::resolve(r);
    } else {
	/* set operation -- don't rebind identifier */
	symbol_ = new Symbol(r->scope());
	compute_index(r);
	r->push_context();
	type_->resolve(r);
	r->pop_context();
	block_ = r->enter_scope(ident_);
	resolve_list(params_, r);
	r->leave_scope();
	compute_indirect();
    }
    symbol_->attribute(this);
}

/*
 * Check to make sure that an operation specified as oneway
 * doesn't try to return anything.
 */

void Operation::check_oneway(Resolver* r) {
    SymbolTable* t = r->symbol_table();
    if (type_->symbol() != t->void_type()) {
	r->error(this, "Return value must be \"void\" for oneway operation");
    } else if (params_ != nil) {
	for (ListItr(ExprList) e(*params_); e.more(); e.next()) {
	    Parameter* p = e.cur()->symbol()->parameter();
	    /* valid params_ => p != nil */
	    if (p->attr() != ExprKit::in_param) {
		ErrorHandler* err = r->handler();
		set_source_position(err);
		err->begin_error();
		err->put_chars("Parameter \"");
		err->put_string(*p->declarator()->ident()->string());
		err->put_chars("\" must be passed \"in\" to oneway operation");
		err->end();
	    }
	}
    }
}

void Operation::compute_index(Resolver* r) {
    interface_ = r->context()->in_symbol->interface();
    InterfaceInfo* i = interface_->info();
    index_ = i->op_index;
    i->op_index += 1;
}

/*
 * Figure out if the operation needs an indirect form and if so,
 * whether it can be inlined.  The issue is whether the operation
 * returns an object reference or has an inout/out parameter
 * that is an object reference.  The indirect operation can be inlined
 * if all the return/inout/out object reference types have been defined.
 */

void Operation::compute_indirect() {
    need_indirect_ = false;
    rtn_indirect_ = false;
    inline_indirect_ = true;
    Symbol* t = type_->symbol();
    if (t != nil) {
	t = t->actual_type();
	rtn_indirect_ = t != nil && t->tag() == Symbol::sym_interface;
	if (rtn_indirect_) {
	    need_indirect_ = true;
	    inline_indirect_ = t->interface()->info()->has_body;
	}
	if (params_ != nil && (!need_indirect_ || inline_indirect_)) {
	    for (ListItr(ExprList) e(*params_); e.more(); e.next()) {
		Parameter* p = e.cur()->symbol()->parameter();
		/* valid params_ => p != nil */
		if (p->attr() != ExprKit::in_param) {
		    Symbol* pt = p->type()->symbol();
		    if (pt != nil) {
			pt = pt->actual_type();
			if (pt != nil && pt->tag() == Symbol::sym_interface) {
			    need_indirect_ = true;
			    if (!pt->interface()->info()->has_body) {
				inline_indirect_ = false;
				break;
			    }
			}
		    }
		}
	    }
	}
    }
}

/*
 * Always generate indirect ops for attributes with object types
 * because of C++ overloading rules.
 */

void AttrOp::compute_indirect() {
    need_indirect_ = false;
    rtn_indirect_ = false;
    inline_indirect_ = true;
    Expr* t = (params_ == nil) ? type_ : params_->item(0);
    Symbol* s = t->symbol();
    if (s != nil) {
	s = s->actual_type();
	if (s != nil) {
	    InterfaceDef* i = s->interface();
	    if (i != nil) {
		need_indirect_ = true;
		rtn_indirect_ = params_ == nil;
		inline_indirect_ = i->info()->has_body;
	    }
	}
    }
}

void Parameter::resolve(Resolver* r) {
    if (attr_ == ExprKit::err_param) {
	r->error(this, "Missing attribute for parameter");
    }
    r->push_context();
    type_->resolve(r);
    Symbol* s = r->context()->out_symbol;
    r->pop_context();
    if (declarator_ == nil) {
	r->error(this, "Missing parameter name");
    } else {
	symbol_ = new Symbol(r->scope());
	symbol_->parameter(this);
	r->push_context(s, type_);
	declarator_->resolve(r);
	r->pop_context();
    }
}

void IdentifierImpl::resolve(Resolver* r) {
    symbol_ = r->resolve(this);
    if (symbol_ == nil) {
	r->undefined(this, value_);
    } else {
	Context* c = r->context();
	if (c != nil) {
	    Symbol* s = c->in_symbol;
	    if (s != nil) {
		Symbol::Tag t = symbol_->tag();
		switch (s->tag()) {
		case Symbol::sym_union:
		    if (t == Symbol::sym_enum_value) {
			check(r, s->union_tag(), symbol_->enum_value_tag());
		    }
		    break;
		case Symbol::sym_operation:
		    /*
		     * Assume we are resolving the raises clause
		     * of an operation.
		     */
		    if (t != Symbol::sym_exception) {
			r->symerr(this, value_, "is not an exception");
		    }
		    break;
		}
	    }
	}
    }
    r->symbol(symbol_);
}

void IdentifierImpl::check(
    Resolver* r, UnionDecl* union_decl, Enumerator* enumerator
) {
    EnumDecl* enum_decl = union_decl->switch_type()->enum_tag();
    if (enum_decl != nil && enum_decl != enumerator->decl()) {
	r->error(this, "Enumerator not declared in enumeration");
	return;
    }
    long value = enumerator->value();
    CaseTable* cases = union_decl->cases();
    long existing;
    if (cases->find(existing, value)) {
	r->error(this, "Case label not unique in union");
    } else {
	cases->insert(value, value);
    }
}

void BooleanLiteral::resolve(Resolver* r) {
    Context* context = r->context();
    if (context != nil && context->in_symbol != nil) {
	UnionDecl* union_decl = context->in_symbol->union_tag();
	if (union_decl != nil) {
	    if (union_decl->switch_type() !=
		r->symbol_table()->boolean_type()
	    ) {
		r->error(this, "Boolean case label not in boolean switch");
	    } else {
		CaseTable* cases = union_decl->cases();
		long existing;
		if (cases->find(existing, value_)) {
		    r->error(this, "Case label not unique in union");
		} else {
		    cases->insert(value_, value_);
		}
	    }
	}
    }
}

void IntegerLiteral::resolve(Resolver* r) {
    Context* context = r->context();
    if (context && context->in_symbol) {
	UnionDecl* union_decl = context->in_symbol->union_tag();
	if (union_decl != nil) {
	    check(r, union_decl->switch_type());
	    CaseTable* cases = union_decl->cases();
	    long existing;
	    if (cases->find(existing, value_)) {
		r->error(this, "Case label not unique in union");
	    } else {
		cases->insert(value_, value_);
	    }
	}
    }
}

void IntegerLiteral::check(Resolver* r, Symbol* switch_type) {
    long max, min;
    Boolean check_range = false;
    SymbolTable* t = r->symbol_table();
    if (switch_type == t->short_type()) {
	min = -(1 << 15);
	max = (1 << 15) - 1;
	check_range = true;
    } else if (switch_type == t->ushort_type()) {
	min = 0;
	max = (1 << 16) - 1;
	check_range = true;
    } else if (switch_type == t->boolean_type()) {
	r->error(this, "Boolean switch cannot take integer cases");
    } else if (switch_type == t->char_type()) {
	r->error(this, "Char switch cannot take integer cases");
    }
    if (check_range && (value_ < min || value_ > max)) {
	r->error(this, "Case label value out of range for switch type");
    }
}

void FloatLiteral::resolve(Resolver* r) {
    Context* context = r->context();
    if (context != nil && context->in_symbol != nil) {
	UnionDecl* union_decl = context->in_symbol->union_tag();
	if (union_decl != nil) {
	    r->error(this, "Float literal as case label");
	}
    }
}

void StringLiteral::resolve(Resolver* r) {
    Context* context = r->context();
    if (context != nil && context->in_symbol != nil) {
	UnionDecl* union_decl = context->in_symbol->union_tag();
	if (union_decl != nil) {
	    r->error(this, "String literal as case label");
	}
    }
}

void CharLiteral::resolve(Resolver* r) {
    Context* context = r->context();
    if (context != nil && context->in_symbol != nil) {
	UnionDecl* union_decl = context->in_symbol->union_tag();
	if (union_decl != nil) {
	    if (union_decl->switch_type() != r->symbol_table()->char_type()) {
		r->error(this, "Character literal not in char switch type");
		return;
	    }
	    CaseTable* cases = union_decl->cases();
	    long existing;
	    if (cases->find(existing, value_)) {
		r->error(this, "Case label not unique in union");
	    } else {
		cases->insert(value_, value_);
	    }
	}
    }
}

void SrcPos::resolve(Resolver*) { }

/* class SymbolTable */

SymbolTable::SymbolTable() {
    map_ = new SymbolMap(500);
    scope_ = nil;
}

SymbolTable::~SymbolTable() {
    for (Table2Iterator(SymbolMap) i(*map_); i.more(); i.next()) {
	Symbol* s = i.cur_value();
	delete s;
    }
    delete map_;
}

Scope* SymbolTable::enter_scope(String* name) {
    Scope* s = new Scope;
    s->name = name;
    s->outer = scope_;
    s->id = 0;
    s->except_index = 0;
    scope_ = s;
    return s;
}

Scope* SymbolTable::scope() { return scope_; }

void SymbolTable::leave_scope() {
    Scope* s = scope_;
    if (s != nil) {
	scope_ = s->outer;
    }
}

void SymbolTable::bind(IdentString* str, Symbol* sym) {
    bind_in_scope(scope_, str, sym);
}

void SymbolTable::bind_in_scope(Scope* s, IdentString* str, Symbol* sym) {
    sym->scope(s);
    map_->insert(s, *str, sym);
}

Symbol* SymbolTable::resolve(IdentString* str) {
    return resolve_in_scope(scope_, str);
}

Symbol* SymbolTable::resolve_in_scope(Scope* s, IdentString* str) {
    Symbol* sym;
    for (Scope* b = s; b != nil; b = b->outer) {
	if (map_->find(sym, b, *str)) {
	    return sym;
	}
    }
    return nil;
}

/* class Symbol */

Symbol::Symbol(Scope* s) {
    tag_ = sym_unknown;
    scope_ = s;
    declared_ = false;
    declared_stub_ = 0;
    value_.interface_ = nil;
}

Symbol::Symbol(const Symbol& s) {
    tag_ = s.tag_;
    scope_ = s.scope_;
    declared_ = false;
    value_.interface_ = s.value_.interface_;
}

Symbol::~Symbol() { }

void Symbol::scope(Scope* s) { scope_ = s; }

Scope* Symbol::inner_scope() {
    switch (tag_) {
    case sym_module:
	return value_.module_->block();
    case sym_interface:
	return value_.interface_->block();
    }
    return nil;
}

Symbol* Symbol::actual_type() {
    Symbol* s = this;
    for (;;) {
	Expr* t;
	switch (s->tag_) {
	case Symbol::sym_typedef:
	    t = s->typename();
	    break;
	case Symbol::sym_member:
	    t = s->struct_member()->type();
	    break;
	case Symbol::sym_union_member:
	    t = s->union_member()->type();
	    break;
	case Symbol::sym_parameter:
	    t = s->parameter()->type();
	    break;
	default:
	    t = nil;
	    break;
	}
	if (t == nil) {
	    break;
	}
	Symbol* ns = t->symbol();
	if (ns == nil) {
	    break;
	}
	s = ns;
    }
    return s;
}

void Symbol::copy_value(Symbol* s) {
    if (s != nil) {
	tag_ = s->tag_;
	scope_ = s->scope_;
	value_ = s->value_;
    }
}

void Symbol::module(Module* m) {
    tag_ = sym_module;
    value_.module_ = m;
}

Module* Symbol::module() {
    return tag_ == sym_module ? value_.module_ : nil;
}

void Symbol::interface(InterfaceDef* i) {
    tag_ = sym_interface;
    value_.interface_ = i;
}

InterfaceDef* Symbol::interface() {
    return tag_ == sym_interface ? value_.interface_ : nil;
}

void Symbol::typename(TypeName* t) {
    tag_ = sym_typedef;
    value_.type_ = t;
}

TypeName* Symbol::typename() {
    return tag_ == sym_typedef ? value_.type_ : nil;
}

void Symbol::constant(Constant* c) {
    tag_ = sym_constant;
    value_.constant_ = c;
}

Constant* Symbol::constant() {
    return tag_ == sym_constant ? value_.constant_ : nil;
}

void Symbol::operation(Operation* o) {
    tag_ = sym_operation;
    value_.operation_ = o;
}

Operation* Symbol::operation() {
    return tag_ == sym_operation ? value_.operation_ : nil;
}

void Symbol::parameter(Parameter* p) {
    tag_ = sym_parameter;
    value_.parameter_ = p;
}

Parameter* Symbol::parameter() {
    return tag_ == sym_parameter ? value_.parameter_ : nil;
}

void Symbol::attribute(AttrOp* a) {
    tag_ = sym_attribute;
    value_.attribute_ = a;
}

AttrOp* Symbol::attribute() {
    return tag_ == sym_attribute ? value_.attribute_ : nil;
}

void Symbol::array(Declarator* d) {
    tag_ = sym_array;
    value_.array_ = d;
}

Declarator* Symbol::array() {
    return tag_ == sym_array ? value_.array_ : nil;
}

void Symbol::struct_tag(StructDecl* s) {
    tag_ = sym_struct;
    value_.struct_tag_ = s;
}

StructDecl* Symbol::struct_tag() {
    return tag_ == sym_struct ? value_.struct_tag_ : nil;
}

void Symbol::struct_member(StructMember* m) {
    tag_ = sym_member;
    value_.struct_member_ = m;
}

StructMember* Symbol::struct_member() {
    return tag_ == sym_member ? value_.struct_member_ : nil;
}

void Symbol::union_tag(UnionDecl* u) {
    tag_ = sym_union;
    value_.union_tag_ = u;
}

UnionDecl* Symbol::union_tag() {
    return tag_ == sym_union ? value_.union_tag_ : nil;
}

void Symbol::union_member(UnionMember* m) {
    tag_ = sym_union_member;
    value_.union_member_ = m;
}

UnionMember* Symbol::union_member() {
    return tag_ == sym_union_member ? value_.union_member_ : nil;
}

void Symbol::enum_tag(EnumDecl* e) {
    tag_ = sym_enum;
    value_.enum_tag_ = e;
}

EnumDecl* Symbol::enum_tag() {
    return tag_ == sym_enum ? value_.enum_tag_ : nil;
}

void Symbol::enum_value_tag(Enumerator* e) {
    tag_ = sym_enum_value;
    value_.enum_value_tag_ = e;
}

Enumerator* Symbol::enum_value_tag() {
    return tag_ == sym_enum_value ? value_.enum_value_tag_ : nil;
}

void Symbol::except_type(ExceptDecl* e) {
    tag_ = sym_exception;
    value_.except_type_ = e;
}

ExceptDecl* Symbol::except_type() {
    return tag_ == sym_exception ? value_.except_type_ : nil;
}

void Symbol::sequence_type(SequenceDecl* s) {
    tag_ = sym_sequence;
    value_.sequence_type_ = s;
}

SequenceDecl* Symbol::sequence_type() {
    return tag_ == sym_sequence ? value_.sequence_type_ : nil;
}

void Symbol::string_type(StringDecl* s) {
    tag_ = sym_string;
    value_.string_type_ = s;
}

StringDecl* Symbol::string_type() {
    return tag_ == sym_string ? value_.string_type_ : nil;
}