//#include "string.h"
#include "iostream.h"
#include "genob.h"
#include "gcompile.h"
#include "expression.h"
#include "modules.h"
#include <std.h>
//#include "hash.h"
#include "evalprocs.h"
#include "traverse.h"
#include "gfunc.h"
extern "C" {
#include "ext_sym.h"
}
EXTERN void CompileBlockC(struct Block *bl, CFile *cf, int braces);


extern char* PackageName;
HashArray *AlreadyDumpedTab = NULL;

struct AddrLabel ** LabelLookup(HashArray* tab, void *addr)
{
    unsigned hash = (unsigned)addr ^ ((unsigned)addr >> 15);
//#define tab AlreadyDumpedTab
#define HASH_ELEMENT_TYPE struct AddrLabel *
#define HASH_LENGTH_LOG tab->tab_len_log
#define HASH_ELEMENT_LOG tab->element_len_log
#define HASH_EQUAL(element,arg) (*element)->addr() == addr
#define HASH_DATA tab->data
#include "hashfunc.h"
}

struct AddrLabel ** AddrLabelLookup(HashArray* tab, AddrLabel *label)
{
    return LabelLookup(tab, label->addr());
}

#define FindLabel(addr) LabelLookup(AlreadyDumpedTab, addr)

struct HashFuncs LabelHashFuncs = {NULL, (LookupFunc)AddrLabelLookup,HashAddr};

static void InitAlreadyDumped();

void InsertAlreadyDumped(struct AddrLabel *label)
{
    if (AlreadyDumpedTab == NULL) InitAlreadyDumped();
    struct AddrLabel **ptr = FindLabel(label->addr());
    *ptr = label;
    AlreadyDumpedTab->rehash_if_needed();
}

static void InitAlreadyDumped()
{
    if (AlreadyDumpedTab)
	return;
    AlreadyDumpedTab = new HashArray(128, sizeof(struct AddrLabel *));
    AlreadyDumpedTab->f = &LabelHashFuncs;
#if 0
    if (GlobalLabels == NULL) read_symbol_table(NULL);
    char *ptr = (char*)GlobalLabels + global_label_hashtab[0];
    char *lim = (char*)GlobalLabels +
	global_label_hashtab[GlobalLabels->hash_size+1];
    while (ptr < lim) {
	struct AddrLabel *label = (struct AddrLabel*)ptr;
	ptr += sizeof(int);
	while (*ptr++ != 0) ;
	InsertAlreadyDumped(label);
    }
#endif
}

inline char *AlreadyDumped(void *val, CFile *cf)
{
    if (AlreadyDumpedTab == NULL) InitAlreadyDumped();
    struct AddrLabel **ptr = FindLabel(val);
    if (*ptr == NULL) return NULL;
    return (*ptr)->name();
}

void DumpPointerTo(RootPtr val, CFile *cf)
{
    if (val == NULL) { cf->asm_stream() << "NULL"; return; }
    char *name = AlreadyDumped(val, cf);
    if (name) cf->asm_stream() << '&' << name;
    else val->dumpPtr(cf);
}

void DoPendingDumps(CFile *cf)
{
    while (cf->pendingDumps) {
	struct PrevDumped *dump = cf->pendingDumps;
	cf->pendingDumps = dump->next;
	(*dump->dumpProc)(dump, cf);
	dump->dumpProc = (DumpProc)NULL;
    }
}

struct PrevDumped *NewPendingDump(
    CFile *cf, const Root *val, DumpProc dumpProc, const char *name)
{
    char tmp_name[20];
    if (name == NULL) {
	cf->generate_label(tmp_name);
	name = tmp_name;
    }
    int name_length = strlen(name);
    PrevDumped *dump = (PrevDumped*)
	malloc(PrevDumpedLabelOffset + name_length + 1);
    strcpy((char*)dump + PrevDumpedLabelOffset, name);
    dump->next = cf->pendingDumps;
    cf->pendingDumps = dump;
    dump->addr() = (void*)val;
    InsertAlreadyDumped(&dump->lab);
    dump->dumpProc = dumpProc;
    return dump;
}

