// $Id: Expr.cc,v 1.82 2003/08/31 00:38:11 vern Exp $
//
// Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
//      The Regents of the University of California.  All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that: (1) source code distributions
// retain the above copyright notice and this paragraph in its entirety, (2)
// distributions including binary code include the above copyright notice and
// this paragraph in its entirety in the documentation or other materials
// provided with the distribution, and (3) all advertising materials mentioning
// features or use of this software display the following acknowledgement:
// ``This product includes software developed by the University of California,
// Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
// the University nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

#include "config.h"

#include "Expr.h"
#include "Event.h"
#include "Frame.h"
#include "Func.h"
#include "RE.h"
#include "Stmt.h"
#include "EventRegistry.h"

const char* expr_name(BroExprTag t)
	{
	static const char* expr_names[int(NUM_EXPRS)] = {
		"name", "const",
		"++", "--", "!", "+", "-",
		"+", "-", "*", "/", "%", "&&", "||",
		"<", "<=", "==", "!=", ">=", ">", "?:", "ref",
		"=", "~", "[]", "$", "?$", "[=]", "$=", "in", "<<>>",
		"()", "schedule", "coerce", "flatten"
	};

	return expr_names[int(t)];
	}

Expr::Expr(BroExprTag arg_tag)
	{
	tag = arg_tag;
	type = 0;
	paren = 0;

	SetLocationInfo(&start_location, &end_location);
	}

Expr::~Expr()
	{
	Unref(type);
	}

int Expr::CanAdd() const
	{
	return 0;
	}

int Expr::CanDel() const
	{
	return 0;
	}

void Expr::Add(Frame* /* f */)
	{
	Internal("Expr::Delete called");
	}

void Expr::Delete(Frame* /* f */)
	{
	Internal("Expr::Delete called");
	}

Expr* Expr::MakeLvalue()
	{
	if ( ! IsError() )
		ExprError("can't be assigned to");
	return this;
	}

void Expr::Assign(Frame* /* f */, Val* /* v */)
	{
	Internal("Expr::Assign called");
	}

BroType* Expr::InitType() const
	{
	return type->Ref();
	}

int Expr::IsRecordElement(TypeDecl* /* td */) const
	{
	return 0;
	}

int Expr::IsPure() const
	{
	return 1;
	}

Val* Expr::InitVal(const BroType* t, Val* aggr) const
	{
	if ( aggr )
		{
		Error("bad initializer");
		return 0;
		}

	if ( IsError() )
		return 0;

	return check_and_promote(Eval(0), t, 1);
	}

void Expr::SetError(const char* msg)
	{
	Error(msg);
	SetError();
	}

void Expr::Describe(ODesc* d) const
	{
	if ( IsParen() && ! d->IsBinary() )
		d->Add("(");

	if ( d->IsPortable() || d->IsBinary() )
		AddTag(d);

	ExprDescribe(d);

	if ( IsParen() && ! d->IsBinary() )
		d->Add(")");
	}

void Expr::AddTag(ODesc* d) const
	{
	if ( d->IsBinary() )
		d->Add(int(Tag()));
	else
		d->AddSP(expr_name(Tag()));
	}

void Expr::Canonicize()
	{
	}

void Expr::ExprError(const char msg[])
	{
	Error(msg);
	SetError();
	}

NameExpr::NameExpr(ID* arg_id) : Expr(EXPR_NAME)
	{
	id = arg_id;
	SetType(id->Type()->Ref());
	}

NameExpr::~NameExpr()
	{
	Unref(id);
	}

Expr* NameExpr::Simplify(SimplifyType simp_type)
	{
	if ( simp_type != SIMPLIFY_LHS && id->IsConst() )
		{
		Val* v = Eval(0);
		if ( v )
			return new ConstExpr(v);
		}

	return this;
	}

Val* NameExpr::Eval(Frame* f) const
	{
	Val* v;

	if ( id->AsType() )
		RunTime("cannot evaluate type name");

	if ( id->IsGlobal() )
		v = id->ID_Val();

	else if ( f )
		v = f->NthElement(id->Offset());

	else
		// No frame - evaluating for Simplify() purposes
		return 0;

	if ( v )
		return v->Ref();
	else
		{
		RunTime("value used but not set");
		return 0;
		}
	}

Expr* NameExpr::MakeLvalue()
	{
	if ( id->AsType() )
		ExprError("Type name is not an lvalue");

	return new RefExpr(this);
	}

void NameExpr::Assign(Frame* f, Val* v)
	{
	if ( id->IsGlobal() )
		id->SetVal(v);
	else
		f->SetElement(id->Offset(), v);
	}

int NameExpr::IsPure() const
	{
	return id->IsConst();
	}

void NameExpr::ExprDescribe(ODesc* d) const
	{
	if ( d->IsReadable() )
		d->Add(id->Name());
	else
		{
		if ( d->IsPortable() )
			d->Add(id->Name());
		else
			d->AddCS(id->Name());
		}
	}

ConstExpr::ConstExpr(Val* arg_val) : Expr(EXPR_CONST)
	{
	val = arg_val;

	if ( val->Type()->Tag() == TYPE_LIST && val->AsListVal()->Length() == 1 )
		{
		val = val->AsListVal()->Index(0);
		val->Ref();
		Unref(arg_val);
		}

	SetType(val->Type()->Ref());
	}

ConstExpr::~ConstExpr()
	{
	Unref(val);
	}

void ConstExpr::ExprDescribe(ODesc* d) const
	{
	val->Describe(d);
	}

Expr* ConstExpr::Simplify(SimplifyType /* simp_type */)
	{
	return this;
	}

Val* ConstExpr::Eval(Frame* /* f */) const
	{
	return Value()->Ref();
	}

UnaryExpr::~UnaryExpr()
	{
	Unref(op);
	}

Expr* UnaryExpr::Simplify(SimplifyType simp_type)
	{
	if ( IsError() )
		return this;

	op = simplify_expr(op, simp_type);
	Canonicize();
	return DoSimplify();
	}

Val* UnaryExpr::Eval(Frame* f) const
	{
	if ( IsError() )
		return 0;

	Val* v = op->Eval(f);

	if ( v )
		{
		Val* result = Fold(v);
		Unref(v);
		return result;
		}
	else
		return 0;
	}

int UnaryExpr::IsPure() const
	{
	return op->IsPure();
	}

Expr* UnaryExpr::DoSimplify()
	{
	return this;
	}

Val* UnaryExpr::Fold(Val* /* v */) const
	{
	return 0;
	}

void UnaryExpr::ExprDescribe(ODesc* d) const
	{
	if ( d->IsReadable() )
		{
		if ( Tag() == EXPR_COERCE )
			d->Add("(coerce ");
		else if ( Tag() == EXPR_FLATTEN )
			d->Add("flatten ");
		else if ( Tag() != EXPR_REF )
			d->Add(expr_name(Tag()));
		}

	op->Describe(d);

	if ( d->IsReadable() && Tag() == EXPR_COERCE )
		{
		d->Add(" to ");
		Type()->Describe(d);
		d->Add(")");
		}
	}

BinaryExpr::~BinaryExpr()
	{
	Unref(op1);
	Unref(op2);
	}

Expr* BinaryExpr::Simplify(SimplifyType /* simp_type */)
	{
	if ( IsError() )
		return this;

	SimplifyOps();

	if ( BothConst() )
		return new ConstExpr(Fold(op1->ExprVal(), op2->ExprVal()));
	else
		return DoSimplify();
	}

Val* BinaryExpr::Eval(Frame* f) const
	{
	if ( IsError() )
		return 0;

	Val* v1 = op1->Eval(f);
	Val* v2 = op2->Eval(f);

	Val* result = 0;
	if ( v1 && v2 )
		result = Fold(v1, v2);

	Unref(v1);
	Unref(v2);
	return result;
	}

int BinaryExpr::IsPure() const
	{
	return op1->IsPure() && op2->IsPure();
	}

Expr* BinaryExpr::DoSimplify()
	{
	return this;
	}

void BinaryExpr::ExprDescribe(ODesc* d) const
	{
	op1->Describe(d);

	d->SP();
	if ( d->IsReadable() )
		d->AddSP(expr_name(Tag()));

	op2->Describe(d);
	}

void BinaryExpr::SimplifyOps()
	{
	op1 = simplify_expr(op1, SIMPLIFY_GENERAL);
	op2 = simplify_expr(op2, SIMPLIFY_GENERAL);
	Canonicize();
	}

Val* BinaryExpr::Fold(Val* v1, Val* v2) const
	{
	InternalTypeTag it = op1->Type()->InternalType();

	if ( it == TYPE_INTERNAL_STRING )
		return StringFold(v1, v2);

	if ( it == TYPE_INTERNAL_ADDR )
		return AddrFold(v1, v2);

	int i1 = 0, i2 = 0, i3 = 0;
	uint32 u1 = 0, u2 = 0, u3 = 0;
	double d1 = 0.0, d2 = 0.0, d3 = 0.0;
	int is_integral = 0;
	int is_unsigned = 0;

	if ( it == TYPE_INTERNAL_INT )
		{
		i1 = v1->InternalInt();
		i2 = v2->InternalInt();
		++is_integral;
		}
	else if ( it == TYPE_INTERNAL_UNSIGNED )
		{
		u1 = v1->InternalUnsigned();
		u2 = v2->InternalUnsigned();
		++is_unsigned;
		}
	else if ( it == TYPE_INTERNAL_DOUBLE )
		{
		d1 = v1->InternalDouble();
		d2 = v2->InternalDouble();
		}
	else
		Internal("bad type in BinaryExpr::Fold");

	switch ( tag ) {
#define DO_INT_FOLD(op) \
	if ( is_integral ) \
		i3 = i1 op i2; \
	else if ( is_unsigned ) \
		u3 = u1 op u2; \
	else \
		Internal("bad type in BinaryExpr::Fold"); \
	break;

#define DO_FOLD(op) \
	if ( is_integral ) \
		i3 = i1 op i2; \
	else if ( is_unsigned ) \
		u3 = u1 op u2; \
	else \
		d3 = d1 op d2; \
	break;

#define DO_INT_VAL_FOLD(op) \
	if ( is_integral ) \
		i3 = i1 op i2; \
	else if ( is_unsigned ) \
		i3 = u1 op u2; \
	else \
		i3 = d1 op d2; \
	break;

	case EXPR_ADD:		DO_FOLD(+)
	case EXPR_SUB:		DO_FOLD(-)
	case EXPR_TIMES:	DO_FOLD(*)
	case EXPR_DIVIDE:	DO_FOLD(/)

	case EXPR_MOD:		DO_INT_FOLD(%)
	case EXPR_AND:		DO_INT_FOLD(&&)
	case EXPR_OR:		DO_INT_FOLD(||)

	case EXPR_LT:		DO_INT_VAL_FOLD(<)
	case EXPR_LE:		DO_INT_VAL_FOLD(<=)
	case EXPR_EQ:		DO_INT_VAL_FOLD(==)
	case EXPR_NE:		DO_INT_VAL_FOLD(!=)
	case EXPR_GE:		DO_INT_VAL_FOLD(>=)
	case EXPR_GT:		DO_INT_VAL_FOLD(>)

	default:
		BadTag("BinaryExpr::Fold");
	}

	if ( type->Tag() == TYPE_INTERVAL )
		return new IntervalVal(d3, 1.0);
	else if ( type->InternalType() == TYPE_INTERNAL_DOUBLE )
		return new Val(d3, type->Tag());
	else if ( type->InternalType() == TYPE_INTERNAL_UNSIGNED )
		return new Val(u3, type->Tag());
	else
		return new Val(i3, type->Tag());
	}