void FunctionDumpData(struct PrevDumped *dump, CFile *cf)
{ProcDescCPut((struct Function*)dump->addr(), cf, dump->name());
}

void FuncDumpPtr(struct Function *fnc, CFile *cf)
{
    char *label;
    char *old_name = AlreadyDumped(fnc, cf);
    if (old_name) {
	cf->asm_stream() << '&' << old_name;
	return;
    }
    if (fnc->fname == NULL)
	fnc->fname = GenName(), label = fnc->fname->string();
    else {
	// FIXME: KLUDGE to disambiguate from C++ names.
	label = (char*)malloc(strlen(fnc->str_name())+3);
	sprintf(label, "%sF_", fnc->str_name());
    }
    cf->aux_stream() << "extern struct Function " << label << ";\n";
    cf->asm_stream() << '&' << label;
    if (fnc->clauses[0].code == NULL) // KLUDGE to check if already compiled!
	{
	struct PrevDumped *dump =
	    NewPendingDump(cf, (Root*)fnc, FunctionDumpData, label);
//	fnc->t.options |= TypeIsCompiled;
    }
}

EXTERN void TypeCompile(struct RecordType *typ, CFile *cf, char *name);
void TypeDumpProc(struct PrevDumped *dump, CFile *cf)
{
    Type *dump_type = (Type*)dump->addr();
    switch (dump_type->kind) {
      case ReferenceTypeKind:
	cf->asm_stream() << "ReferenceType " << dump->name();
	cf->asm_stream() << " = {{\n  NULL," << dump_type->inst_size;
	cf->asm_stream() << ",0,0,NULL,0,0,ReferenceTypeKind,";
	cf->asm_stream() << dump_type->prefixLen << ',' << dump_type->alignment
	    << ',' << dump_type->excess_bits << ','
	    << (dump_type->options & ~TypeIsCompiled) << "|TypeIsCompiled}, ";
	DumpPointerTo(((ReferenceType*)dump_type)->base_class, cf);	
	cf->asm_stream() << "&};\n";
	break;
      case RecordTypeKind:
	TypeCompile((struct RecordType*)dump_type, cf, dump->name());
	break;
      default:
	abort();
    }
}

void RecordType::dumpPtr(CFile *cf) const
{
//    if (class_name == NULL) class_name = GenName();
    cf->asm_stream() << name() << "T::desc()";
    if (!(options & TypeIsCompiled)) {
//	options |= TypeIsCompiled;
	struct PrevDumped *dump = NewPendingDump(cf,this,&TypeDumpProc,NULL);
	cf->aux_stream() << "extern Class " << dump->name() << ";\n";
	cf->asm_stream() << '&' << dump->name();
    }
}

void ReferenceType::dumpPtr(CFile *cf) const
{
    if (this == &RefRoot) {
	cf->asm_stream() << "&RefRoot";
    }
    else if (this == &RefInteger)
	cf->asm_stream() << "&RefInteger";
    else if (this == &RefReal)
	cf->asm_stream() << "&RefReal";
    else if (this == &RefNumeric)
	cf->asm_stream() << "&RefNumeric";
    else if (this == &RefVector)
	cf->asm_stream() << "&RefVector";
    else {
	cf->asm_stream() << "<<unknown ref type>>";
    }
}

void PrimIntType::dumpPtr(CFile *cf) const
{
    if (this == _int::desc())
	cf->asm_stream() << "&_int::classDesc";
    else {
	cf->asm_stream() << "<<unknown prim int type>>";
    }
}

void TextType::dumpPtr(CFile *cf) const
{
    cf->asm_stream() << "&Text";
}

void GFunctionDumpProc(struct PrevDumped *dump, CFile *cf)
{
    GFunction *dump_func = (GFunction*)dump->addr();
    cf->asm_stream() << "GFunction " << dump->name() << "(";
    FuncDumpPtr(dump_func->func, cf);
    cf->asm_stream() << ");\n";
}

void GFunction::dumpPtr(CFile *cf) const
{
    struct PrevDumped *dump = NewPendingDump(cf, this, &GFunctionDumpProc, 0);
    cf->aux_stream() << "extern GFunction " << dump->name() << ";\n";
    cf->asm_stream() << "&" << dump->name();
}

void MFunctionDumpProc(struct PrevDumped *dump, CFile *cf)
{
    GFunction *dump_func = (GFunction*)dump->addr();
    cf->asm_stream() << "MFunction " << dump->name() << '(';
    FuncDumpPtr(dump_func->func, cf);
    cf->asm_stream() << ");\n";
}

void MFunction::dumpPtr(CFile *cf) const
{
    struct PrevDumped *dump = NewPendingDump(cf, this, &MFunctionDumpProc, 0);
    cf->aux_stream() << "extern MFunction " << dump->name() << ";\n";
    cf->asm_stream() << "&" << dump->name();
}

void ExprQuoteDumpProc(struct PrevDumped *dump, CFile *cf)
{
    ExprQuote *dump_expr = (ExprQuote*)dump->addr();
    cf->asm_stream() << "ExprQuote " << dump->name() << "(";
    DumpPointerTo(dump_expr->value(), cf);
    cf->asm_stream() << ");\n";
}

void ExprQuote::dumpPtr(CFile *cf) const
{
    if (this == &NULL_expr) {
	cf->asm_stream() << "&NULL_expr";
	return;
    }
    struct PrevDumped *dump = NewPendingDump(cf, this, &ExprQuoteDumpProc, 0);
    cf->aux_stream() << "extern ExprQuote " << dump->name() << ";\n";
    cf->asm_stream() << "&" << dump->name();
}

extern void SaveModule(struct Module *module, int compiling);

static void ModuleMainLabel(char *buf, char* module_name)
{
    sprintf(buf, "%s$SELF", module_name);
}

void EmitFields(struct Field *fields, CFile& cf)
{
    cf.indentation += 2;
    for (struct Field *fld = fields; fld != NULL; fld = fld->next()) {
	IndentC(&cf);
	switch (fld->kind) {
	  case Method_Field: cf.asm_stream() << "A_Method_FIELD("; break;
	  case Constant_Field: cf.asm_stream() << "A_Constant_FIELD("; break;
	  case Pointer_Field: cf.asm_stream() << "A_Pointer_FIELD("; break;
	  case Bit_Field:
	    cf.asm_stream() << (fld->u.b.is_signed ? "Signed" : "Unsigned");
	    cf.asm_stream() << "_Bit_FIELD(";
	    break;
	  case Struct_Field: cf.asm_stream() << "A_Struct_FIELD("; break;
	  case Include_Field: cf.asm_stream() << "A_Include_FIELD("; break;
	  default: cf.asm_stream() << "BAD_FIELD("; break;
	}
	DumpPointerTo(fld->fname(), &cf);
	switch (fld->kind) {
	  case Pointer_Field:
	  case Struct_Field:
	    cf.asm_stream() << ", " << fld->u.offset << ", ";
#if 0
	    if (fld->u.type == AnyT)
		fprintf(ff, "AnyT)\n");
	    else if (fld->u.type == PtrT)
		fprintf(ff, "PtrT)\n");
	    else if (fld->u.type == VariableT)
		fprintf(ff, "VariableT)\n");
	    else
#endif
		DumpPointerTo(fld->type, &cf), cf.asm_stream() << ")\n";
	    break;
	  case Method_Field:
	    cf.asm_stream() << ", ";
	    FuncDumpPtr(fld->u.func, &cf);
	    cf.asm_stream() << ")\n";
	    break;
	  case Constant_Field:
	    cf.asm_stream() << ", ";
	    DumpPointerTo((Root*)fld->u.value, &cf);
	    cf.asm_stream() << ")\n";
	    break;
	  case Bit_Field:
	    cf.asm_stream() << ", " << fld->u.offset << ", "
		<< fld->u.b.size << ")\n";
	    break;
	  default:
	    cf.asm_stream() << " offset:" << fld->u.offset
		<< ", kind:" << fld->kind << ")\n";
	}
    }
    cf.asm_stream() << "  EndFieldList()";
    cf.indentation -= 2;
    cf.asm_stream() << "};\n";
}