Val* BinaryExpr::StringFold(Val* v1, Val* v2) const
	{
	BroString* s1 = v1->AsString();
	BroString* s2 = v2->AsString();
	int result = 0;

	switch ( tag ) {
#undef DO_FOLD
#define DO_FOLD(sense) { result = Bstr_cmp(s1, s2) sense 0; break; }

	case EXPR_LT:		DO_FOLD(<)
	case EXPR_LE:		DO_FOLD(<=)
	case EXPR_EQ:		DO_FOLD(==)
	case EXPR_NE:		DO_FOLD(!=)
	case EXPR_GE:		DO_FOLD(>=)
	case EXPR_GT:		DO_FOLD(>)

	default:
		BadTag("BinaryExpr::StringFold");
	}

	return new Val(result, TYPE_BOOL);
	}

Val* BinaryExpr::AddrFold(Val* v1, Val* v2) const
	{
	addr_type a1 = v1->AsAddr();
	addr_type a2 = v2->AsAddr();
	int result = 0;

	switch ( tag ) {
#undef DO_FOLD
#ifdef BROv6
#define DO_FOLD(sense) { result = memcmp(a1, a2, 16) sense 0; break; }
#else
#define DO_FOLD(sense)	\
	{ \
	a1 = ntohl(a1); \
	a2 = ntohl(a2); \
	result = (a1 < a2 ? -1 : (a1 == a2 ? 0 : 1)) sense 0; \
	break; \
	}
#endif

	case EXPR_LT:		DO_FOLD(<)
	case EXPR_LE:		DO_FOLD(<=)
	case EXPR_EQ:		DO_FOLD(==)
	case EXPR_NE:		DO_FOLD(!=)
	case EXPR_GE:		DO_FOLD(>=)
	case EXPR_GT:		DO_FOLD(>)

	default:
		BadTag("BinaryExpr::AddrFold");
	}

	return new Val(result, TYPE_BOOL);
	}

void BinaryExpr::SwapOps()
	{
	// We could check here whether the operator is commutative.
	Expr* t = op1;
	op1 = op2;
	op2 = t;
	}

void BinaryExpr::PromoteOps(TypeTag t)
	{
	if ( op1->Type()->Tag() != t )
		op1 = new ArithCoerceExpr(op1, t);
	if ( op2->Type()->Tag() != t )
		op2 = new ArithCoerceExpr(op2, t);
	}

void BinaryExpr::PromoteType(TypeTag t)
	{
	PromoteOps(t);
	SetType(base_type(t));
	}

IncrExpr::IncrExpr(BroExprTag arg_tag, Expr* arg_op)
: UnaryExpr(arg_tag, arg_op->MakeLvalue())
	{
	if ( IsError() )
		return;

	BroType* t = op->Type();

	if ( ! IsIntegral(t->Tag()) )
		ExprError("requires an integral operand");
	else
		SetType(t->Ref());
	}

Val* IncrExpr::Eval(Frame* f) const
	{
	Val* v = op->Eval(f);
	if ( ! v )
		return 0;

	int k = v->CoerceToInt();
	Unref(v);

	if ( Tag() == EXPR_INCR )
		++k;
	else
		{
		--k;

		if ( k < 0 &&
		     v->Type()->InternalType() == TYPE_INTERNAL_UNSIGNED )
			RunTime("count underflow");
		}

	v = new Val(k, Type()->Tag());
	op->Assign(f, v);

	return v->Ref();
	}

int IncrExpr::IsPure() const
	{
	return 0;
	}

NotExpr::NotExpr(Expr* arg_op) : UnaryExpr(EXPR_NOT, arg_op)
	{
	if ( IsError() )
		return;

	BroType* t = op->Type();
	TypeTag bt = t->Tag();

	if ( ! IsIntegral(bt) && bt != TYPE_BOOL )
		ExprError("requires an integral or boolean operand");
	else
		SetType(base_type(TYPE_BOOL));
	}

Expr* NotExpr::DoSimplify()
	{
	op = simplify_expr(op, SIMPLIFY_GENERAL);
	Canonicize();

	if ( op->Tag() == EXPR_NOT )
		// !!x == x
		return ((NotExpr*) op)->Op()->Ref();

	if ( op->IsConst() )
		return new ConstExpr(Fold(op->ExprVal()));

	return this;
	}

Val* NotExpr::Fold(Val* v) const
	{
	return new Val(! v->InternalInt(), type->Tag());
	}

PosExpr::PosExpr(Expr* arg_op) : UnaryExpr(EXPR_POSITIVE, arg_op)
	{
	if ( IsError() )
		return;

	BroType* t = op->Type();
	TypeTag bt = t->Tag();

	if ( IsIntegral(bt) )
		// Promote count and counter to int.
		SetType(base_type(TYPE_INT));
	else if ( bt == TYPE_INTERVAL || bt == TYPE_DOUBLE )
		SetType(t->Ref());
	else
		ExprError("requires an integral or double operand");
	}

Expr* PosExpr::DoSimplify()
	{
	op = simplify_expr(op, SIMPLIFY_GENERAL);
	Canonicize();

	TypeTag t = op->Type()->Tag();

	if ( t == TYPE_DOUBLE || t == TYPE_INTERVAL || t == TYPE_INT )
		return op->Ref();

	if ( op->IsConst() )
		return new ConstExpr(Fold(op->ExprVal()));

	return this;
	}

Val* PosExpr::Fold(Val* v) const
	{
	TypeTag t = v->Type()->Tag();

	if ( t == TYPE_DOUBLE || t == TYPE_INTERVAL || t == TYPE_INT )
		return v->Ref();
	else
		return new Val(v->CoerceToInt(), type->Tag());
	}

NegExpr::NegExpr(Expr* arg_op) : UnaryExpr(EXPR_NEGATE, arg_op)
	{
	if ( IsError() )
		return;

	BroType* t = op->Type();
	TypeTag bt = t->Tag();

	if ( IsIntegral(bt) )
		SetType(base_type(TYPE_INT));
	else if ( bt == TYPE_INTERVAL || bt == TYPE_DOUBLE )
		SetType(t->Ref());
	else
		ExprError("requires an integral or double operand");
	}

Expr* NegExpr::DoSimplify()
	{
	op = simplify_expr(op, SIMPLIFY_GENERAL);
	Canonicize();

	if ( op->Tag() == EXPR_NEGATE )
		// -(-x) == x
		return ((NegExpr*) op)->Op()->Ref();

	if ( op->IsConst() )
		return new ConstExpr(Fold(op->ExprVal()));

	if ( op->Tag() == EXPR_SUB )
		{ // -(a-b) == b-a
		SubExpr* s = (SubExpr*) op;
		return new SubExpr(s->Op2()->Ref(), s->Op1()->Ref());
		}

	return this;
	}

Val* NegExpr::Fold(Val* v) const
	{
	if ( v->Type()->Tag() == TYPE_DOUBLE )
		return new Val(- v->InternalDouble(), type->Tag());
	else if ( v->Type()->Tag() == TYPE_INTERVAL )
		return new IntervalVal(- v->InternalDouble(), 1.0);
	else
		return new Val(- v->CoerceToInt(), type->Tag());
	}

AddExpr::AddExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_ADD, arg_op1, arg_op2)
	{
	if ( IsError() )
		return;

	Canonicize();

	TypeTag bt1 = op1->Type()->Tag();
	TypeTag bt2 = op2->Type()->Tag();

	if ( bt1 == TYPE_TIME && bt2 == TYPE_INTERVAL )
		SetType(base_type(bt1));
	else if ( bt2 == TYPE_TIME && bt1 == TYPE_INTERVAL )
		SetType(base_type(bt2));
	else if ( bt1 == TYPE_INTERVAL && bt2 == TYPE_INTERVAL )
		SetType(base_type(bt1));
	else if ( BothArithmetic(bt1, bt2) )
		PromoteType(max_type(bt1, bt2));
	else
		ExprError("requires arithmetic operands");
	}

Expr* AddExpr::DoSimplify()
	{
	// If there's a constant, then it's in op1, since Canonicize()
	// makes sure of that.
	if ( op1->IsZero() )
		return op2->Ref();

	else if ( op1->Tag() == EXPR_NEGATE )
		// (-a)+b = b-a
		return new AddExpr(op2->Ref(), ((NegExpr*) op1)->Op()->Ref());

	else if ( op2->Tag() == EXPR_NEGATE )
		// a+(-b) == a-b
		return new SubExpr(op1->Ref(), ((NegExpr*) op2)->Op()->Ref());

	return this;
	}

void AddExpr::Canonicize()
	{
	if ( expr_greater(op2, op1) ||
	     (op1->Type()->Tag() == TYPE_INTERVAL &&
	      op2->Type()->Tag() == TYPE_TIME) ||
	     (op2->IsConst() && ! op1->IsConst()) )
		SwapOps();
	}

SubExpr::SubExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_SUB, arg_op1, arg_op2)
	{
	if ( IsError() )
		return;

	TypeTag bt1 = op1->Type()->Tag();
	TypeTag bt2 = op2->Type()->Tag();

	if ( bt1 == TYPE_TIME && bt2 == TYPE_INTERVAL )
		SetType(base_type(bt1));
	else if ( bt1 == TYPE_INTERVAL && bt2 == TYPE_INTERVAL )
		SetType(base_type(bt1));
	else if ( bt1 == TYPE_TIME && bt2 == TYPE_TIME )
		SetType(base_type(TYPE_INTERVAL));
	else if ( BothArithmetic(bt1, bt2) )
		PromoteType(max_type(TYPE_INT,max_type(bt1, bt2)));
	else
		ExprError("requires arithmetic operands");
	}

Expr* SubExpr::DoSimplify()
	{
	if ( op1->IsZero() )
		return new NegExpr(op2->Ref());

	else if ( op2->IsZero() )
		return op1->Ref();

	else if ( op2->Tag() == EXPR_NEGATE )
		// a-(-b) = a+b
		return new AddExpr(op1->Ref(), ((NegExpr*) op2)->Op()->Ref());

	return this;
	}