void SaveModule(struct Module *module, int compiling)
  { char buf[40];
    struct ModuleList *ext_mod = module->imported;
    register struct Declaration *decl;
    struct Declaration **ptr;
    const StringC *name_string = module->package_name();
    char *name = name_string ? name_string->chars() : "<unknown>";

    if (module->flags & ModuleError)
      {
	fprintf(stderr, "Module %s not saved due to errors\n", name);
	return;
      }
    CFile cf(name, module, compiling);
/*     cf.pendingList = SaveListFirst; */
/*    fprintf(stderr, "<SaveModule(%s, %d)>\n", name, compiling); */

    DumpPending(cf);
    for (ptr = &module->lookupDecls; *ptr != NULL; ptr = &(*ptr)->next()) {}
    *ptr = module->block->decls.first;
    for (decl = module->lookupDecls; decl != NULL; decl = decl->next()) {
	struct Any val;
#if 0
	if (DeclIsInclude(decl)) {
	    fprintf(LogFile, "[Attempt to save * ]\n");
	    //PutType(LogFile, MemGetType(ob)); fprintf(LogFile, ">#%X]\n", ob);
	    continue;
	}
#endif
	val.type = &RefRoot;
	if (decl->is_proc()) {
//	    struct Function *func = (struct Function*)ExType_Ptr(decl->type);
//	    ProcDescCPut(func, &cf, SymbolString(((struct Field*)decl)->name));
	    continue;
	}
	else if (decl->is_const())
	    val.addr = decl->get_const();
#if 0
	else if ((decl->flags & LookupDeclaration)
	  && (decl->is_const() || decl->is_proc()))
	    var = (Var *)decl->type.ptr;
#endif
	else {
	    CompileError(&cf,
			 "SaveModule: Confusion for decl %s!\n",
			 SymbolString(((struct Field*)decl)->name));
	    continue;
	}
#if 0
	if (val.addr == NULL) val = Object_TO_Any(val.type);
	if (HasHType(ob, Type) && decl->name != NULL)
	  { struct Type *t = (struct Type*)ob;
	    MakeLabelToken(&decl->token, SymbolString(decl->name), 0, 0);
	    if (t->name == NULL) t->name = decl->name;
	  }
	if (val.type == TypeT && ((struct Type*)val.addr)->name == NULL)
	    ((struct Type*)val.addr)->name = SymbolString(decl->name);
#endif

	fprintf(stderr, "[%s~: ", SymbolString(decl->name));

	((Type*)((Root*)val.addr)->isA())->printon(cerr);
	cerr << " = " << *((Root*)val.addr) << "]\n";

      }
#if 0
    struct DataToken token[1];
    ModuleMainLabel(buf, name);
    MakeLabelToken(token, SymbolString(module->name), 0, 0);
    DumpGen(MAKE_ANY(MemGetType(module), TypeT), &cf, token);
    MakeLabelToken(token, buf, 0, 0);
    token->options |= GlobalLabel;
    CPutGen(module, &cf, token);
#endif

    if (PackageName) {
	for (struct Field *fld = module->lookupDecls;
	     fld != NULL; fld = fld->next()) {
	    cf.asm_stream() << "static Predefined __pre"
		<< cf.generate_label_number() << "(";
	    Symbol *sym = fld->fname();
	    DumpPointerTo(sym, &cf);
	    cf.asm_stream() << ", ";
	    Root* val = sym->sym_value();
	    if (val == NULL) {
		cerr << "SaveModule confusion: no value for " << *sym << "\n";
		cf.asm_stream() << "???";
	    }
	    else
		DumpPointerTo(val, &cf);
	    cf.asm_stream() << ");\n";
	}
    }
    else {
	cf.asm_stream() << "struct Field _FIELDS_[] = {\n";
	EmitFields(module->lookupDecls, cf);
	cf.aux_stream() << "MOD_INIT(" << name << ")\n";
	ModuleMainLabel(buf, name);
    }
    if (PackageName == NULL) {
	cf.asm_stream() << "static struct Type *_MOD_ = " << name << "T;\n";
	cf.asm_stream() << "void INIT() { RegisterModule((Object)&_MOD_+1, ";
	DumpPointerTo(module->name(), &cf);
	cf.asm_stream() << "); }\n";    
    }
}

EXTERN void CompileCoerce(Expr *, ExType, CFile *);

struct Block * TestConstructor(register struct Block *block)
{
#if 0
    if (block->flags & BlockReturnSelf) return block;
#else
    struct Statement *st;
    for (;; block = st->src.block()) {
	// Check if block has a single statement.
	if (block->flags & BlockReturnSelf) return block;
	if (block->flags & BlockHasReturn) break;
	st = block->first;
	if (st == NULL || st->next != NULL || st->src.code() != Block_code)
	    break;
      }
#endif
    return NULL;
  }

#if 0
MakeFrameRefCountToken(struct DataToken *token, int fp_reg)
  {
    return MakeRegOffsetToken(token, fp_reg, -4);
  }
#endif

static void CompileParamList(struct ProcExpr *proc, Label *label,
			     ostream& outs, int declare_only)
{
    if (proc->procKind == 'C' || proc->expr->type == &Text)
	outs << "void ";
    else {
	    PrintTypeAsC(proc->expr->type, NULL, outs);
	    outs << ' ';
	}

    if (label != NULL && label->kind == StringLabel)
	outs << label->label;
    else if (label->kind == GeneratedLabel)
	outs << "FTMP_" << (int)label->label;
    else
	outs << *label;

    outs << '(';
    struct Declaration *var = proc->paramDecls;
    int i = 1;
    for (; var != NULL; i++, var = var->next()) {
	if (i > 1) outs << ", ";
	PrintTypeAsC(var->type,
		     declare_only ? NULL : ((struct Field*)var)->name,
		     outs);
    }
    outs << ')';
}