TimesExpr::TimesExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_TIMES, arg_op1, arg_op2)
	{
	if ( IsError() )
		return;

	Canonicize();

	TypeTag bt1 = op1->Type()->Tag();
	TypeTag bt2 = op2->Type()->Tag();

	if ( bt1 == TYPE_INTERVAL || bt2 == TYPE_INTERVAL )
		{
		if ( IsArithmetic(bt1) || IsArithmetic(bt2) )
			PromoteType(TYPE_INTERVAL);
		else
			ExprError("multiplication with interval requires arithmetic operand");
		}
	else if ( BothArithmetic(bt1, bt2) )
		PromoteType(max_type(bt1, bt2));
	else
		ExprError("requires arithmetic operands");
	}

Expr* TimesExpr::DoSimplify()
	{
	// If there's a constant, then it's in op1, since Canonicize()
	// makes sure of that.
	if ( op1->IsConst() )
		{
		if ( op1->IsZero() )
			return make_zero(type);
		else if ( op1->IsOne() )
			return op2->Ref();
		}

	return this;
	}

void TimesExpr::Canonicize()
	{
	if ( expr_greater(op2, op1) || op2->Type()->Tag() == TYPE_INTERVAL ||
	     (op2->IsConst() && ! op1->IsConst()) )
		SwapOps();
	}

DivideExpr::DivideExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_DIVIDE, arg_op1, arg_op2)
	{
	if ( IsError() )
		return;

	TypeTag bt1 = op1->Type()->Tag();
	TypeTag bt2 = op2->Type()->Tag();

	if ( bt1 == TYPE_INTERVAL || bt2 == TYPE_INTERVAL )
		{
		if ( IsArithmetic(bt1) || IsArithmetic(bt2) )
			PromoteType(TYPE_INTERVAL);
		else if ( bt1 == TYPE_INTERVAL && bt2 == TYPE_INTERVAL )
			SetType(base_type(TYPE_DOUBLE));
		else
			ExprError("division of interval requires arithmetic operand");
		}

	else if ( BothArithmetic(bt1, bt2) )
		PromoteType(max_type(bt1, bt2));

	else if ( bt1 == TYPE_ADDR && (bt2 == TYPE_COUNT || bt2 == TYPE_INT) )
		SetType(base_type(TYPE_SUBNET));

	else
		ExprError("requires arithmetic operands");
	}

Val* DivideExpr::AddrFold(Val* v1, Val* v2) const
	{
	addr_type a1 = v1->AsAddr();

	int mask;
	if ( v2->Type()->Tag() == TYPE_COUNT )
		mask = int(v2->InternalUnsigned());
	else
		mask = v2->InternalInt();

	return new SubNetVal(a1, mask);
	}

Expr* DivideExpr::DoSimplify()
	{
	if ( IsError() )
		return this;

	if ( op1->Type()->Tag() == TYPE_ADDR )
		return this;

	if ( op2->IsConst() )
		{
		if ( op2->IsOne() )
			return op1->Ref();
		else if ( op2->IsZero() )
			Error("zero divisor");
		}

	else if ( same_expr(op1, op2) )
		return make_one(type);

	return this;
	}

ModExpr::ModExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_MOD, arg_op1, arg_op2)
	{
	if ( IsError() )
		return;

	TypeTag bt1 = op1->Type()->Tag();
	TypeTag bt2 = op2->Type()->Tag();

	if ( BothIntegral(bt1, bt2) )
		PromoteType(max_type(bt1, bt2));
	else
		ExprError("requires integral operands");
	}

Expr* ModExpr::DoSimplify()
	{
	if ( IsError() )
		return this;

	if ( op2->IsConst() )
		{
		if ( op2->IsOne() )
			return make_zero(type);
		else if ( op2->IsZero() )
			Error("zero modulus");
		}

	else if ( same_expr(op1, op2) )
		return make_zero(type);

	return this;
	}