void CompileProc(struct ProcExpr *proc, CFile *cf, struct Label *label)
{
    struct ProcExpr *save_curProc = cf->curProc;
    int construct1 = 0;

#if 0
//  struct DataToken tmp_token[1], frameSizeLabel[1];
//  Object ex; int i;
//  int arg_offset, arg0_offset, arg_step;
    struct Declaration *var;
    char *label_label;
    if (label == NULL || label->kind != StringLabel)
	label_label = NULL;
    else label_label = label->label;

    if (!HasHType(proc, ProcExpr))
      { struct Label *expr_lab; struct ProcExpr *psave = proc;
	extern struct ProcExpr* Proc2ProcExpr();
	proc = Proc2ProcExpr(proc);
	if (proc == NULL || !HasHType(proc, ProcExpr))
	  { 
	    CompileError(cf, "Cannot compile proc: #%x (label %s)!",
		psave, label_label);
	    return 0;
	  }
	cf->curProc = proc;
	CPutGen(proc, cf, label); /* to handle Bind- and SearchPrevCompiles */
	cf->curProc = save_curProc;
	return;
      }
    ProcInit(cf);
#endif

    cf->sourcePos = proc->sourcePos;
    if (proc->procKind == 'C')
	construct1 = 1;

#if 0
    if (proc->flags & ProcIsExternal) {
	Expr_Ptr ex = proc->expr->first->src;
	if (ExprCodeOf(ex.E) != External_code) abort();
	cf->asm_stream() << "extern "C" RootPtr "
	    << SymbolString((Symbol*)ex.call) << "(void);\n",
	return;
    }
#endif
    if (!(label->flags | GlobalLabel)) cf->asm_stream() << "static ";
    if (label->kind == GeneratedLabel) {
	char buf[20];
	GenLabToString(buf, (int)label->label);
	cf->asm_stream() << "Object FTMP_" << (int)label->label
	    << "() asm(\"" << buf << "\");";
    }
    
    CompileParamList(proc, label, cf->aux_stream(), 1);
    if (proc->code_label && proc->code_label->isKindOf(*StringC::desc()))
	cf->aux_stream() << " asm(\""
	    << ((StringC*)proc->code_label)->chars() << "\");\n";
    else
	cf->aux_stream() << ";\n";
    
    if (proc->flags & ProcIsExternal)
	return;
    
    CompileParamList(proc, label, cf->asm_stream(), 0);
    
    cf->indentation = 2;
    cf->curProc = proc;
    if (construct1) {
	cf->asm_stream() << " {\n";
	CompileBlockC(proc->expr, cf, 0);
    }
    else {
	cf->asm_stream() << " { return ";
	CompileCoerce((Expr*)proc->expr, proc->expr->type, cf);
	cf->asm_stream() << "; ";
    }
    cf->curProc = save_curProc;
    cf->asm_stream() << "}\n";
    return;
}

void ProcDescCPut(struct Function *func, CFile *cf, char *name)
{
    TraverseData *data = cf->module->tr_data;
    PushPendingProc(func, data);
    PopPendingProcs(data);
    int i, j;
    char buf[80];
    struct Clause *clause;
    struct Label nLab;
    nLab.kind = StringLabel; nLab.flags = 0; nLab.offset = 0;
    for (i = 0, clause = &func->clauses[0]; i < func->nClauses; i++, clause++){
	struct Clause *clause = &func->clauses[i];
	int j; struct Formal *formal;
	struct Field *field0;
	nLab.label = buf;
	sprintf(buf, "%s_%dP", name, i);
	DumpClass(clause->paramDesc, &nLab, cf);
	if (clause->nParams > 0) {
	    Declaration *pdecl = clause->expr->paramDecls;
	    j = 0;
	    for (; pdecl != NULL; pdecl = pdecl->next(), j++)
		index_in_decl_list(pdecl) = j;
	    cf->asm_stream() << "static struct Formal " << name << "_"
		<< i << "F[" << clause->nParams << "] = {\n";
	    cf->indentation += 2;
	    field0 = clause->paramDesc->fields;
	    j = 0, formal = clause->formals;
	    for ( ; j < clause->nParams; j++, formal++) {
		IndentC(cf);
		if (formal->flags & FormalMustUnify)
		    cf->asm_stream() << "{{[expr]";
		else
		    cf->asm_stream() << "{{" << name << "_" << i << "P_F+"
			<< index_in_decl_list((Declaration*)formal->u.id);
	        cf->asm_stream() << "}, {";
		if (formal->default_expr == NULL)
		    cf->asm_stream() << "0";
		else if (formal->default_expr == &NilExpr)
		    cf->asm_stream() << "&NilExpr";
		else
		    DumpPointerTo(formal->default_expr, cf);
	        cf->asm_stream() << "}, " << formal->flags << "},\n";
	    }
	    cf->indentation -= 2;
	    cf->asm_stream() << "};\n";
	}
#if 0
	if (clause->resultType != NULL) {
	    if (clause->resultType->name == NULL) {
		sprintf(buf, "%s_%dR", name, i);
		clause->resultType->name = strdup(buf);
	    }
	    nLab.label = clause->resultType->name;
	    DumpGen(MAKE_ANY(clause->resultType, &Type), cf, &nLab);
	    nLab.label = buf;
	}
#endif
	if (clause->expr->code_label
	    && clause->expr->code_label->isKindOf(*Symbol::desc()))
	    nLab.label = ((Symbol*)clause->expr->code_label)->string();
	else
	    sprintf(buf, "%s_%d", name, i);
	CompileProc(clause->expr, cf, &nLab);
	if (clause->keywords) {
	    int nKeywords = clause->pn[2].required + clause->pn[2].optional;
	    KeywordEntry *keywordPtr = clause->keywords;
	    cf->asm_stream() << "static struct KeywordEntry " << name << "_"
		<< i << "K[" << nKeywords << "] = {\n";
	    for (i = 0; i < nKeywords; i++, keywordPtr++) {
		cf->asm_stream() << "  {";
		DumpPointerTo(keywordPtr->label, cf);
		cf->asm_stream() << ", " << keywordPtr->formal_number << ", "
		    << keywordPtr->inverse_formal_number << "},\n";
	    }
	    cf->asm_stream() << "};\n";
	}
    }
    cf->asm_stream() << "struct Clause " << name << "_C["
	<< func->nClauses << "] = {\n";
    for (i = 0, clause = &func->clauses[0]; ; clause++) {
	/* there is at least one clause */
	if (clause->expr->code_label
	    && clause->expr->code_label->isKindOf(*Symbol::desc()))
	    cf->asm_stream() << "  {(Func)"
		<< ((Symbol*)clause->expr->code_label)->string();
	else
	    cf->asm_stream() << "  {(Func)" << name << "_" << i;
	cf->asm_stream() << ", _" << name << "_" << i << "P_, ";
	if (clause->nParams > 0)
	    cf->asm_stream() << name << "_" << i << "F, ";
	else cf->asm_stream() << "NULL, ";
	if (clause->result == NULL) cf->asm_stream() << "NULL, ";
	else
	    cf->asm_stream() << name << "_" << i << "P_F+"
		<< clause->result - clause->paramDesc->fields << ",";
	if (clause->self == NULL) cf->asm_stream() << "NULL,";
	else
	    cf->asm_stream() << name << "_" << i << "P_F+"
		<< clause->self - clause->paramDesc->fields << ",";
	if (clause->expr->expr->flags & ExprAtMostOneResult)
	    clause->flags |= ClauseAtMostOneResult;
	cf->asm_stream() << clause->nParams << ", " << clause->minParams << ","
	    << clause->paramSize << "," <<(clause->flags|ClauseCompiled)<< ",";
	DumpPointerTo(clause->resultType, cf);
	cf->asm_stream() << ",NULL, {";
	for (j = 0; j < 3; j++)
	    cf->asm_stream() << "{" << clause->pn[j].required << "," <<
		clause->pn[j].optional << "," <<  clause->pn[j].tuple << "},";
		
	cf->asm_stream() << "}, ";
	if (clause->keywords)
	    cf->asm_stream() << name << "_" << i << "K";
	else
	    cf->asm_stream() << "NULL";
	cf->asm_stream() << '}';
	i++;
	if (i >= func->nClauses) break;
	cf->asm_stream() << ",\n  ";
    }
    cf->asm_stream() << "};\n";
/*  id = CompileStdPrefix(cf, NULL, "Function"); */
    cf->asm_stream() << "struct Function " << name << " = {";
#if 0
    fprintf(ff, "{,0,0,0,&FunctionClassDesc,\n  0,0,FunctionTypeKind,0,0,0,TypeIsCompiled},");
#endif
    DumpPointerTo(func->fname, cf);
    cf->asm_stream() << "," << func->flags << "," << func->nClauses
    << "," << name << "_C," << func->nParams << "};\n";
}