BoolExpr::BoolExpr(BroExprTag arg_tag, Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(arg_tag, arg_op1, arg_op2)
	{
	if ( IsError() )
		return;

	TypeTag bt1 = op1->Type()->Tag();
	TypeTag bt2 = op2->Type()->Tag();

	if ( BothBool(bt1, bt2) )
		SetType(base_type(TYPE_BOOL));
	else
		ExprError("requires boolean operands");
	}

Val* BoolExpr::Eval(Frame* f) const
	{
	if ( IsError() )
		return 0;

	Val* v1 = op1->Eval(f);
	if ( ! v1 )
		return 0;

	if ( tag == EXPR_AND )
		{
		if ( v1->IsZero() )
			return v1;
		else
			{
			Unref(v1);
			return op2->Eval(f);
			}
		}

	else
		{
		if ( v1->IsZero() )
			{
			Unref(v1);
			return op2->Eval(f);
			}
		else
			return v1;
		}
	}

Expr* BoolExpr::DoSimplify()
	{
	if ( op1->IsConst() )
		{
		if ( op1->IsZero() )
			// F && x  or  F || x
			return (tag == EXPR_AND) ? make_zero(type) : op2->Ref();
		else
			// T && x  or  T || x
			return (tag == EXPR_AND) ? op2->Ref() : make_one(type);
		}

	else if ( op2->IsConst() )
		{
		if ( op1->IsZero() )
			// x && F  or  x || F
			return (tag == EXPR_AND) ? make_zero(type) : op1->Ref();
		else
			// x && T  or  x || T
			return (tag == EXPR_AND) ? op1->Ref() : make_one(type);
		}

	else if ( same_expr(op1, op2) )
		{
		Warn("redundant boolean operation");
		return op1->Ref();
		}

	return this;
	}

EqExpr::EqExpr(BroExprTag arg_tag, Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(arg_tag, arg_op1, arg_op2)
	{
	if ( IsError() )
		return;

	Canonicize();

	TypeTag bt1 = op1->Type()->Tag();
	TypeTag bt2 = op2->Type()->Tag();

	SetType(base_type(TYPE_BOOL));

	if ( BothArithmetic(bt1, bt2) )
		PromoteOps(max_type(bt1, bt2));

	else if ( EitherArithmetic(bt1, bt2) &&
		// Allow comparisons with zero.
		  ((bt1 == TYPE_TIME && op2->IsZero()) ||
		   (bt2 == TYPE_TIME && op1->IsZero())) )
		PromoteOps(TYPE_TIME);

	else if ( bt1 == bt2 )
		{
		switch ( bt1 ) {
		case TYPE_BOOL:
		case TYPE_TIME:
		case TYPE_INTERVAL:
		case TYPE_STRING:
		case TYPE_PORT:
		case TYPE_ADDR:
		case TYPE_NET:
		case TYPE_SUBNET:
		case TYPE_ERROR:
			break;

		case TYPE_ENUM:
			if ( ! same_type(op1->Type(), op2->Type()) )
				ExprError("illegal enum comparison");
			break;

		default:
			ExprError("illegal comparison");
		}
		}

	else if ( bt1 == TYPE_PATTERN && bt2 == TYPE_STRING )
		;

	else
		ExprError("type clash in comparison");
	}

void EqExpr::Canonicize()
	{
	if ( op2->Type()->Tag() == TYPE_PATTERN )
		SwapOps();

	else if ( op1->Type()->Tag() == TYPE_PATTERN )
		;

	else if ( expr_greater(op2, op1) )
		SwapOps();
	}

Expr* EqExpr::DoSimplify()
	{
	if ( same_expr(op1, op2) )
		{
		if ( ! optimize )
			Warn("redundant comparison");

		if ( tag == EXPR_EQ )
			return make_one(type);
		else
			return make_zero(type);
		}

	return this;
	}

Val* EqExpr::Fold(Val* v1, Val* v2) const
	{
	if ( op1->Type()->Tag() == TYPE_PATTERN )
		{
		RE_Matcher* re = v1->AsPattern();
		BroString* s = v2->AsString();
		if ( tag == EXPR_EQ )
			return new Val(re->MatchExactly(s), TYPE_BOOL);
		else
			return new Val(! re->MatchExactly(s), TYPE_BOOL);
		}

	else
		return BinaryExpr::Fold(v1, v2);
	}

RelExpr::RelExpr(BroExprTag arg_tag, Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(arg_tag, arg_op1, arg_op2)
	{
	if ( IsError() )
		return;

	Canonicize();

	TypeTag bt1 = op1->Type()->Tag();
	TypeTag bt2 = op2->Type()->Tag();

	SetType(base_type(TYPE_BOOL));

	if ( BothArithmetic(bt1, bt2) )
		PromoteOps(max_type(bt1, bt2));

	else if ( bt1 != bt2 )
		ExprError("operands must be of the same type");

	else if ( bt1 != TYPE_TIME && bt1 != TYPE_INTERVAL &&
		  bt1 != TYPE_PORT && bt1 != TYPE_ADDR )
		ExprError("illegal comparison");
	}

Expr* RelExpr::DoSimplify()
	{
	if ( same_expr(op1, op2) )
		{
		Warn("redundant comparison");
		// Here we use the fact that the canonical form of
		// a RelExpr only uses EXPR_LE or EXPR_LT.
		if ( tag == EXPR_LE )
			return make_one(type);
		else
			return make_zero(type);
		}

	return this;
	}

void RelExpr::Canonicize()
	{
	if ( tag == EXPR_GT )
		{
		SwapOps();
		tag = EXPR_LT;
		}

	else if ( tag == EXPR_GE )
		{
		SwapOps();
		tag = EXPR_LE;
		}
	}

CondExpr::CondExpr(Expr* arg_op1, Expr* arg_op2, Expr* arg_op3)
: Expr(EXPR_COND)
	{
	op1 = arg_op1;
	op2 = arg_op2;
	op3 = arg_op3;

	if ( op1->IsError() || op2->IsError() || op3->IsError() )
		SetError();

	else if ( op1->Type()->Tag() != TYPE_BOOL )
		ExprError("requires boolean conditional");

	else
		{
		TypeTag bt2 = op2->Type()->Tag();
		TypeTag bt3 = op3->Type()->Tag();

		if ( BothArithmetic(bt2, bt3) )
			{
			TypeTag t = max_type(bt2, bt3);
			if ( bt2 != t )
				op2 = new ArithCoerceExpr(op2, t);
			if ( bt3 != t )
				op3 = new ArithCoerceExpr(op3, t);
			SetType(base_type(t));
			}

		else if ( bt2 != bt3 )
			ExprError("operands must be of the same type");

		else
			SetType(op2->Type()->Ref());
		}
	}

CondExpr::~CondExpr()
	{
	Unref(op1);
	Unref(op2);
	Unref(op3);
	}

Expr* CondExpr::Simplify(SimplifyType /* simp_type */)
	{
	op1 = simplify_expr(op1, SIMPLIFY_GENERAL);
	op2 = simplify_expr(op2, SIMPLIFY_GENERAL);
	op3 = simplify_expr(op3, SIMPLIFY_GENERAL);

	if ( op1->IsConst() )
		{
		Val* v = op1->ExprVal();
		return (v->IsZero() ? op3 : op2)->Ref();
		}

	if ( op1->Tag() == EXPR_NOT )
		return new CondExpr(((NotExpr*) op1)->Op()->Ref(),
					op3->Ref(), op2->Ref());

	return this;
	}

Val* CondExpr::Eval(Frame* f) const
	{
	Val* v = op1->Eval(f);
	int false_eval = v->IsZero();
	Unref(v);

	return (false_eval ? op3 : op2)->Eval(f);
	}

int CondExpr::IsPure() const
	{
	return op1->IsPure() && op2->IsPure() && op3->IsPure();
	}

void CondExpr::ExprDescribe(ODesc* d) const
	{
	op1->Describe(d);
	d->AddSP(" ?");
	op2->Describe(d);
	d->AddSP(" :");
	op3->Describe(d);
	}

RefExpr::RefExpr(Expr* arg_op) : UnaryExpr(EXPR_REF, arg_op)
	{
	if ( IsError() )
		return;

	if ( ! is_assignable(op->Type()) )
		ExprError("illegal assignment target");
	else
		SetType(op->Type()->Ref());
	}

Expr* RefExpr::MakeLvalue()
	{
	return this;
	}

Val* RefExpr::Fold(Val* v) const
	{
	return v->Ref();
	}

void RefExpr::Assign(Frame* f, Val* v)
	{
	op->Assign(f, v);
	}

AssignExpr::AssignExpr(Expr* arg_op1, Expr* arg_op2, int arg_is_init)
: BinaryExpr(EXPR_ASSIGN, arg_is_init ? arg_op1 : arg_op1->MakeLvalue(), arg_op2)
	{
	is_init = arg_is_init;

	if ( IsError() )
		return;

	SetType(op1->Type()->Ref());

	if ( is_init )
		{
		SetLocationInfo(arg_op1->GetLocationInfo(),
				arg_op2->GetLocationInfo());
		return;
		}

	TypeTag bt1 = op1->Type()->Tag();
	TypeTag bt2 = op2->Type()->Tag();

	if ( ((bt1 == TYPE_ENUM) ^ (bt2 == TYPE_ENUM)) )
		ExprError("can't convert to/from enumerated type");

	else if ( IsArithmetic(bt1) )
		{
		if ( ! IsArithmetic(bt2) )
			ExprError("assignment of non-arithmetic value to arithmetic");
		else if ( bt1 == TYPE_DOUBLE )
			PromoteOps(TYPE_DOUBLE);
		else
			{
			if ( bt2 == TYPE_DOUBLE )
				{
				Warn("dangerous assignment of double to integral");
				op2 = new ArithCoerceExpr(op2, bt1);
				bt2 = op2->Type()->Tag();
				}

			if ( bt1 == TYPE_INT )
				PromoteOps(TYPE_INT);
			else
				{
				if ( bt2 == TYPE_INT )
					{
					Warn("dangerous assignment of integer to count");
					op2 = new ArithCoerceExpr(op2, bt1);
					bt2 = op2->Type()->Tag();
					}

				// Assignment of count to counter or vice
				// versa is allowed, and requires no
				// coercion.
				}
			}
		}

	else if ( bt1 == TYPE_TIME && IsArithmetic(bt2) && op2->IsZero() )
		{ // Allow assignments to zero as a special case.
		op2 = new ArithCoerceExpr(op2, bt1);
		bt2 = op2->Type()->Tag();
		}

	else if ( ! same_type(op1->Type(), op2->Type()) )
		{
		if ( op1->Type()->Tag() == TYPE_RECORD &&
		     op2->Type()->Tag() == TYPE_RECORD )
			op2 = new RecordCoerceExpr(op2, op1->Type()->AsRecordType());

		else
			ExprError("type clash in assignment");
		}

	SetLocationInfo(arg_op1->GetLocationInfo(), arg_op2->GetLocationInfo());
	}

Expr* AssignExpr::Simplify(SimplifyType /* simp_type */)
	{
	op1 = simplify_expr(op1, SIMPLIFY_LHS);
	op2 = simplify_expr(op2, SIMPLIFY_GENERAL);
	return this;
	}

Val* AssignExpr::Eval(Frame* f) const
	{
	if ( is_init )
		{
		Error("illegal assignment in initialization");
		return 0;
		}

	Val* v = op2->Eval(f);

	if ( v )
		{
		op1->Assign(f, v);
		//### op1->SetAttribs();
		return v->Ref();
		}
	else
		return 0;
	}

BroType* AssignExpr::InitType() const
	{
	if ( op1->Tag() != EXPR_LIST )
		{
		Error("bad initializer");
		return 0;
		}

	BroType* tl = op1->Type();
	if ( tl->Tag() != TYPE_LIST )
		Internal("inconsistent list expr in AssignExpr::InitType");

	return new TableType(tl->Ref()->AsTypeList(), op2->Type()->Ref());
	}

Val* AssignExpr::InitVal(const BroType* t, Val* aggr) const
	{
	if ( ! aggr )
		{
		Error("assignment in initialization");
		return 0;
		}

	if ( IsError() )
		return 0;

	TypeDecl td(0, 0);
	if ( IsRecordElement(&td) )
		{
		if ( t->Tag() != TYPE_RECORD )
			{
			Error("not a record initializer", t);
			return 0;
			}
		const RecordType* rt = t->AsRecordType();
		int field = rt->FieldOffset(td.id);

		if ( field < 0 )
			{
			Error("no such field");
			return 0;
			}

		if ( aggr->Type()->Tag() != TYPE_RECORD )
			Internal("bad aggregate in AssignExpr::InitVal");
		RecordVal* aggr_r = aggr->AsRecordVal();

		Val* v = op2->InitVal(rt->FieldType(td.id), 0);
		if ( ! v )
			return 0;

		aggr_r->Assign(field, v);
		return v;
		}

	else if ( op1->Tag() == EXPR_LIST )
		{
		if ( t->Tag() != TYPE_TABLE )
			{
			Error("not a table initialization", t);
			return 0;
			}

		if ( aggr->Type()->Tag() != TYPE_TABLE )
			Internal("bad aggregate in AssignExpr::InitVal");

		TableVal* tv = aggr->AsTableVal();
		const TableType* tt = tv->Type()->AsTableType();
		const BroType* yt = tv->Type()->YieldType();
		Val* index = op1->InitVal(tt->Indices(), 0);
		Val* v = op2->InitVal(yt, 0);
		if ( ! index || ! v )
			return 0;

		if ( ! tv->ExpandAndInit(index, v) )
			{
			Unref(index);
			Unref(tv);
			return 0;
			}

		Unref(index);
		return tv;
		}

	else
		{
		Error("illegal initializer");
		return 0;
		}
	}

int AssignExpr::IsRecordElement(TypeDecl* td) const
	{
	if ( op1->Tag() == EXPR_NAME )
		{
		if ( td )
			{
			const NameExpr* n = (const NameExpr*) op1;
			td->type = op2->Type()->Ref();
			td->id = copy_string(n->Id()->Name());
			}

		return 1;
		}
	else
		return 0;
	}

int AssignExpr::IsPure() const
	{
	return 0;
	}

IndexExpr::IndexExpr(Expr* arg_op1, ListExpr* arg_op2)
: BinaryExpr(EXPR_INDEX, arg_op1, arg_op2)
	{
	if ( IsError() )
		return;

	expr_list& el = arg_op2->Exprs();
	if ( el.length() == 1 && el[0]->Type()->Tag() == TYPE_RECORD )
		{
		op2 = new FlattenExpr(el[0]->Ref());
		Unref(arg_op2);

		if ( op1->Type()->Tag() != TYPE_TABLE )
			{
			Error("type cannot be indexed", op1->Type());
			SetError();
			return;
			}

		const TypeList* it = op1->Type()->AsTableType()->Indices();
		if ( ! same_type(it, op2->Type()) )
			{
			it->Error("indexing mismatch", op2->Type());
			SetError();
			return;
			}

		BroType* yt = op1->Type()->YieldType();
		SetType(yt ? yt->Ref() : base_type(TYPE_VOID));
		}

	else if ( ! op1->Type()->MatchesIndex(arg_op2) )
		SetError("not an index type");

	else if ( ! op1->Type()->YieldType() )
		// It's a set - so indexing it yields void.  We don't
		// directly generate an error message, though, since this
		// expression might be part of an add/delete statement,
		// rather than yielding a value.
		SetType(base_type(TYPE_VOID));

	else
		SetType(op1->Type()->YieldType()->Ref());
	}

int IndexExpr::CanAdd() const
	{
	if ( IsError() )
		return 1;	// avoid cascading the error report

	// "add" only allowed if our type is "set".
	return op1->Type()->Tag() == TYPE_TABLE && ! op1->Type()->YieldType();
	}

int IndexExpr::CanDel() const
	{
	if ( IsError() )
		return 1;	// avoid cascading the error report

	return op1->Type()->Tag() == TYPE_TABLE;
	}

void IndexExpr::Add(Frame* f)
	{
	if ( IsError() )
		return;

	Val* v1 = op1->Eval(f);
	Val* v2 = op2->Eval(f);

	if ( v1 && v2 )
		v1->AsTableVal()->Assign(v2, 0);

	Unref(v1);
	Unref(v2);
	}

void IndexExpr::Delete(Frame* f)
	{
	if ( IsError() )
		return;

	Val* v1 = op1->Eval(f);
	Val* v2 = op2->Eval(f);

	if ( v1 && v2 )
		Unref(v1->AsTableVal()->Delete(v2));

	Unref(v1);
	Unref(v2);
	}

Expr* IndexExpr::MakeLvalue()
	{
	return new RefExpr(this);
	}

Expr* IndexExpr::Simplify(SimplifyType simp_type)
	{
	op1 = simplify_expr(op1, simp_type);
	op2 = simplify_expr(op2, SIMPLIFY_GENERAL);
	return this;
	}

Val* IndexExpr::Fold(Val* v1, Val* v2) const
	{
	if ( IsError() )
		return 0;

	TableVal* v_tbl = v1->AsTableVal();
	Val* v = v_tbl->Lookup(v2);

	if ( ! v )
		{
		Attr* def_attr = v_tbl->FindAttr(ATTR_DEFAULT);

		if ( ! def_attr )
			{
			RunTime("no such index");
			return 0;
			}

		Val* def_val = def_attr->AttrExpr()->Eval(0);

		if ( def_val )
			{
			if ( def_val->Type()->Tag() == TYPE_FUNC )
				{
				// This is a bit strange - we need to Ref()
				// v2 twice.  Once, to preserve it when lv
				// is deleted below; the second time, when
				// the Call() unrefs the arguments.  We can't
				// just Ref() it once and not unref lv,
				// because we may-or-may-not create lv anew,
				// and if we do, we need to delete it to
				// prevent a leak.
				v2->Ref();
				v2->Ref();

				Func* f = def_val->AsFunc();
				ListVal* lv;

				if ( v2->Type()->Tag() == TYPE_LIST )
					lv = v2->AsListVal();
				else
					{
					lv = new ListVal(TYPE_ANY);
					lv->Append(v2);
					}

				def_val = f->Call(lv->Vals());
				Unref(lv);

				if ( ! def_val )
					{
					RunTime("no value returned from &default function");
					return 0;
					}
				}

			v_tbl->Assign(v2, def_val);
			return def_val->Ref();
			}

		else
			RunTime("non-constant default attribute");

		return 0;
		}
	else
		return v->Ref();
	}

void IndexExpr::Assign(Frame* f, Val* v)
	{
	if ( IsError() )
		return;

	Val* v1 = op1->Eval(f);
	Val* v2 = op2->Eval(f);

	if ( ! v1 || ! v2 )
		return;

	TableVal* v_tbl = v1->AsTableVal();
	if ( ! v_tbl->Assign(v2, v) )
		Internal("assignment failed");

	Unref(v1);
	Unref(v2);
	}

void IndexExpr::ExprDescribe(ODesc* d) const
	{
	op1->Describe(d);
	if ( d->IsReadable() )
		d->Add("[");

	op2->Describe(d);
	if ( d->IsReadable() )
		d->Add("]");
	}

FieldExpr::FieldExpr(Expr* arg_op, const char* arg_field_name)
: UnaryExpr(EXPR_FIELD, arg_op)
	{
	field_name = arg_field_name;
	td = 0;
	field = 0;

	if ( IsError() )
		return;

	if ( streq(arg_field_name, "attr") )
		{
		field = -1;
		SetType(op->Type()->AttributesType()->Ref());
		return;
		}

	if ( ! IsRecord(op->Type()->Tag()) )
		ExprError("not a record");
	else
		{
		RecordType* rt = op->Type()->AsRecordType();
		field = rt->FieldOffset(field_name);
		td = rt->FieldDecl(field);

		if ( field < 0 )
			ExprError("no such field in record");
		else
			SetType(rt->FieldType(field)->Ref());
		}
	}

FieldExpr::~FieldExpr()
	{
	delete field_name;
	}

Expr* FieldExpr::MakeLvalue()
	{
	return new RefExpr(this);
	}

Expr* FieldExpr::Simplify(SimplifyType simp_type)
	{
	op = simplify_expr(op, simp_type);
	return this;
	}

void FieldExpr::Assign(Frame* f, Val* v)
	{
	if ( IsError() || ! v )
		return;

	if ( field < 0 )
		{
		Val* lhs = op->Eval(f);
		lhs->SetAttribs(v->AsRecordVal());
		Unref(lhs);
		return;
		}

	Val* op_v = op->Eval(f);
	if ( op_v )
		{
		RecordVal* r = op_v->AsRecordVal();
		r->Assign(field, v);
		Unref(r);
		}
	}

Val* FieldExpr::Fold(Val* v) const
	{
	if ( field < 0 )
		return v->GetAttribs(true)->Ref();

	Val* result = v->AsRecordVal()->Lookup(field);
	if ( result )
		return result->Ref();

	// Check for &default.
	const Attr* def_attr = td ? td->FindAttr(ATTR_DEFAULT) : 0;
	if ( def_attr )
		return def_attr->AttrExpr()->Eval(0);
	else
		{
		Internal("field value missing");
		return 0;
		}
	}

void FieldExpr::ExprDescribe(ODesc* d) const
	{
	op->Describe(d);
	if ( d->IsReadable() )
		d->Add("$");

	if ( IsError() )
		d->Add("<error>");
	else if ( d->IsReadable() )
		d->Add(field_name);
	else
		d->Add(field);
	}

HasFieldExpr::HasFieldExpr(Expr* arg_op, const char* arg_field_name,
			   bool arg_is_attr)
: UnaryExpr(EXPR_HAS_FIELD, arg_op)
	{
	field_name = arg_field_name;
	is_attr = arg_is_attr;
	field = 0;

	if ( IsError() )
		return;

	if ( ! is_attr && ! IsRecord(op->Type()->Tag()) )
		ExprError("not a record");
	else
		{
		RecordType* rt = is_attr ?
					op->Type()->AttributesType() :
					op->Type()->AsRecordType();
		field = rt->FieldOffset(field_name);

		if ( field < 0 )
			ExprError("no such field in record");

		SetType(base_type(TYPE_BOOL));
		}
	}

HasFieldExpr::~HasFieldExpr()
	{
	delete field_name;
	}

Val* HasFieldExpr::Fold(Val* v) const
	{
	RecordVal* rec_to_look_at;

	if ( is_attr )
		rec_to_look_at = v->GetAttribs(false);
	else
		rec_to_look_at = v->AsRecordVal();

	if ( ! rec_to_look_at )
		return new Val(0, TYPE_BOOL);

	RecordVal* r = rec_to_look_at->Ref()->AsRecordVal();
	Val* ret = new Val(r->Lookup(field) != 0, TYPE_BOOL);
	Unref(r);

	return ret;
	}

void HasFieldExpr::ExprDescribe(ODesc* d) const
	{
	op->Describe(d);

	if ( d->IsReadable() )
		{
		if ( is_attr )
			d->Add("?$$");
		else
			d->Add("?$");
		}

	if ( IsError() )
		d->Add("<error>");
	else if ( d->IsReadable() )
		d->Add(field_name);
	else
		d->Add(field);
	}

RecordConstructorExpr::RecordConstructorExpr(ListExpr* constructor_list)
: UnaryExpr(EXPR_RECORD_CONSTRUCTOR, constructor_list)
	{
	if ( IsError() )
		return;

	// Spin through the list, which should be comprised of
	// either record's or record-field-assign, and build up a
	// record type to associate with this constructor.
	type_decl_list* record_types = new type_decl_list;

	const expr_list& exprs = constructor_list->Exprs();
	loop_over_list(exprs, i)
		{
		Expr* e = exprs[i];
		BroType* t = e->Type();

		if ( e->Tag() == EXPR_FIELD_ASSIGN )
			{
			FieldAssignExpr* field = (FieldAssignExpr*) e;

			BroType* field_type = field->Type()->Ref();
			char* field_name = copy_string(field->FieldName());

			record_types->append(new TypeDecl(field_type, field_name));
			continue;
			}

		if ( t->Tag() != TYPE_RECORD )
			{
			Error("bad type in record constructor", e);
			SetError();
			continue;
			}

		// It's a record - add in its fields.
		const RecordType* rt = t->AsRecordType();
		int n = rt->NumFields();
		for ( int j = 0; j < n; ++j )
			{
			const TypeDecl* td = rt->FieldDecl(j);
			record_types->append(new TypeDecl(td->type->Ref(), td->id));
			}
		}

	SetType(new RecordType(record_types));
	}

Val* RecordConstructorExpr::InitVal(const BroType* t, Val* aggr) const
	{
	if ( ! aggr )
		aggr = new RecordVal(const_cast<RecordType *>(t->AsRecordType()));
		
	if ( record_promotion_compatible(t->AsRecordType(), Type()->AsRecordType()) )
		{
		RecordVal* ar = aggr->AsRecordVal();
		RecordType* ar_t = aggr->Type()->AsRecordType();

		RecordVal* rv = Eval(0)->AsRecordVal();
		RecordType* rv_t = rv->Type()->AsRecordType();

		int i;
		for ( i = 0; i < rv_t->NumFields(); ++i )
			{
			int t_i = ar_t->FieldOffset(rv_t->FieldName(i));

			if ( t_i < 0 )
				{
				char buf[512];
				snprintf(buf, sizeof(buf),
					"orphan field \"%s\" in initialization",
					rv_t->FieldName(i));
				Error(buf);
				break;
				}

			else
				ar->Assign(t_i, rv->Lookup(i)->Ref());
			}

		for ( i = 0; i < ar_t->NumFields(); ++i )
			if ( ! ar->Lookup(i) &&
			     ! ar_t->FieldDecl(i)->FindAttr(ATTR_OPTIONAL) )
				{
				char buf[512];
				snprintf(buf, sizeof(buf),
					"non-optional field \"%s\" missing in initialization", ar_t->FieldName(i));
				Error(buf);
				}

		Unref(rv);

		return ar;
		}

	else
		{
		Error("bad record initializer");
		return 0;
		}
	}

Val* RecordConstructorExpr::Fold(Val* v) const
	{
	ListVal* lv = v->AsListVal();
	RecordType* rt = type->Ref()->AsRecordType();

	if ( lv->Length() != rt->NumFields() )
		Internal("inconsistency evaluating record constructor");

	RecordVal* rv = new RecordVal(rt);

	for ( int i = 0; i < lv->Length(); ++i )
		rv->Assign(i, lv->Index(i)->Ref());

	return rv;
	}

void RecordConstructorExpr::ExprDescribe(ODesc* d) const
	{
	d->Add("[");
	op->Describe(d);
	d->Add("]");
	}

FieldAssignExpr::FieldAssignExpr(const char* arg_field_name, Expr* value)
: UnaryExpr(EXPR_FIELD_ASSIGN, value), field_name(arg_field_name)
	{
	value->Ref();
	SetType(value->Type());
	}

Val* FieldAssignExpr::Fold(Val* v) const
	{
	return v->Ref();
	}

void FieldAssignExpr::ExprDescribe(ODesc* d) const
	{
	d->Add("$");
	d->Add(FieldName());
	d->Add("=");
	op->Describe(d);
	}


RecordMatchExpr::RecordMatchExpr(RecordMatchCases* arg_match_cases)
: Expr(EXPR_MATCH)
	{
	match_cases = arg_match_cases;

	RecordMatchCases::iterator pos;
	for ( pos = match_cases->begin(); pos != match_cases->end(); ++pos )
		{
		RecordMatchCase* match = pos->second;
		if ( match->match_expr->Type()->Tag() != TYPE_BOOL )
			ExprError("Match expression must be boolean");
		}

	SetType(base_type(TYPE_STRING));
	}

void RecordMatchExpr::AddMatchCase(RecordMatchCase* match_case)
	{
	match_cases->insert(make_pair(match_case->priority, match_case));
	}

Expr* RecordMatchExpr::Simplify(SimplifyType simp_type)
	{
	if ( IsError() )
		return this;

	RecordMatchCases::iterator pos;
	for ( pos = match_cases->begin(); pos != match_cases->end(); ++pos )
		{
		RecordMatchCase* match = pos->second;
		match->match_expr = simplify_expr(match->match_expr, simp_type);
		}

	return this;
	}

void RecordMatchExpr::ExprDescribe(ODesc* d) const
	{
	if ( d->IsReadable() )
		{
		d->Add("{");

		for ( RecordMatchCases::iterator pos = match_cases->begin();
		      pos != match_cases->end(); ++pos )
			{
			RecordMatchCase* match = pos->second;

			d->Add("[");
			d->Add(match->priority);
			d->Add(",");
			match->classname->Describe(d);
			d->Add(",");
			match->match_expr->Describe(d);
			d->Add("],");
			}

		d->Add("}");
		}
	}

Val* RecordMatchExpr::Eval(Frame *f) const
	{
	if ( IsError() )
		return 0;

	RecordMatchCases::iterator pos;
	for ( pos = match_cases->begin(); pos != match_cases->end(); ++pos )
		{
		RecordMatchCase* match = pos->second;
		if ( ! match->match_expr->Eval(f)->IsZero() )
			return match->classname;
		}

	return new StringVal("");
	}


ArithCoerceExpr::ArithCoerceExpr(Expr* arg_op, TypeTag t)
: UnaryExpr(EXPR_COERCE, arg_op)
	{
	if ( IsError() )
		return;

	SetType(base_type(t));

	TypeTag bt = op->Type()->Tag();

	if ( ((bt == TYPE_ENUM) ^ (t == TYPE_ENUM)) )
		ExprError("can't convert to/from enumerated type");

	else if ( ! IsArithmetic(t) && ! IsBool(t) &&
	     t != TYPE_TIME && t != TYPE_INTERVAL )
		ExprError("bad coercion");

	else if ( ! IsArithmetic(bt) && ! IsBool(bt) )
		ExprError("bad coercion value");
	}

Expr* ArithCoerceExpr::DoSimplify()
	{
	InternalTypeTag my_int = type->InternalType();
	InternalTypeTag op_int = op->Type()->InternalType();

	if ( my_int == TYPE_INTERNAL_UNSIGNED )
		my_int = TYPE_INTERNAL_INT;
	if ( op_int == TYPE_INTERNAL_UNSIGNED )
		op_int = TYPE_INTERNAL_INT;

	if ( my_int == op_int )
		return op->Ref();

	if ( op->IsConst() )
		{
		if ( my_int == TYPE_INTERNAL_INT )
			{
			if ( op_int != TYPE_INTERNAL_DOUBLE )
				Internal("bad coercion in CoerceExpr::DoSimplify");
			double d = op->ExprVal()->InternalDouble();
			int i = int(d);

			if ( i < 0 &&
			     type->InternalType() == TYPE_INTERNAL_UNSIGNED )
				Warn("coercion produces negative count value");

			if ( d != double(i) )
				Warn("coercion loses precision");

			return new ConstExpr(new Val(i, type->Tag()));
			}

		if ( my_int == TYPE_INTERNAL_DOUBLE )
			{
			if ( op_int == TYPE_INTERNAL_INT )
				{
				int i = op->ExprVal()->InternalInt();
				double d = double(i);

				if ( i != int(d) )
					Warn("coercion loses precision");

				return new ConstExpr(new Val(d, type->Tag()));
				}

			if ( op_int == TYPE_INTERNAL_UNSIGNED )
				{
				uint32 u = op->ExprVal()->InternalUnsigned();
				double d = double(u);

				if ( u != uint32(d) )
					Warn("coercion loses precision");

				return new ConstExpr(new Val(d, type->Tag()));
				}

			}

		Internal("bad coercion in CoerceExpr::DoSimplify");
		}

	return this;
	}

Val* ArithCoerceExpr::Fold(Val* v) const
	{
	InternalTypeTag t = type->InternalType();
	switch ( t ) {
	case TYPE_INTERNAL_DOUBLE:
		return new Val(v->CoerceToDouble(), TYPE_DOUBLE);

	case TYPE_INTERNAL_INT:
		return new Val(v->CoerceToInt(), TYPE_INT);

	case TYPE_INTERNAL_UNSIGNED:
		return new Val(v->CoerceToUnsigned(), TYPE_COUNT);

	default:
		Internal("bad type in CoerceExpr::Fold");
		return 0;
	}
	}

RecordCoerceExpr::RecordCoerceExpr(Expr* op, RecordType* r)
: UnaryExpr(EXPR_COERCE, op)
	{
	map_size = 0;
	map = 0;

	if ( IsError() )
		return;

	SetType(r->Ref());

	if ( Type()->Tag() != TYPE_RECORD )
		ExprError("coercion to non-record");

	else if ( op->Type()->Tag() != TYPE_RECORD )
		ExprError("coercion of non-record to record");

	else
		{
		RecordType* t_r = type->AsRecordType();
		RecordType* sub_r = op->Type()->AsRecordType();

		map_size = t_r->NumFields();
		map = new int[map_size];

		int i;
		for ( i = 0; i < map_size; ++i )
			map[i] = -1;	// -1 = field is not mapped

		for ( i = 0; i < sub_r->NumFields(); ++i )
			{
			int t_i = t_r->FieldOffset(sub_r->FieldName(i));
			if ( t_i < 0 )
				{
				// Same as in RecordConstructorExpr::InitVal.
				char buf[512];
				snprintf(buf, sizeof(buf),
					"orphan record field \"%s\"",
					sub_r->FieldName(i));
				Error(buf);
				continue;
				}

			BroType* sub_t_i = sub_r->FieldType(i);
			BroType* sup_t_i = t_r->FieldType(t_i);

			if ( ! same_type(sup_t_i, sub_t_i) )
				{
				char buf[512];
				snprintf(buf, sizeof(buf),
					"type clash for field \"%s\"", sub_r->FieldName(i));
				Error(buf, sub_t_i);
				SetError();
				}

			map[t_i] = i;
			}

		for ( i = 0; i < map_size; ++i )
			if ( map[i] == -1 &&
			     ! t_r->FieldDecl(i)->FindAttr(ATTR_OPTIONAL) )
				{
				char buf[512];
				snprintf(buf, sizeof(buf),
					"non-optional field \"%s\" missing", t_r->FieldName(i));
				Error(buf);
				SetError();
				}
		}
	}

RecordCoerceExpr::~RecordCoerceExpr()
	{
	delete [] map;
	}

Val* RecordCoerceExpr::Fold(Val* v) const
	{
	RecordVal* val = new RecordVal(Type()->Ref()->AsRecordType());
	RecordVal* rv = v->AsRecordVal();

	for ( int i = 0; i < map_size; ++i )
		{
		if ( map[i] >= 0 )
			val->Assign(i, rv->Lookup(map[i])->Ref());
		else
			val->Assign(i, 0);
		}

	return val;
	}

FlattenExpr::FlattenExpr(Expr* arg_op)
: UnaryExpr(EXPR_FLATTEN, arg_op)
	{
	if ( IsError() )
		return;

	BroType* t = op->Type();
	if ( t->Tag() != TYPE_RECORD )
		Internal("bad type in FlattenExpr::FlattenExpr");

	RecordType* rt = t->AsRecordType();
	num_fields = rt->NumFields();

	TypeList* tl = new TypeList();
	for ( int i = 0; i < num_fields; ++i )
		tl->Append(rt->FieldType(i)->Ref());

	Unref(rt);
	SetType(tl);
	}

Val* FlattenExpr::Fold(Val* v) const
	{
	RecordVal* rv = v->AsRecordVal();
	ListVal* l = new ListVal(TYPE_ANY);

	for ( int i = 0; i < num_fields; ++i )
		{
		Val* fv = rv->Lookup(i);

		if ( fv )
			{
			l->Append(fv->Ref());
			continue;
			}

		const RecordType* rv_t = rv->Type()->AsRecordType();
		const Attr* fa = rv_t->FieldDecl(i)->FindAttr(ATTR_DEFAULT);
		if ( fa )
			l->Append(fa->AttrExpr()->Eval(0));

		else
			Internal("missing field value");
		}

	return l;
	}


ScheduleTimer::ScheduleTimer(EventHandlerPtr arg_event, val_list* arg_args,
				double t)
: Timer(t)
	{
	event = arg_event;
	args = arg_args;
	}

ScheduleTimer::~ScheduleTimer()
	{
	}

void ScheduleTimer::Dispatch(double /* t */, int /* is_expire */)
	{
	mgr.QueueEvent(event, args);
	}

ScheduleExpr::ScheduleExpr(Expr* arg_when, EventExpr* arg_event)
: Expr(EXPR_SCHEDULE)
	{
	when = arg_when;
	event = arg_event;

	if ( IsError() || when->IsError() || event->IsError() )
		return;

	TypeTag bt = when->Type()->Tag();
	if ( bt != TYPE_TIME && bt != TYPE_INTERVAL )
		ExprError("schedule expression requires a time or time interval");
	else
		SetType(base_type(TYPE_TIMER));
	}

ScheduleExpr::~ScheduleExpr()
	{
	Unref(when);
	Unref(event);
	}

int ScheduleExpr::IsPure() const
	{
	return 0;
	}

Expr* ScheduleExpr::Simplify(SimplifyType simp_type)
	{
	when = when->Simplify(simp_type);
	Expr* generic_event = event->Simplify(simp_type);

	if ( ! generic_event )
		return 0;

	if ( generic_event->Tag() != EXPR_CALL )
		Internal("bad event type in ScheduleExpr::Simplify");

	event = (EventExpr*) generic_event;

	return this;
	}

Val* ScheduleExpr::Eval(Frame* f) const
	{
	Val* when_val = when->Eval(f);
	if ( ! when_val )
		return 0;

	double dt = when_val->InternalDouble();
	if ( when->Type()->Tag() == TYPE_INTERVAL )
		dt += network_time;

	val_list* args = eval_list(f, event->Args());

	if ( args )
		timer_mgr->Add(new ScheduleTimer(event->Handler(), args, dt));

	return 0;
	}

void ScheduleExpr::ExprDescribe(ODesc* d) const
	{
	if ( d->IsReadable() )
		d->AddSP("schedule");

	when->Describe(d);
	d->SP();

	if ( d->IsReadable() )
		{
		d->Add("{");
		d->PushIndent();
		event->Describe(d);
		d->PopIndent();
		d->Add("}");
		}
	else
		event->Describe(d);
	}

InExpr::InExpr(Expr* arg_op1, Expr* arg_op2)
: BinaryExpr(EXPR_IN, arg_op1, arg_op2)
	{
	if ( IsError() )
		return;

	if ( op1->Type()->Tag() == TYPE_PATTERN )
		{
		if ( op2->Type()->Tag() != TYPE_STRING )
			{
			op2->Type()->Error("pattern requires string index", op1);
			SetError();
			}
		else
			SetType(base_type(TYPE_BOOL));
		}

	else if ( op1->Type()->Tag() == TYPE_RECORD )
		{
		if ( op2->Type()->Tag() != TYPE_TABLE )
			{
			op2->Type()->Error("table/set required");
			SetError();
			}

		else
			{
			op1 = new FlattenExpr(op1);

			const BroType* t1 = op1->Type();
			const TypeList* it = op2->Type()->AsTableType()->Indices();

			if ( ! same_type(t1, it) )
				{
				t1->Error("indexing mismatch", op2->Type());
				SetError();
				}
			else
				SetType(base_type(TYPE_BOOL));
			}
		}

	else if ( op1->Type()->Tag() == TYPE_STRING &&
		  op2->Type()->Tag() == TYPE_STRING )
		SetType(base_type(TYPE_BOOL));

	else
		{
		// Check for:	<addr> in <subnet>
		//		<addr> in set[subnet]
		//		<addr> in table[subnet] of ...
		if ( op1->Type()->Tag() == TYPE_ADDR )
			{
			if ( op2->Type()->Tag() == TYPE_SUBNET )
				{
				SetType(base_type(TYPE_BOOL));
				return;
				}

			if ( (op2->Type()->Tag() == TYPE_SET ||
			      op2->Type()->Tag() == TYPE_TABLE) &&
			     op2->Type()->AsTableType()->IsSubNetIndex() )
				{
				SetType(base_type(TYPE_BOOL));
				return;
				}
			}

		if ( op1->Tag() != EXPR_LIST )
			op1 = new ListExpr(op1);

		ListExpr* lop1 = op1->AsListExpr();

		if ( ! op2->Type()->MatchesIndex(lop1) )
			SetError("not an index type");
		else
			{
			op1 = lop1;
			SetType(base_type(TYPE_BOOL));
			}
		}
	}

Val* InExpr::Fold(Val* v1, Val* v2) const
	{
	if ( v1->Type()->Tag() == TYPE_PATTERN )
		{
		RE_Matcher* re = v1->AsPattern();
		const BroString* s = v2->AsString();
		return new Val(re->MatchAnywhere(s) != 0, TYPE_BOOL);
		}

	if ( v2->Type()->Tag() == TYPE_STRING )
		{
		const BroString* s1 = v1->AsString();
		const BroString* s2 = v2->AsString();

		// Could do better here - either roll our own, to deal with
		// NULs, and/or Boyer-Moore if done repeatedly.
		return new Val(strstr(s2->CheckString(), s1->CheckString()) != 0, TYPE_BOOL);
		}

	if ( v1->Type()->Tag() == TYPE_ADDR &&
	     v2->Type()->Tag() == TYPE_SUBNET )
		return new Val(v2->AsSubNetVal()->Contains(v1->AsAddr()), TYPE_BOOL);

	TableVal* vt = v2->AsTableVal();
	if ( vt->Lookup(v1) )
		return new Val(1, TYPE_BOOL);
	else
		return new Val(0, TYPE_BOOL);
	}

CallExpr::CallExpr(Expr* arg_func, ListExpr* arg_args)
: Expr(EXPR_CALL)
	{
	func = arg_func;
	args = arg_args;

	if ( func->IsError() || args->IsError() )
		{
		SetError();
		return;
		}

	BroType* func_type = func->Type();
	if ( ! IsFunc(func_type->Tag()) )
		{
		func->Error("not a function");
		SetError();
		return;
		}

	if ( ! func_type->MatchesIndex(args) )
		SetError("not an index type");
	else
		{
		BroType* yield = func_type->YieldType();

			if ( ! yield )
				{
				Error("event called in expression");
				SetError();
				}
			else
				SetType(yield->Ref());
			}
		}

CallExpr::~CallExpr()
	{
	Unref(func);
	Unref(args);
	}

int CallExpr::IsPure() const
	{
	if ( IsError() )
		return 1;

	if ( ! func->IsPure() )
		return 0;

	Val* func_val = func->Eval(0);
	int pure = func_val && func_val->AsFunc()->IsPure() && args->IsPure();
	Unref(func_val);

	return pure;
	}

Expr* CallExpr::Simplify(SimplifyType /* simp_type */)
	{
	if ( IsError() )
		return this;

	func = simplify_expr(func, SIMPLIFY_GENERAL);
	args = simplify_expr_list(args, SIMPLIFY_GENERAL);

	if ( IsPure() )
		return new ConstExpr(Eval(0));
	else
		return this;
	}

Val* CallExpr::Eval(Frame* f) const
	{
	if ( IsError() )
		return 0;

	Val* ret = 0;
	Val* func_val = func->Eval(f);
	val_list* v = eval_list(f, args);

	if ( func_val && v )
		{
		::Func* func = func_val->AsFunc();
			calling_expr = this;

			ret = func->Call(v);
			// Don't Unref() the arguments, as Func::Call
			// already did that.
			delete v;

			calling_expr = 0;
			}
	else
		delete_vals(v);

	Unref(func_val);

	return ret;
	}

void CallExpr::ExprDescribe(ODesc* d) const
	{
	func->Describe(d);
	if ( d->IsReadable() || d->IsPortable() )
		{
		d->Add("(");
		args->Describe(d);
		d->Add(")");
		}
	else
		args->Describe(d);
	}

EventExpr::EventExpr(const char* arg_name, ListExpr* arg_args)
: Expr(EXPR_EVENT)
	{
	name = copy_string(arg_name);
	args = arg_args;

	EventHandler* h = event_registry->Lookup(name);
	if ( ! h )
		{
		h = new EventHandler(name);
		event_registry->Register(h);
		}

	handler = h;
	}

EventExpr::~EventExpr()
	{
	delete [] name;
	Unref(args);
	}

Expr* EventExpr::Simplify(SimplifyType /* simp_type */)
	{
	if ( ! IsError() )
		args = simplify_expr_list(args, SIMPLIFY_GENERAL);

	return this;
	}

Val* EventExpr::Eval(Frame* f) const
	{
	if ( IsError() )
		return 0;

	val_list* v = eval_list(f, args);
	mgr.QueueEvent(handler, v);

	return 0;
	}

void EventExpr::ExprDescribe(ODesc* d) const
	{
	d->Add(name);
	if ( d->IsReadable() || d->IsPortable() )
		{
		d->Add("(");
		args->Describe(d);
		d->Add(")");
		}
	else
		args->Describe(d);
	}


ListExpr::ListExpr() : Expr(EXPR_LIST)
	{
	SetType(new TypeList());
	}

ListExpr::ListExpr(Expr* e) : Expr(EXPR_LIST)
	{
	SetType(new TypeList());
	Append(e);
	}

ListExpr::~ListExpr()
	{
	loop_over_list(exprs, i)
		Unref(exprs[i]);
	}

void ListExpr::Append(Expr* e)
	{
	exprs.append(e);
	((TypeList*) type)->Append(e->Type()->Ref());
	}

int ListExpr::IsPure() const
	{
	loop_over_list(exprs, i)
		if ( ! exprs[i]->IsPure() )
			return 0;

	return 1;
	}

int ListExpr::AllConst() const
	{
	loop_over_list(exprs, i)
		if ( ! exprs[i]->IsConst() )
			return 0;

	return 1;
	}

Expr* ListExpr::Simplify(SimplifyType /* simp_type */)
	{
	loop_over_list(exprs, i)
		exprs.replace(i, simplify_expr(exprs[i], SIMPLIFY_GENERAL));

	// Note that we do *not* simplify a list with one element
	// to just that element.  The assumption that simplify_expr(ListExpr*)
	// returns a ListExpr* is widespread.
	return this;
	}

Val* ListExpr::Eval(Frame* f) const
	{
	ListVal* v = new ListVal(TYPE_ANY);

	loop_over_list(exprs, i)
		v->Append(exprs[i]->Eval(f));
	return v;
	}

BroType* ListExpr::InitType() const
	{
	if ( exprs.length() == 0 )
		{
		Error("empty list in untyped initialization");
		return 0;
		}

	if ( exprs[0]->IsRecordElement(0) )
		{
		type_decl_list* types = new type_decl_list;
		loop_over_list(exprs, i)
			{
			TypeDecl* td = new TypeDecl(0, 0);
			if ( ! exprs[i]->IsRecordElement(td) )
				{
				exprs[i]->Error("record element expected");
				delete td;
				delete types;
				return 0;
				}

			types->append(td);
			}

		return new RecordType(types);
		}

	else
		{
		TypeList* tl = new TypeList();
		loop_over_list(exprs, i)
			{
			Expr* e = exprs[i];
			BroType* ti = e->Type();

			// Collapse any embedded sets or lists.
			if ( ti->IsSet() || ti->Tag() == TYPE_LIST )
				{
				TypeList* til = ti->IsSet() ?
					ti->AsSetType()->Indices() :
					ti->AsTypeList();

				if ( ! til->IsPure() ||
				     ! til->AllMatch(til->PureType(), 1) )
					tl->Append(til->Ref());
				else
					tl->Append(til->PureType()->Ref());
				}
			else
				tl->Append(ti->Ref());
			}

		return tl;
		}
	}

Val* ListExpr::InitVal(const BroType* t, Val* aggr) const
	{
	if ( IsError() )
		return 0;

	// Check whether each element of this list itself matches t,
	// in which case we should expand as a ListVal.
	if ( ! aggr && type->AsTypeList()->AllMatch(t, 1) )
		{
		ListVal* v = new ListVal(TYPE_ANY);

		loop_over_list(exprs, i)
			{
			Val* vi = exprs[i]->InitVal(t, 0);
			if ( ! vi )
				{
				Unref(v);
				return 0;
				}
			v->Append(vi);
			}
		return v;
		}

	if ( t->Tag() == TYPE_LIST )
		{
		if ( aggr )
			{
			Error("bad use of list in initialization", t);
			return 0;
			}

		const type_list* tl = t->AsTypeList()->Types();
		if ( exprs.length() != tl->length() )
			{
			Error("index mismatch", t);
			return 0;
			}

		ListVal* v = new ListVal(TYPE_ANY);
		loop_over_list(exprs, i)
			{
			Val* vi = exprs[i]->InitVal((*tl)[i], 0);
			if ( ! vi )
				{
				Unref(v);
				return 0;
				}
			v->Append(vi);
			}
		return v;
		}

	if ( t->Tag() != TYPE_RECORD && t->Tag() != TYPE_TABLE )
		{
		if ( exprs.length() == 1 )
			// Allow "global x:int = { 5 }"
			return exprs[0]->InitVal(t, aggr);
		else
			{
			Error("aggregate initializer for scalar type", t);
			return 0;
			}
		}

	if ( ! aggr )
		Internal("missing aggregate in ListExpr::InitVal");

	if ( t->IsSet() )
		return AddSetInit(t, aggr);

	// If we got this far, then it's either a table or record
	// initialization.  Both of those involve AssignExpr's, which
	// know how to add themselves to a table or record.  Another
	// possibility is an expression that evaluates itself to a
	// table, which we can then add to the aggregate.
	loop_over_list(exprs, i)
		{
		Expr* e = exprs[i];

		if ( e->Tag() == EXPR_ASSIGN || e->Tag() == EXPR_FIELD_ASSIGN )
			{
			if ( ! e->InitVal(t, aggr) )
				return 0;
			}
		else
			{
			if ( t->Tag() == TYPE_RECORD )
				{
				e->Error("bad record initializer", t);
				return 0;
				}

			Val* v = e->Eval(0);
			if ( ! same_type(v->Type(), t) )
				{
				v->Type()->Error("type clash in table initializer", t);
				return 0;
				}

			if ( ! v->AsTableVal()->AddTo(aggr->AsTableVal(), 1) )
				return 0;
			}
		}

	return aggr;
	}

Val* ListExpr::AddSetInit(const BroType* t, Val* aggr) const
	{
	if ( aggr->Type()->Tag() != TYPE_TABLE )
		Internal("bad aggregate in ListExpr::InitVal");

	TableVal* tv = aggr->AsTableVal();
	const TableType* tt = tv->Type()->AsTableType();
	const BroType* it = tt->Indices();

	loop_over_list(exprs, i)
		{
		Val* element;

		if ( exprs[i]->Type()->IsSet() )
			// A set to flatten.
			element = exprs[i]->Eval(0);
		else
			element = exprs[i]->InitVal(it, 0);

		if ( ! element )
			return 0;

		if ( element->Type()->IsSet() )
			{
			if ( ! same_type(element->Type(), t) )
				{
				element->Error("type clash in set initializer", t);
				return 0;
				}

			if ( ! element->AsTableVal()->AddTo(tv, 1) )
				return 0;

			continue;
			}

		if ( ! (element = check_and_promote(element, it, 1)) )
			return 0;

		if ( ! tv->ExpandAndInit(element, 0) )
			{
			Unref(element);
			Unref(tv);
			return 0;
			}

		Unref(element);
		}

	return tv;
	}

void ListExpr::ExprDescribe(ODesc* d) const
	{
	d->AddCount(exprs.length());

	loop_over_list(exprs, i)
		{
		if ( (d->IsReadable() || d->IsPortable()) && i > 0 )
			d->Add(", ");

		exprs[i]->Describe(d);
		}
	}


RecordAssignExpr::RecordAssignExpr(Expr* record, Expr* init_list, int is_init)
	{
	const expr_list& inits = init_list->AsListExpr()->Exprs();

	RecordType* lhs = record->Type()->AsRecordType();

	// The inits have two forms:
	// 1) other records -- use all matching field names+types
	// 2) a string indicating the field name, then (as the next element)
	//    the value to use for that field.

	for ( int i = 0; i < inits.length(); ++i )
		{
		if ( inits[i]->Type()->Tag() == TYPE_RECORD )
			{
			RecordType* t = inits[i]->Type()->AsRecordType();

			for ( int j = 0; j < t->NumFields(); ++j )
				{
				const char* field_name = t->FieldName(j);
				int field = lhs->FieldOffset(field_name);

				if ( field >= 0 &&
				     same_type(lhs->FieldType(field), t->FieldType(j)) )
					{
					FieldExpr* fe_lhs = new FieldExpr(record, field_name);
					FieldExpr* fe_rhs = new FieldExpr(inits[i], field_name);
					Append(get_assign_expr(fe_lhs->Ref(), fe_rhs->Ref(), is_init));
					}
				}
			}

		else if ( inits[i]->Tag() == EXPR_FIELD_ASSIGN )
			{
			FieldAssignExpr* rf = (FieldAssignExpr*) inits[i];
			rf->Ref();

			const char* field_name = ""; // rf->FieldName();
			if ( lhs->HasField(field_name) )
				{
				FieldExpr* fe_lhs = new FieldExpr(record, field_name);
				Expr* fe_rhs = rf->Op();
				Append(get_assign_expr(fe_lhs->Ref(), fe_rhs, is_init));
				}
			else
				{
				string s = "No such field '";
				s += field_name;
				s += "'";
				init_list->SetError(s.c_str());
				}
			}

		else
			{
			init_list->SetError("bad record initializer");
			return;
			}
		}
	}


Expr* get_assign_expr(Expr* op1, Expr* op2, int is_init)
	{
	if ( op1->Type()->Tag() == TYPE_RECORD &&
	     op2->Type()->Tag() == TYPE_LIST )
		return new RecordAssignExpr(op1, op2, is_init);
	else
		return new AssignExpr(op1, op2, is_init);
	}


int check_and_promote_expr(Expr*& e, BroType* t)
	{
	BroType* et = e->Type();
	TypeTag e_tag = et->Tag();
	TypeTag t_tag = t->Tag();

	if ( EitherArithmetic(t_tag, e_tag) )
		{
		if ( e_tag == t_tag )
			return 1;

		if ( ! BothArithmetic(t_tag, e_tag) )
			{
			t->Error("arithmetic mixed with non-arithmetic", e);
			return 0;
			}

		TypeTag mt = max_type(t_tag, e_tag);
		if ( mt != t_tag )
			{
			t->Error("over-promotion of arithmetic value", e);
			return 0;
			}

		e = new ArithCoerceExpr(e, t_tag);
		return 1;
		}

	else if ( ! same_type(t, et) )
		{
		if ( t->Tag() == TYPE_RECORD && et->Tag() == TYPE_RECORD )
			{
			RecordType* t_r = t->AsRecordType();
			RecordType* et_r = et->AsRecordType();

			if ( record_promotion_compatible(t_r, et_r) )
				{
				e = new RecordCoerceExpr(e, t_r);
				return 1;
				}
			}

		t->Error("type clash", e);
		return 0;
		}

	return 1;
	}

int check_and_promote_exprs(ListExpr*& elements, TypeList* types)
	{
	expr_list& el = elements->Exprs();
	const type_list* tl = types->Types();

	if ( tl->length() == 1 && (*tl)[0]->Tag() == TYPE_ANY )
		return 1;

	if ( el.length() != tl->length() )
		{
		types->Error("indexing mismatch", elements);
		return 0;
		}

	loop_over_list(el, i)
		{
		Expr* e = el[i];
		if ( ! check_and_promote_expr(e, (*tl)[i]) )
			{
			e->Error("type mismatch", (*tl)[i]);
			return 0;
			}
		if ( e != el[i] )
			el.replace(i, e);
		}

	return 1;
	}

Expr* simplify_expr(Expr* e, SimplifyType simp_type)
	{
	if ( ! e )
		return 0;

	for ( Expr* s = e->Simplify(simp_type); s != e; s = e->Simplify(simp_type) )
		{
		Unref(e);
		e = s;
		}

	return e;
	}

ListExpr* simplify_expr_list(ListExpr* l, SimplifyType simp_type)
	{
	return (ListExpr*) simplify_expr(l, simp_type);
	}

val_list* eval_list(Frame* f, const ListExpr* l)
	{
	val_list* v = new val_list;

	const expr_list& e = l->Exprs();
	loop_over_list(e, i)
		{
		Val* ev = e[i]->Eval(f);
		if ( ! ev )
			break;
		v->append(ev);
		}

	if ( i < e.length() )
		{ // Failure.
		loop_over_list(*v, j)
			Unref((*v)[j]);
		delete v;
		return 0;
		}

	else
		return v;
	}

int same_expr(const Expr* e1, const Expr* e2)
	{
	if ( e1 == e2 )
		return 1;

	if ( e1->Tag() != e2->Tag() || ! same_type(e1->Type(), e2->Type()) )
		return 0;

	if ( e1->IsError() || e2->IsError() )
		return 0;

	switch ( e1->Tag() ) {
	case EXPR_NAME:
		{
		const NameExpr* n1 = (NameExpr*) e1;
		const NameExpr* n2 = (NameExpr*) e2;
		return n1->Id() == n2->Id();
		}

	case EXPR_CONST:
		{
		const ConstExpr* c1 = (ConstExpr*) e1;
		const ConstExpr* c2 = (ConstExpr*) e2;
		return same_val(c1->Value(), c2->Value());
		}

	case EXPR_INCR:
	case EXPR_DECR:
	case EXPR_NOT:
	case EXPR_NEGATE:
	case EXPR_POSITIVE:
	case EXPR_REF:
	case EXPR_RECORD_CONSTRUCTOR:
	case EXPR_FIELD_ASSIGN:
	case EXPR_COERCE:
	case EXPR_FLATTEN:
		{
		const UnaryExpr* u1 = (UnaryExpr*) e1;
		const UnaryExpr* u2 = (UnaryExpr*) e2;
		return same_expr(u1->Op(), u2->Op());
		}

	case EXPR_FIELD:
		{
		const FieldExpr* f1 = (FieldExpr*) e1;
		const FieldExpr* f2 = (FieldExpr*) e2;
		return same_expr(f1->Op(), f2->Op()) &&
			f1->Field() == f2->Field();
		}

	case EXPR_SCHEDULE:
		{
		const ScheduleExpr* s1 = (ScheduleExpr*) e1;
		const ScheduleExpr* s2 = (ScheduleExpr*) e2;
		return same_expr(s1->When(), s2->When()) &&
			same_expr(s1->Event(), s2->Event());
		}

	case EXPR_ADD:
	case EXPR_SUB:
	case EXPR_TIMES:
	case EXPR_DIVIDE:
	case EXPR_MOD:
	case EXPR_AND:
	case EXPR_OR:
	case EXPR_LT:
	case EXPR_LE:
	case EXPR_EQ:
	case EXPR_NE:
	case EXPR_GE:
	case EXPR_GT:
	case EXPR_ASSIGN:
	case EXPR_MATCH:
	case EXPR_INDEX:
	case EXPR_IN:
		{
		const BinaryExpr* b1 = (BinaryExpr*) e1;
		const BinaryExpr* b2 = (BinaryExpr*) e2;
		return same_expr(b1->Op1(), b2->Op1()) &&
			same_expr(b1->Op2(), b2->Op2());
		}

	case EXPR_LIST:
		{
		const ListExpr* l1 = (ListExpr*) e1;
		const ListExpr* l2 = (ListExpr*) e2;

		const expr_list& le1 = l1->Exprs();
		const expr_list& le2 = l2->Exprs();

		if ( le1.length() != le2.length() )
			return 0;

		loop_over_list(le1, i)
			if ( ! same_expr(le1[i], le2[i]) )
				return 0;

		return 1;
		}

	case EXPR_CALL:
		{
		const CallExpr* c1 = (CallExpr*) e1;
		const CallExpr* c2 = (CallExpr*) e2;

		return same_expr(c1->Func(), c2->Func()) &&
			c1->IsPure() && same_expr(c1->Args(), c2->Args());
		}

	default:
		internal_error("bad tag in same_expr()");
	}

	return 0;
	}

int expr_greater(const Expr* e1, const Expr* e2)
	{
	return int(e1->Tag()) > int(e2->Tag());
	}

static Expr* make_constant(BroType* t, double d)
	{
	Val* v = 0;
	switch ( t->InternalType() ) {
	case TYPE_INTERNAL_INT:		v = new Val(int(d), t->Tag()); break;
	case TYPE_INTERNAL_UNSIGNED:	v = new Val(uint32(d), t->Tag()); break;
	case TYPE_INTERNAL_DOUBLE:	v = new Val(double(d), t->Tag()); break;

	default:
		internal_error("bad type in make_constant()");
	}

	return new ConstExpr(v);
	}

Expr* make_zero(BroType* t)
	{
	return make_constant(t, 0.0);
	}

Expr* make_one(BroType* t)
	{
	return make_constant(t, 1.0);
	}
