%eden

/*
 * $Id: eddi.eden,v 1.1 2002/02/28 14:15:28 cssbz Exp $
 * Warning: this is a generated file
 */


##
## Original file eddipf.e (length 10703, dated Oct 23 08:58) follows...
##

%eden
/*
	File:		eddipf.e
	Program: 	EDEN functions for EDDI/P
	Date:		6/2/96
	Author:		Son V Truong
*/

/* Generally messed around with since by Ashley and Meurig */
/* Added some checking to the input of functions - Michael */
/*  */

/* Make a version of a table with no repeated rows */
func Makedistinct {
	para l;
	auto result, elt, ix;
	result = [];
	while (l#!=0) {
		elt = l[1];
		shift l;
		ix = 1;
		while ((ix<=result#)&&(elt!=result[ix])) ix++;
		if (result#<ix) result = result // [elt];
	}
	return result;
};

func DummyDistinct {
	para l;
	return l;
}

EDDI_distinct = 1;
makedistinct is ((EDDI_distinct) ? Makedistinct : DummyDistinct);

proc markFunctionsWhenGlobalStateChanges : EDDI_distinct {
  touch(&union, &diff, &inter, &project, &select, &rdupcols);
}

func create
/* table = (c1,k/n,c2,k/n,...,cN,k/n) */
{
	auto i, tlist;
	tlist = [[[]]];
	for (i=1; i<=$#; i+=2)
	{
		append tlist[1],$[i];
		if ($[i+1] == "#")
			append tlist[1][1],1;
		else
			append tlist[1][1],0;
	}
	return tlist;
}

func ucompat
/* bool = ucompat(t1,t2) */
{
	return ($1[1][1] == $2[1][1]);
}

func notin
/* bool = notin(t,v) */
{
	auto i,j;
	for (i=1; i<=$1#; i++)
	{
		if ($1[i] == $2)
			return 0;
	}
	return 1;
}

func showrel
/* showrel(t) */
{
	auto i,j;

	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for showrel.");
		return [[[]]];
	} else if ($1==@)
	{
		writeln("EDEN: ERROR: showrel has received an "//
		"undefined table.");
		return [[[]]];
	}
	
	if ($1 != [])
	{
		for (i=2; i<=$1[1]#; i++)
                {
                        write("----------------");
                }
		writeln("");
		for (i=2; i<=$1[1]#-1; i++)
		{
			write($1[1][i]);
			write("\t\t");
		}
		writeln($1[1][i]);
		for (i=2; i<=$1[1]#; i++)
                {
                        write("----------------");
                }
		writeln("");
		for (j=2; j<=$1#; j++)
		{
			for (i=1; i<=$1[1]#-2; i++)
		        {
		                write($1[j][i]);
		                write("\t\t");
       		 	}
		        writeln($1[j][i]);
		}
		for (i=2; i<=$1[1]#; i++)
                {
                        write("----------------");
                }
		writeln("");
	}
	else
		writeln("EDEN: table is empty.");
	
}

func addvals
/* table2 = addvals(t1,tup1,tup2,...,tupN) */
{
	auto i;
	
	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for addvals.");
		return [[[]]];
	} else if ($1==@)
	{
		writeln("EDEN: ERROR: addvals has received an "//
		"undefined table.");
		return [[[]]];
	}
	
        for (i=2; i<=$#; i++)
	{
		if ($1[1]#-1 == $[i]#)
		{
			if (notin($1,$[i])==1)
				append $1,$[i];
			else
				writeln("EDDI/EDEN ERROR: tuple exists already.");
		}
		else
			writeln("EDEN: ERROR: incorrect number of values.");
	}
	return $1;
}

func delvals
/* table2 = delvals(t1,v1,v2,...,vN) */
{
	auto i,j;

	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for delvals.");
		return [[[]]];
	} else if ($1==@)
	{
		writeln("EDEN: ERROR: delvals has received an "//
		"undefined table.");
		return [[[]]];
	}
	
	for (i=2; i<=$#; i++)
		if ($1[1]#-1 == $[i]#)
		{
			for (j=2; j<=$1#; j++)
				if ($1[j] == $[i])
					delete $1,j;
		}
		else
		{
			writeln("EDEN: ERROR: incorrect number of values.");
			return $1;
		}
	return $1;
}

func union
/* table3 = union(table1,table2) */
{
	auto i;
	
	if ($#<2)
	{
		writeln("EDEN: ERROR: two tables not provided for union.");
		return [[[]]];
	} else if (($1==@) || ($2==@))
	{
		writeln("EDEN: ERROR: union has received at least one "//
		"undefined table.");
		return [[[]]];
	}
	
	if (ucompat($1,$2) != 1)
	{
		writeln("EDEN: ERROR: tables are not union-compatible.");
		return [[[]]];
	}
	else
	{
		for (i=2; i<=$2#; i++)
			append $1,$2[i];
		return makedistinct($1);
	}

}

func getindex
/* index = getindex(t) */
{
	return $1[1][1];
}

func getkeys
/* keys = getkeys(t) */
{
	auto i,j, index;
	key = [];
	keylist = [];
	index = getindex($1);
	for (j=2; j<=$1#; j++)
	{
		for (i=1; i<=index#; i++)
			if (index[i] == 1)
				append key, $1[j][i];
		append keylist, key;
		key = [];
	}
	return keylist;
}

func diff
/* t3 = diff(t1,t2) */
{
	auto i, j, k;
	
	if ($#<2)
	{
		writeln("EDEN: ERROR: two tables not provided for diff.");
		return [[[]]];
	} else if (($1==@) || ($2==@))
	{
		writeln("EDEN: ERROR: diff has received at least one "//
		"undefined table.");
		return [[[]]];
	}

	tlist = $1;
	dlist = [];	
        if (ucompat($1,$2) != 1)
        {
                writeln("EDEN: ERROR: tables are not union-compatible.");
                return [[[]]];
        }
	else
	{
		for (j=2; j<=$1#; j++)
			for (k=2; k<=$2#; k++)
				if ($1[j] == $2[k])
					append dlist, $1[j];
		for(i=1;i<=dlist#;i++)
			tlist = delvals(tlist,dlist[i]);
		return makedistinct(tlist);
	}
}

func inter
/* t3 = inter(t1,t2) */
{
        auto j, k, tlist;
	
	if ($#<2)
	{
		writeln("EDEN: ERROR: two tables not provided for inter.");
		return [[[]]];
	} else if (($1==@) || ($2==@))
	{
		writeln("EDEN: ERROR: inter has received at least one "//
		"undefined table.");
		return [[[]]];
	}
	
        tlist = [];
        if (ucompat($1,$2) != 1)
        {
                writeln("EDEN: ERROR: tables are not union-compatible.");
                return [[[]]];
        }
	else
	{
		append tlist, $1[1];
	        for (j=2; j<=$1#; j++)
        	        for (k=2; k<=$2#; k++)
                	        if ($1[j] == $2[k])
                        	        append tlist, $1[j];
	        return makedistinct(tlist);
	}
}

func getcolumn
/* c_number = getcolumn(t,c) */
{
	auto i,j;
	j = 0;
	for (i=2; i<=$1[1]#; i++)
		if ($1[1][i] == $2)
		{
			j = i;
			break;
		}
	if (j != 0)
		return j-1;
	else
	{
		writeln("EDEN: ERROR: column not found.");
		return 0;
	}
}

func project
/* t2 = project(t1,c_list) */
{
	auto i,j,k;
	/* writeln("Project called with pars ", $1, " ", $2); */
	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for project.");
		return [[[]]];
	} else if ($1==@)
	{
		writeln("EDEN: ERROR: project has received an "//
		"undefined table.");
		return [[[]]];
	}
	
	tlist = [[[]]];
	
	/* For renaming attrs: c_list can contain [col_name,new_name] - ME*/
	for (i=1; i<=$2#; i++)
		if (type($2[i]) == "list")
		{
			append tlist[1],$2[i][2];
			$2[i] = $2[i][1];
		}
		else
			append tlist[1],$2[i];
			
        for (i=2; i<=$1#; i++)
                append tlist,[];
	for (i=1; i<=$2#; i++)
	{
		addcol = getcolumn($1,$2[i]);
		append tlist[1][1], $1[1][1][addcol];
		for (j=2; j<=$1#; j++)
			append tlist[j], $1[j][addcol];
	}
	return makedistinct(tlist);
}

func getcolval
{
	auto i,j;
	tlist = [];
	for (i=2; i<=$1#; i++)
		append tlist,$1[i][$2];
	return tlist;
}

func select
/* t2 = select(t1,c,c_op,c_val) */
{
	auto i,j,k,addcol;
	tlist1 = [];
	append tlist1, $1[1];
	keys = getcolval($1,getcolumn($1,$2));
	switch($3)
	{
		case "==" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] == $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		case "!=" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] != $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		case "<" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] < $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		case "<=" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] <= $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		case ">" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] > $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		case ">=" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] >= $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		default : writeln("EDDI/P Error: not a comparison.");
	}
	return makedistinct(tlist1);
}

func getkcols
{
	auto i;
	tlist = [];
	for (i=1; i<=$1[1][1]#; i++)
		if ($1[1][1][i] == 1)
			append tlist, $1[1][i+1];
	return tlist;
}

func rdupcols
{
	auto i,j,k;
	tlist = [[[]]];
	colnos = [2];
	delcols = [$1[1][2]];
	for (i=3; i<=$1[1]#; i++)
		if (notin(delcols,$1[1][i]))
		{
			append colnos, i;
			append delcols, $1[1][i];
		}
	for (j=1; j<=colnos#; j++)
	{
		append tlist[1][1], $1[1][1][colnos[j]-1];
		append tlist[1], $1[1][colnos[j]];
	}
	for (k=2; k<=$1#; k++)
	{
		append tlist, [];
		for (j=1; j<=colnos#; j++)
			append tlist[k], $1[k][colnos[j]-1];
	}
	return makedistinct(tlist);
}

func matchcols
/* [[mct1],[mct2]] = matchcols(t1,t2) */
{
	auto i,j;
	mct1 = [];
	mct2 = [];
	for(i=2;i<=$1[1]#;i++)
		for(j=2;j<=$2[1]#;j++)
		{
			if ($1[1][i] == $2[1][j])
			{
				append mct1,i;
				append mct2,j;
			}
		}
	return [mct1,mct2];
}

func njoin
{
	auto i,j,k,x,y,z;

	if ($#<2)
	{
		writeln("EDEN: ERROR: two tables not provided for njoin.");
		return [[[]]];
	} else if (($1==@) || ($2==@))
	{
		writeln("EDEN: ERROR: njoin has received at least one "//
		"undefined table.");
		return [[[]]];
	}

        tlist1 = [];
	vals1 = [];
	vals2 = [];
	nvals1 = [];
	nvals2 = [];
        append tlist1, $1[1];
	matcols = matchcols($1,$2);
	if (matcols != [[],[]])
	{
		for (i=1; i<=matcols[1]#; i++)
			append vals1, getcolval($1,matcols[1][i]-1);
		for (i=1; i<=matcols[2]#; i++)
			append vals2, getcolval($2,matcols[2][i]-1);
		for (j=1; j<=vals1[1]#; j++)
		{	
			append nvals1, [];
			for (k=1; k<=vals1#; k++)
				append nvals1[j], vals1[k][j];
		}
        	for (j=1; j<=vals2[1]#; j++)
	        {
	                append nvals2, [];
        	        for (k=1; k<=vals2#; k++)
	                        append nvals2[j], vals2[k][j];
		}
		attr = $1[1];
		attr[1] = attr[1] // $2[1][1];
		for (i=2; i<=$2[1]#; i++)
			append attr, $2[1][i];
		tlist = [attr];
		z = 1;
		for (x=1; x<=nvals1#; x++)
			for (y=1; y<=nvals2#; y++)
				if (nvals1[x] == nvals2[y])
				{
					append tlist, $1[x+1];
					z++;
					for (i=1; i<=$2[y+1]#; i++)
						append tlist[z], $2[y+1][i];
				}
		return rdupcols(tlist);
	}
	else
	{
		attr = $1[1];
		attr[1] = attr[1] // $2[1][1];
		for (i=2; i<=$2[1]#; i++)
                        append attr, $2[1][i];
                tlist = [attr];
		for (x=2;x<=$1#;x++)
			for (y=2; y<=$2#; y++)
			{
				append tlist, ($1[x] // $2[y]);
			}
		return tlist;
	}
}

func epipe
{
	auto i;
	tlist = [];
	for(i=2;i<=$1#;i++)
		append tlist,$1[i];
	return tlist;
}

##
## Original file eddi.e (length 6144, dated Feb 21 22:43) follows...
##
%eden

/* Modification by Ash */
/* include ("eddi/eddipf.e"); */
/* Removed by Ash Feb 21 2002: will be inserted above */
/* include(getenv("TKEDEN_LIB")//"/eddipf.e"); */

operators = [[':',"select_wrapper"],['%',"project"],['.',"inter"],['*',"njoin"],['+',"union"],['-',"diff"]];

func lookupop {
	para op;
	auto i;

	for (i = 1; i <= operators#; i++)
		if (char (op) == operators [i][1])
			return operators [i][2];

	return "unknown";
}

func select_wrapper {
	para tbl, pred;
	auto var, op, val, i, j;
	i = 1;

	while (i <= pred# && (isalphanum (pred[i]) || pred[i] == ' ')) i++;
	var = stripspace(substr (pred, 1, i - 1));
	j = i;
	
	while (i <= pred# && pred[i] != ' ' && !isalphanum (pred [i])) i++;
	op = stripspace (substr (pred, j, i - 1));
	val = converttonum (stripspace (substr (pred, i, pred#)));
	if (type (val) == "string")
		val = cutquotes (val);
	return select (tbl, var, op, val);
}

eddi_tables = [];

proc droptable {
	para tbl;
	auto i, new_tables;

	new_tables = [];

	for (i = 1; i <= eddi_tables#; i++)
		if (eddi_tables [i] != tbl)
			new_tables = new_tables // [eddi_tables [i]];

	eddi_tables = new_tables;
	forget (tbl);
}

proc addtotablelist {
	para tbl;
	eddi_tables = eddi_tables // [tbl];
}

proc listtables {
	auto i;
	writeln ("----------------");

	for (i = 1; i <= eddi_tables#; i++)
		writeln (eddi_tables [i]);

	writeln ("----------------");
}

eddi_notation = [";", "eddi_statement", []];

eddi_statement = ["suffix", ";", "eddi_statement_1", ["fail", "eddi_statement_1"]];

/*
eddi_statement_1 = ["prefix", "?", "table_val", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "showrel (%%);", "relname"]], ["fail", "eddi_statement_2"]];
*/
/* For reg_exp queries rather than just table name */
eddi_statement_1 = ["prefix", "?", "rel_exp", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "showrel (%%);", "relname"]], ["fail", "eddi_statement_2"]];
eddi_statement_2 = ["prefix", "~", "table_name", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "droptable (%%);", "relname"]], ["fail", "eddi_statement_3"]];

eddi_statement_3 = ["pivot", "<<", ["table_name", "tuples"], ["script", ["declare", "relname"], ["setparas", ["relname"], []], ["later", "$$ = addvals ($$, %%);", "relname", "relname", "v_substrs[2]"]], ["fail", "eddi_statement_4"]];
eddi_statement_4 = ["pivot", "!!", ["table_name", "tuples"], ["script", ["declare", "relname"], ["setparas", ["relname"], []], ["later", "$$ = delvals ($$, %%);", "relname", "relname", "v_substrs[2]"]], ["fail", "eddi_statement_5"]];

eddi_statement_5 = ["pivot", "is", ["table_name", "rel_exp"], ["script", ["declare", "relname", "expr"], ["setparas", ["relname"], ["expr"]], ["later", "$$ is %%;", "relname", "expr"]], ["fail", "eddi_statement_6"]];
eddi_statement_6 = ["pivot", "(", ["table_name", "create_state"], ["script", ["declare", "relname", "cdata"], ["setparas", ["relname"], ["cdata"]], ["later", "$$ = create ($$); addtotablelist (\"$$\");", "relname", "cdata", "relname"]], ["fail", "eddi_statement_7"]];

eddi_statement_7 = ["literal", "#", ["script", ["execute", "listtables ();"]]];

table_name = ident_ex ([["script", ["execute", "%% = \"%%\";", "v_paras[1]", "v_string"]]]);
table_val = ident_ex ([["script", ["execute", "%% is %%;", "v_paras[1]", "v_string"]]]);

func op_exp {
    para op, next;
    return ["pivot", str (op), ["rel_exp", "rel_exp"], ["script", ["declare", "p1", "p2"], ["setparas", ["p1"], ["p2"]], ["execute", "%% is " // lookupop (op) // "(%%, %%);", "v_paras[1]", "p1", "p2"]], ["ignore", ["bras"]], ["fail", next]];
}

rel_exp   = op_exp ('+', "rel_exp_1");
rel_exp_1 = op_exp ('-', "rel_exp_2");

rel_exp_2 = op_exp ('*', "rel_exp_3");
rel_exp_3 = op_exp ('.', "rel_exp_4");

rel_exp_4 = ["rev_pivot", "%", ["rel_exp", "attr_list"], ["script", ["declare", "expr_part", "attr_part"], ["setparas", ["expr_part"], ["attr_part"]], ["execute", "%% is " // lookupop ('%') // "(%%, %%);", "v_paras[1]", "expr_part", "attr_part"]], ["ignore", ["bras"]], ["fail", "rel_exp_5"]];
rel_exp_5 = ["rev_pivot", ":", ["rel_exp", "predicate"], ["script", ["declare", "expr_part"], ["setparas", ["expr_part"], []], ["execute", "%% is " // lookupop (':') // "(%%, ##);", "v_paras[1]", "expr_part", "v_substrs[2]"]], ["ignore", ["bras"]], ["fail", "rel_exp_6"]];

rel_exp_6 = ["prefix", "(", "rel_exp_7", ["fail", "table_val"], ["script", ["setparas", ["v_paras[1]"]]]];
rel_exp_7 = ["suffix", ")", "rel_exp", ["script", ["setparas", ["v_paras[1]"]]]];

tuples  = ["split", ",", "tuple", ["ignore", ["sq_bras"]]];

tuple   = ["prefix", "[", "tuple_1"];
tuple_1 = ["suffix", "]", "tuple_2"];
tuple_2 = ["split", ",", "tuple_3"];

tuple_3 = ["prefix", "\"", "tuple_5", ["fail", "float_num"]];
tuple_5 = ["suffix", "\"", "stringval"];

attr_list = ["split", ",", "col_name", ["script", ["allparas", "attrs"], ["execute", "%% is %%;", "v_paras[1]", "attrs"]]];
col_name = ident_ex ([["script", ["execute", "%% = \"%%\";", "v_paras[1]", "v_string"]]]);

predicate = anything;
stringval = anything;

func convertcols {
    para inlist;
    auto outstr, i;

    if (inlist# < 1)
        return "";

    outstr = "\"" // inlist [1][1] // "\", \"" // inlist [1][2] // "\"";

    for (i = 2; i <= inlist#; i++)
        outstr = outstr // ", \"" // inlist [i][1] // "\", \"" // inlist [i][2] // "\"";

    return outstr;
}

create_state   = ["suffix", ")", "create_state_1", ["script", ["declare", "cdata"], ["setparas", ["cdata"]], ["execute", "%% is convertcols (%%);", "v_paras[1]", "cdata"]]];
create_state_1 = ["split", ",", "col_info", ["script", ["allparas", "cols"], ["execute", "%% is %%;", "v_paras[1]", "cols"]]];

col_info   = ["pivot", " ", ["col_name", "col_info_2"], ["script", ["declare", "cname", "cdata"], ["setparas", ["cname"], ["cdata"]], ["execute", "%% is [%%, %%];", "v_paras[1]", "cname", "cdata"]]];
col_info_2 = ["suffix", "key", "anything", ["script", ["execute", "%% = \"#\";", "v_paras[1]"]], ["fail", "col_info_3"]];
col_info_3 = ["read_all", [], ["script", ["execute", "%% = \"X\";", "v_paras[1]"]]];

notation ("eddi", "eddi_notation");


##
## Original file neweddipf.e (length 10034, dated Oct 23 20:07) follows...
##

%eden
/*
	File:		eddipf.e
	Program: 	EDEN functions for EDDI/P
	Date:		6/2/96
	Author:		Son V Truong
*/

/* Generally messed around with since by Ashley and Meurig */
/* Added some checking to the input of functions - Michael */
/*  */

/* Make a version of a table with no repeated rows */
func Makedistinct {
	para l;
	auto result, elt, ix;
	result = [];
	while (l#!=0) {
		elt = l[1];
		shift l;
		ix = 1;
		while ((ix<=result#)&&(elt!=result[ix])) ix++;
		if (result#<ix) result = result // [elt];
	}
	return result;
};

func DummyDistinct {
	para l;
	return l;
}

EDDI_distinct = 1;
makedistinct is ((EDDI_distinct) ? Makedistinct : DummyDistinct);

proc markFunctionsWhenGlobalStateChanges : EDDI_distinct {
  touch(&union, &diff, &inter, &project, &select, &rdupcols);
}

func create
/* table = (c1,k/n,c2,k/n,...,cN,k/n) */
{
	auto i, tlist;
	tlist = [[[]]];
	for (i=1; i<=$#; i+=2)
	{
		append tlist[1],$[i];
		if ($[i+1] == "#")
			append tlist[1][1],1;
		else
			append tlist[1][1],0;
	}
	return tlist;
}

func ucompat
/* bool = ucompat(t1,t2) */
{
	return ($1[1][1] == $2[1][1]);
}

func notin
/* bool = notin(t,v) */
{
	auto i,j;
	for (i=1; i<=$1#; i++)
	{
		if ($1[i] == $2)
			return 0;
	}
	return 1;
}

func showrel
/* showrel(t) */
{
	auto i,j;

	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for showrel.");
		return @;
	} else if ($1==@)
	{
		writeln("EDEN: ERROR: showrel has received an "//
		"undefined table.");
		return @;
	}
	
	if ($1 != [])
	{
		for (i=2; i<=$1[1]#; i++)
                {
                        write("----------------");
                }
		writeln("");
		for (i=2; i<=$1[1]#-1; i++)
		{
			write($1[1][i]);
			write("\t\t");
		}
		writeln($1[1][i]);
		for (i=2; i<=$1[1]#; i++)
                {
                        write("----------------");
                }
		writeln("");
		for (j=2; j<=$1#; j++)
		{
			for (i=1; i<=$1[1]#-2; i++)
		        {
		                write($1[j][i]);
		                write("\t\t");
       		 	}
		        writeln($1[j][i]);
		}
		for (i=2; i<=$1[1]#; i++)
                {
                        write("----------------");
                }
		writeln("");
	}
	else
		writeln("EDEN: table is empty.");
	
}

func addvals
/* table2 = addvals(t1,tup1,tup2,...,tupN) */
{
	auto i;
	
	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for addvals.");
		return @;
	} else if ($1==@)
	{
		writeln("EDEN: ERROR: addvals has received an "//
		"undefined table.");
		return @;
	}
	
        for (i=2; i<=$#; i++)
	{
		if ($1[1]#-1 == $[i]#)
		{
			if (notin($1,$[i])==1)
				append $1,$[i];
			else
				writeln("EDDI/EDEN ERROR: tuple exists already.");
		}
		else
			writeln("EDEN: ERROR: incorrect number of values.");
	}
	return $1;
}

func delvals
/* table2 = delvals(t1,v1,v2,...,vN) */
{
	auto i,j;

	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for delvals.");
		return @;
	} else if ($1==@)
	{
		writeln("EDEN: ERROR: delvals has received an "//
		"undefined table.");
		return @;
	}
	
	for (i=2; i<=$#; i++)
		if ($1[1]#-1 == $[i]#)
		{
			for (j=2; j<=$1#; j++)
				if ($1[j] == $[i])
					delete $1,j;
		}
		else
		{
			writeln("EDEN: ERROR: incorrect number of values.");
			return $1;
		}
	return $1;
}

func union
/* table3 = union(table1,table2) */
{
	auto i;
	
	if ($#<2)
	{
		writeln("EDEN: ERROR: two tables not provided for union.");
		return @;
	} else if (($1==@) || ($2==@))
	{
		writeln("EDEN: ERROR: union has received at least one "//
		"undefined table.");
		return @;
	}
	
	if (ucompat($1,$2) != 1)
	{
		writeln("EDEN: ERROR: tables are not union-compatible.");
		return @;
	}
	else
	{
		for (i=2; i<=$2#; i++)
			append $1,$2[i];
		return makedistinct($1);
	}

}

func getindex
/* index = getindex(t) */
{
	return $1[1][1];
}

func getkeys
/* keys = getkeys(t) */
{
	auto i,j, index;
	key = [];
	keylist = [];
	index = getindex($1);
	for (j=2; j<=$1#; j++)
	{
		for (i=1; i<=index#; i++)
			if (index[i] == 1)
				append key, $1[j][i];
		append keylist, key;
		key = [];
	}
	return keylist;
}

func diff
/* t3 = diff(t1,t2) */
{
	auto i, j, k;
	
	if ($#<2)
	{
		writeln("EDEN: ERROR: two tables not provided for diff.");
		return @;
	} else if (($1==@) || ($2==@))
	{
		writeln("EDEN: ERROR: diff has received at least one "//
		"undefined table.");
		return @;
	}

	tlist = $1;
	dlist = [];	
        if (ucompat($1,$2) != 1)
        {
                writeln("EDEN: ERROR: tables are not union-compatible.");
                return @;
        }
	else
	{
		for (j=2; j<=$1#; j++)
			for (k=2; k<=$2#; k++)
				if ($1[j] == $2[k])
					append dlist, $1[j];
		for(i=1;i<=dlist#;i++)
			tlist = delvals(tlist,dlist[i]);
		return makedistinct(tlist);
	}
}

func inter
/* t3 = inter(t1,t2) */
{
        auto j, k, tlist;
	
	if ($#<2)
	{
		writeln("EDEN: ERROR: two tables not provided for inter.");
		return @;
	} else if (($1==@) || ($2==@))
	{
		writeln("EDEN: ERROR: inter has received at least one "//
		"undefined table.");
		return @;
	}
	
        tlist = [];
        if (ucompat($1,$2) != 1)
        {
                writeln("EDEN: ERROR: tables are not union-compatible.");
                return @;
        }
	else
	{
		append tlist, $1[1];
	        for (j=2; j<=$1#; j++)
        	        for (k=2; k<=$2#; k++)
                	        if ($1[j] == $2[k])
                        	        append tlist, $1[j];
	        return makedistinct(tlist);
	}
}

func getcolumn
/* c_number = getcolumn(t,c) */
{
	auto i,j;
	j = 0;
	for (i=2; i<=$1[1]#; i++)
		if ($1[1][i] == $2)
		{
			j = i;
			break;
		}
	if (j != 0)
		return j-1;
	else
	{
		writeln("EDEN: ERROR: column not found.");
		return 0;
	}
}

func project
/* t2 = project(t1,c_list) */
{
	auto i,j,k;
	/* writeln("Project called with pars ", $1, " ", $2); */
	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for project.");
		return [[[]]];
	} else if ($1==@)
	{
		writeln("EDEN: ERROR: project has received an "//
		"undefined table.");
		return [[[]]];
	}
	
	tlist = [[[]]];
	
	/* For renaming attrs: c_list can contain [col_name,new_name] - ME*/
	for (i=1; i<=$2#; i++)
		if (type($2[i]) == "list")
		{
			append tlist[1],$2[i][2];
			$2[i] = $2[i][1];
		}
		else
			append tlist[1],$2[i];
			
        for (i=2; i<=$1#; i++)
                append tlist,[];
	for (i=1; i<=$2#; i++)
	{
		addcol = getcolumn($1,$2[i]);
		append tlist[1][1], $1[1][1][addcol];
		for (j=2; j<=$1#; j++)
			append tlist[j], $1[j][addcol];
	}
	return makedistinct(tlist);
}

func getcolval
{
	auto i,j;
	tlist = [];
	for (i=2; i<=$1#; i++)
		append tlist,$1[i][$2];
	return tlist;
}

func select
/* t2 = select(t1,c,c_op,c_val) */
{
	auto i,j,k,addcol;
	tlist1 = [];
	append tlist1, $1[1];
	keys = getcolval($1,getcolumn($1,$2));
	switch($3)
	{
		case "==" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] == $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		case "!=" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] != $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		case "<" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] < $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		case "<=" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] <= $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		case ">" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] > $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		case ">=" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] >= $4)
					append tlist1,$1[i+1];
			}
			break;
		}
		default : writeln("EDDI/P Error: not a comparison.");
	}
	return makedistinct(tlist1);
}

func getkcols
{
	auto i;
	tlist = [];
	for (i=1; i<=$1[1][1]#; i++)
		if ($1[1][1][i] == 1)
			append tlist, $1[1][i+1];
	return tlist;
}

func rdupcols
{
	auto i,j,k;
	tlist = [[[]]];
	colnos = [2];
	delcols = [$1[1][2]];
	for (i=3; i<=$1[1]#; i++)
		if (notin(delcols,$1[1][i]))
		{
			append colnos, i;
			append delcols, $1[1][i];
		}
	for (j=1; j<=colnos#; j++)
	{
		append tlist[1][1], $1[1][1][colnos[j]-1];
		append tlist[1], $1[1][colnos[j]];
	}
	for (k=2; k<=$1#; k++)
	{
		append tlist, [];
		for (j=1; j<=colnos#; j++)
			append tlist[k], $1[k][colnos[j]-1];
	}
	return makedistinct(tlist);
}

func matchcols
/* [[mct1],[mct2]] = matchcols(t1,t2) */
{
	auto i,j;
	mct1 = [];
	mct2 = [];
	for(i=2;i<=$1[1]#;i++)
		for(j=2;j<=$2[1]#;j++)
		{
			if ($1[1][i] == $2[1][j])
			{
				append mct1,i;
				append mct2,j;
			}
		}
	return [mct1,mct2];
}

func njoin
{
	auto i,j,k,x,y,z;

	if ($#<2)
	{
		writeln("EDEN: ERROR: two tables not provided for njoin.");
		return @;
	} else if (($1==@) || ($2==@))
	{
		writeln("EDEN: ERROR: njoin has received at least one "//
		"undefined table.");
		return @;
	}

        tlist1 = [];
	vals1 = [];
	vals2 = [];
	nvals1 = [];
	nvals2 = [];
        append tlist1, $1[1];
	matcols = matchcols($1,$2);
	if (matcols != [[],[]])
	{
		for (i=1; i<=matcols[1]#; i++)
			append vals1, getcolval($1,matcols[1][i]-1);
		for (i=1; i<=matcols[2]#; i++)
			append vals2, getcolval($2,matcols[2][i]-1);
		for (j=1; j<=vals1[1]#; j++)
		{	
			append nvals1, [];
			for (k=1; k<=vals1#; k++)
				append nvals1[j], vals1[k][j];
		}
        	for (j=1; j<=vals2[1]#; j++)
	        {
	                append nvals2, [];
        	        for (k=1; k<=vals2#; k++)
	                        append nvals2[j], vals2[k][j];
		}
		attr = $1[1];
		attr[1] = attr[1] // $2[1][1];
		for (i=2; i<=$2[1]#; i++)
			append attr, $2[1][i];
		tlist = [attr];
		z = 1;
		for (x=1; x<=nvals1#; x++)
			for (y=1; y<=nvals2#; y++)
				if (nvals1[x] == nvals2[y])
				{
					append tlist, $1[x+1];
					z++;
					for (i=1; i<=$2[y+1]#; i++)
						append tlist[z], $2[y+1][i];
				}
		return rdupcols(tlist);
	}
	else
	{
		attr = $1[1];
		attr[1] = attr[1] // $2[1][1];
		for (i=2; i<=$2[1]#; i++)
                        append attr, $2[1][i];
                tlist = [attr];
		for (x=2;x<=$1#;x++)
			for (y=2; y<=$2#; y++)
			{
				append tlist, ($1[x] // $2[y]);
			}
		return tlist;
	}
}

func epipe
{
	auto i;
	tlist = [];
	for(i=2;i<=$1#;i++)
		append tlist,$1[i];
	return tlist;
}

##
## Original file newshowrel2.e (length 4517, dated Oct 9 17:57) follows...
##
%eden

_DUMMY = [[[0],"A"],[0]];
/* a dummy eddi relation _DUMMY (A int); _DUMMY << [1]; */
curr_rel = _DUMMY;

/* file derived from newshowrel.dev.e which contains some development stuff */
/* Added check for a defined table to showrel(rel) - Michael  */

num_tuple is curr_rel#-1;
curr_attr is curr_rel[1][curr_index+1];
curr_attr_value is curr_rel[curr_tuple_num+1][curr_index];
/* curr_attr_str is (curr_rel[1][1][curr_index]==1)?curr_attr_value:ntzstr(curr_attr_value); */
curr_attr_str is ntzstr(curr_attr_value);
curr_attr_len is curr_attr_str#;

/*  curr_attr_len is (curr_rel[1][1][curr_index]==1)?curr_attr_value#:str(curr_attr_value)#; */

func ntzstr {
        /* no trailing zeros display for real x */
	/* this conversion function also passes strings through unmodified */
	/* this is because of the boundary problem in the definitive environment */
	/* whereby neither curr_tuple_num = 0 / 1 is appropriate */
        para x;
        auto strx, i, j, result;
	strx = str(x);
	j = strx#;
	if (x==int(x)) return(str(int(x)));
	if (x!=str(x)) {
	        i=1;
	        while (strx[i]!='.') i++;
	        while ((j>i) && (strx[j]=='0')) j--;
	};
	result = "";
	for (i=1; i<=j; i++) result = result // strx[i];
        return result;
};


func normalise_len {
	 para s, n;
        auto i, result;
        i = 0;
	result = "";
        while (i<n) {
                i++;
                if (i<=s#) result = result // s[i];
                else result = result // ' ';
        };
        return result // " | ";
};

func compute_max_len {
	/* as given by curr_index (which field) and curr_rel (which rel) */
	auto i,result;
	result = curr_attr#;
	for (i=1; i<=num_tuple; i++) {
		curr_tuple_num = i;
		if (result < curr_attr_len) result = curr_attr_len;
	};
	curr_tuple_num = 1;
	/* this assignment addresses the boundary problem in the definitive environment */
	return result;
};

func mkdisplist_col {
	/* assumes curr_index given and curr_rel */
	auto i,ml,result;
	ml = compute_max_len();
	result = [repchar('-', ml+3)];
	/* normalise_len introduces 3 extra characters to pad strings */
        result = result // [normalise_len(curr_attr,ml)];
	result = result // [repchar('-', ml+3)];
        for (i=1; i<=num_tuple; i++) {
                curr_tuple_num = i;
                result = result // [normalise_len(curr_attr_str,ml)];
        };
	result = result // [repchar('-', ml+3)];
        curr_tuple_num = 1;
        /* this assignment addresses the boundary problem in the definitive environment */
        return result;
};

num_fields is curr_rel[1][1]#;

func mkdisplist_rel {
	/* assumes a curr_rel is given */
	auto i,result;
	curr_index = 1;
	result = mkdisplist_col();
	for (i=2; i<=num_fields; i++) {
		curr_index=i;
		result = displayrt(result, mkdisplist_col());
	};
	curr_index = 1;
	/* this assignment addresses the boundary problem in the definitive environment */
	return result;
};


proc display_list
{
        /* display a display_list $1 */
        auto i;
        for (i=1; i<=$1#; i++)
        {
                writeln($1[i]);
        }
}

func repchar
{
 /* $1=char, $2=number of repetitions */
 auto s, i;
 s = substr("", 1, $2);
 for (i = 1; i <= $2; i++)
   s[i] = $1;
 return s;
}

func displayabove
{
	/* two display lists $1 and $2 -> display list for $1 above $2 */
	auto s,i;
	s = $1;
	for (i=1; i<=$2#; i++) {
		append s, $2[i];
	}
	return s;
}

func displayrt
{
	/* two display lists $1 and $2 -> display list for $1 to right of $2 */
	auto s,i;
	s = [];
	for (i=1; i<=$1#; i++) {
		append s, ($1[i] // $2[i]);
	}
	return s;
}

/* some instances of showrel() in action that can be used to test above in connection
	with the fruits.eddi database */

/*

curr_rel = ALLFRUITS;
display_list(mkdisplist_rel());

NEWFRUITS = [ALLFRUITS[1]];	/* empty relation */
curr_rel = NEWFRUITS;
display_list(mkdisplist_rel());

curr_rel = CITRUS;
display_list(mkdisplist_rel());

MIX = union(APPLE, CITRUS);
curr_rel = MIX;
display_list(mkdisplist_rel());
*/

proc showrel {
	para rel;
	
	if (rel==@)
	{
		writeln("EDEN: ERROR: showrel has been given an "//
		"undefined table.");
		return [[[]]];
	}
	
	autocalc = 0;
	curr_rel = rel;
	display_list(mkdisplist_rel());
	
	if (rel# == 2)
		writeln("(1 row)");
	else
		writeln("(" // str(rel#-1) // " rows)");
	
	curr_rel = _DUMMY;
	autocalc = 1;
};



##
## Original file newselect2.e (length 2709, dated Oct 27 10:57) follows...
##
autocalc=0;
func select
/* t2 = select(t1,c,c_op,c_val) */
{
	auto i,j,k,addcol,compval, constval, constelt;
	tlist1 = [];		/* why isn't tlist auto? */
	if ($1==@) {
		writeln("EDEN: ERROR: select has been given an "//
		 "undefined table.");
		return @;
	} else
		if (!isinlist($2, tail($1[1]))) {
			writeln("EDEN: ERROR: select has been given an "//
				 "invalid attribute.");
			return @;
		} 
	append tlist1, $1[1];
	keys = getcolval($1,getcolumn($1,$2));
	/* writeln(type($4), " ", $4); indicates types of selection */
	constelt =((type($4) == "string") && ($4[1]== '\"'))
					? cutquotes($4) : $4;
	constval = [];
	for (i=1; i<=$1#-1; i++) constval = constval // [constelt]; 
	compval = constval;
	/* constval is the list of constant values of type number
		or string that is appropriate when $4 is a literal value */
	if ((type($4) == "string") && ($4[1]!= '\"')) {
		if (!isinlist($4, tail($1[1]))) {
			writeln("EDEN: ERROR: select has been given an "//
				 "invalid attribute.");
			return @;
		}
		else compval = getcolval($1,getcolumn($1,$4));
	}
	/* compval is the list of values resulting from column selection
		where $4 is the name of an attribute in the relation $1 */
	switch($3)
	{
		case "==" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] == compval[i])
					append tlist1,$1[i+1];
			}
			break;
		}
		case "!=" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] != compval[i])
					append tlist1,$1[i+1];
			}
			break;
		}
		case "<" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] < compval[i])
					append tlist1,$1[i+1];
			}
			break;
		}
		case "<=" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] <= compval[i])
					append tlist1,$1[i+1];
			}
			break;
		}
		case ">" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] > compval[i])
					append tlist1,$1[i+1];
			}
			break;
		}
		case ">=" :
		{
			for (i=1; i<=keys#; i++)
			{
				if (keys[i] >= compval[i])
					append tlist1,$1[i+1];
			}
			break;
		}
		default :	writeln("EDDI/P Error: not a comparison.");
				return(@);
	}
	return makedistinct(tlist1);
}

func select_wrapper {
	para tbl, pred;
	auto var, op, val, i, j;

	i = 1;

	while (i <= pred# && (isalphanum (pred[i]) || pred[i] == ' ')) i++;
	var = stripspace(substr (pred, 1, i - 1));
	j = i;
	
	while (i <= pred# && pred[i] != ' ' && !isalphanum (pred [i]) && pred[i] != '\"') i++;
	/* originally the terminating condition pred[i] == '\"' was omitted */
	op = stripspace (substr (pred, j, i - 1));
	val = converttonum (stripspace (substr (pred, i, pred#)));
	return select (tbl, var, op, val);
}
autocalc=1;

##
## Original file curragent.e (length 2560, dated Oct 10 10:04) follows...
##
%eden

/* this resets curr_agent to 0 whenever an sql query is parsed, and so ensures
	that the vanilla pivot operation is applied in eddi translation phase */
SQL0_statement is ["suffix", ";", "SQL1",
["script", ["execute", "curr_agent = 0;"], 
["declare","statement"],
["setparas",["statement"]],
["later","append SQL0_statement_list, %%;","statement"]]
];

SQL_statement is ["suffix", ";", "SQL1",
["script", ["execute", "curr_agent = 0;"],
["declare","statement"],
["setparas",["statement"]],
["later","append SQL_statement_list, %%;","statement"]]
];

SQL_to_eddi_statement is ["suffix", ";", "SQL1",
["script", ["execute", "curr_agent = 0;"],
["declare","statement"],
["setparas",["statement"]],
["later","append SQL_to_eddi_statement_list, %%;","statement"]]
];


/*
eddi_statement_1 = ["prefix", "?", "table_val", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "showrel (%%);", "relname"], ["execute", "curr_agent=1;"]], ["fail", "eddi_statement_2"]];
*/
/* For reg_exp queries rather than just table name */
eddi_statement_1 = ["prefix", "?", "rel_exp", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "showrel (%%);", "relname"], ["execute", "curr_agent = 1;"] ], ["fail", "eddi_statement_2"]];
eddi_statement_2 = ["prefix", "~", "table_name", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "droptable (%%);", "relname"], ["execute", "curr_agent = 2;"] ], ["fail", "eddi_statement_3"]];

eddi_statement_3 = ["pivot", "<<", ["table_name", "tuples"], ["script", ["declare", "relname"], ["setparas", ["relname"], []], ["later", "$$ = addvals ($$, %%);", "relname", "relname", "v_substrs[2]"], ["execute", "curr_agent = 3;"] ], ["fail", "eddi_statement_4"]];
eddi_statement_4 = ["pivot", "!!", ["table_name", "tuples"], ["script", ["declare", "relname"], ["setparas", ["relname"], []], ["later", "$$ = delvals ($$, %%);", "relname", "relname", "v_substrs[2]"], ["execute", "curr_agent = 4;"] ], ["fail", "eddi_statement_5"]];

eddi_statement_5 = ["pivot", "is", ["table_name", "rel_exp"], ["script", ["declare", "relname", "expr"], ["setparas", ["relname"], ["expr"]], ["later", "$$ is %%;", "relname", "expr"], ["execute", "curr_agent = 5;"] ], ["fail", "eddi_statement_6"]];
eddi_statement_6 = ["pivot", "(", ["table_name", "create_state"], ["script", ["declare", "relname", "cdata"], ["setparas", ["relname"], ["cdata"]], ["later", "$$ = create ($$); addtotablelist (\"$$\");", "relname", "cdata", "relname"], ["execute", "curr_agent = 6;"] ], ["fail", "eddi_statement_7"]];
 

##
## Original file newpivctn.e (length 3229, dated Nov 1 20:08) follows...
##
%eden
autocalc=0;

/*
func pivot {
        para instr, piv, ignore;
        auto i;

        i = extract (instr, piv, ignore, 1);
		if ( (i == 0)
			|| (
				((curr_agent==1) 	|| (curr_agent==5)
							|| (curr_agent==8)) &&
				( (isdigit(instr[i-1]))
					|| (i+piv#==instr#)
					|| (isdigit(instr[i+piv#+1]))
				)
			)
		)
            return [];
        else 
             return [substr(instr,1,i-1), substr(instr,i+piv#,instr#)];
}
*/

/*
func pivot {
        para instr, piv, ignore;
        auto i;

        i = extract (instr, piv, ignore, 1);
	/* consult setting of curr_agent to determine whether there is a
		possibility that '.' appears a decimal point and a rel op
		curr_agent is 1 (query), 5 (definition), 6 (assignment)
	*/
	  if (i!=0)
	  while ( (i!=0) &&
		((curr_agent==1) 	|| (curr_agent==5) || (curr_agent==6)) &&
			( (isdigit(instr[i-1])) && (i+piv#<=instr#)
					&&(isdigit(instr[i+piv#]))
			 )
	  )
	  i = extract (instr, piv, ignore, i+piv#);
	  if (i == 0)
            return [];
        else 
             return [substr(instr,1,i-1), substr(instr,i+piv#,instr#)];
}

*/

func pivot {
        para instr, piv, ignore;
        auto i;

        i = extract (instr, piv, ignore, 1);
	/* consult setting of curr_agent to determine whether there is a
		possibility that '.' appears a decimal point and a rel op
		curr_agent is 1 (query), 5 (definition), 6 (assignment)
	*/
	  if (i!=0)
	  while ( (i!=0) && (
		   (  ((curr_agent==1)||(curr_agent==5)||(curr_agent==6)) &&
			( (i>1) && (isdigit(instr[i-1])) && (i+piv#<=instr#)
							&&(isdigit(instr[i+piv#]))
			  	)
		   )
				||
				(  ((i>1) && (ischar(instr[i-1]))
					&& (ischar(instr[i]))
			 	   )
				 ||( (ischar(instr[i+piv#-1]))
					&& (i+piv#<=instr#)
					&& (ischar(instr[i+piv#]))
				   )
			  )
		)
	  )
	  i = extract (instr, piv, ignore, i+piv#);
	  if (i == 0)
            return [];
        else 
             return [substr(instr,1,i-1), substr(instr,i+piv#,instr#)];
}

/* the three versions of pivot above are a flawed pivot that distinguishes decimal point from intersect, but can this overlook intersect, a better version that finds intersect OK in any event,
and a version that also detects when a alphabetic pivot occurs in
the adjacent context of a letter, as in IN in SINNING */

func converttonum {
        para instr;
        auto i, radix, sum;
        i = instr#;
        radix = 1;
        sum = 0;

        while ((i >= 1) && (isdigit (instr [i]))) {
                        sum += ((instr [i] - '0') * radix);
                        radix = radix * 10;
		i--;
        }
        if (i==0) return sum;
         if (!isdigit(instr [i]) && (instr[i]!='.')) return instr;
        if (instr[i]=='.') sum2 = float(sum) / float(radix);
	radix = 1;
	i--;
	/* 	writeln(sum2);  */
	sum= 0;
        while (i >= 1) {
	if (!isdigit(instr[i])) return instr;
                if (isdigit (instr [i])) {
                        sum +=  ((instr [i] - '0') * radix);
                        radix = radix * 10;
		i--;
                }

        }
	/*	writeln("   ", i);  */
	return sum+sum2;
}

autocalc=1;

##
## Original file asgn.e (length 957, dated Oct 10 10:47) follows...
##
/* adding an assignment of relations to eddi, as in
	X = APPLE : PRICE > 0.25;*/

/* observe assignment before the create table clause which is identified through its
use of the round brackets.  Otherwise have problems with assignments of the form
	X = ( ... );
Statement 6 is =, statement 7 is create, statement 8 is #
*/

%eden

eddi_statement_7 = ["pivot", "(", ["table_name", "create_state"], ["script", ["declare", "relname ", "cdata"], ["setparas", ["relname"], ["cdata"]], ["later", "$$ = create ($$); addtotablelist (\"$$\");", "relname", "cdata", "relname"], ["execute", "curr_agent=7;"]], ["fail", "eddi_statement_8"]];

eddi_statement_6 = ["pivot", "=", ["table_name", "rel_exp"], ["script", ["declare", "relname", "expr"], ["setparas", ["relname"], ["expr"]], ["later", "$$ = %%;", "relname", "expr"], ["execute", "curr_agent=6;"]], ["fail", "eddi_statement_7"]];

eddi_statement_8 = ["literal", "#", ["script", ["execute", "listtables ();"]]];

##
## Original file prec.e (length 1191, dated Oct 9 17:57) follows...
##
%eden
/* this file changes the precedence of the eddi ops - giving higher precedence to * than to % and : and lowest precedence to +, - and . 
*/
rel_exp   = op_exp ('+', "rel_exp_1");
rel_exp_1 = op_exp ('-', "rel_exp_2");

rel_exp_5 = op_exp ('*', "rel_exp_6");
rel_exp_2 = op_exp ('.', "rel_exp_3");

rel_exp_3 = ["rev_pivot", "%", ["rel_exp", "attr_list"], ["script", ["declare", "expr_part", "attr_part"], ["setparas", ["expr_part"], ["attr_part"]], ["execute", "%% is " // lookupop ('%') // "(%%, %%);", "v_paras[1]", "expr_part", "attr_part"]], ["ignore", ["bras"]], ["fail", "rel_exp_4"]];
rel_exp_4 = ["rev_pivot", ":", ["rel_exp", "predicate"], ["script", ["declare", "expr_part"], ["setparas", ["expr_part"], []], ["execute", "%% is " // lookupop (':') // "(%%, ##);", "v_paras[1]", "expr_part", "v_substrs[2]"]], ["ignore", ["bras"]], ["fail", "rel_exp_5"]];

/* it overcomes the problems of parsing eddi expressions such as:

?ALLFRUITS * APPLE : BEGIN < 4;

and deals with the sql equivalent

SELECT * FROM ALLFRUITS, APPLE WHERE BEGIN < 4;

well also

More complex expressions such as

SELECT * FROM ALLFRUITS WHERE (BEGIN < 4 AND END > 8) OR BEGIN = 5;

still parse also

*/

##
## Original file catalogue.e (length 5792, dated Oct 31 08:21) follows...
##
%eddi
_CATALOGUE ( relname CHAR, reltype CHAR, defn CHAR, ptr POINTER); 

%eden

/* this line was added after type checking: it makes use of redundant fields in the relation table record that had been inappropriately used for key information */

_CATALOGUE[1][1] = ["string", "string", "string", "pointer"];  

func search_CAT {
	para tablename;
	auto cat, i, result;
	cat = _CATALOGUE;
	i= 1;
	result = 0;
	shift cat;
	while (cat!=[]) {
		i++;
		if (cat[1][1] == tablename) result = i;
		shift cat;
	}
	return result;
}

proc delrelvar {
	para tablename;
	/* name of table - as string - presumed to be in the catalogue */
	*(_CATALOGUE[search_CAT(tablename)][4]) = @;
}

eddi_statement_8 = ["literal", "#", ["script", ["execute", "curr_agent=8; showrel(CATALOGUE);"]]];

eddi_statement_1 = ["prefix", "?", "rel_exp", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "showrel (%%);", "relname"], ["execute", "curr_agent=1;"]],["fail", "eddi_statement_2"]];

/* handle this checking elsewhere in parsing rel expressions
eddi_statement_1 = ["prefix", "?", "rel_exp", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "if (search_CAT(%%)!=0) showrel (%%); else writeln(\"Table not in catalogue\");", "relname", "relname"], ["execute", "curr_agent=1;"]],["fail", "eddi_statement_2"]];
*/

eddi_statement_2 = ["prefix", "~", "table_name", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "if ((%%[1]!='_') && (search_CAT(%%)>2)) { delrelvar(%%); delete _CATALOGUE, search_CAT(%%);} else {if (search_CAT(%%)==2) writeln (\"Can't delete the catalogue\"); else writeln(\"Table / view name is not in the catalogue\");}", "relname", "relname", "relname", "relname", "relname"], ["execute", "curr_agent=2;"]], ["fail", "eddi_statement_3"]];

eddi_statement_5 = ["pivot", "is", ["table_name", "rel_exp"], ["script", ["declare", "relname", "expr"], ["setparas", ["relname"], ["expr"]], ["execute", "curr_agent=5; instr = v_string;"], ["later", "if (search_CAT(%%)==0) { $$ is %%; _CATALOGUE = addvals (_CATALOGUE, [\"$$\", \"view\", instr, &$$]); } else writeln(\"Table name already in use\");", "relname", "relname", "expr", "relname", "relname"]], ["fail", "eddi_statement_6"]];

eddi_statement_6 = ["pivot", "=", ["table_name", "rel_exp"], ["script", ["declare", "relname", "expr"], ["setparas", ["relname"], ["expr"]], ["later", "if (search_CAT(%%)==0) { $$ = %%; _CATALOGUE = addvals (_CATALOGUE, [\"$$\", \"table\", \"\", &$$]); } else writeln(\"Table name already in use\");", "relname", "relname", "expr", "relname", "relname"], ["execute", "curr_agent=6;"]], ["fail", "eddi_statement_7"]];

eddi_statement_7 = ["pivot", "(", ["table_name", "create_state"], ["script", ["declare", "relname", "cdata"], ["setparas", ["relname"], ["cdata"]], ["later", "if (search_CAT(%%)==0) { $$ = create ($$); _CATALOGUE = addvals (_CATALOGUE, [\"$$\", \"table\", \"\", &$$]); } else writeln(\"Table name already in use\");", "relname", "relname", "cdata", "relname", "relname"], ["execute", "curr_agent=7;"]], ["fail", "eddi_statement_8"]];

%eddi

CATALOGUE is _CATALOGUE % relname, reltype;

%eden

func size {
	para tblname;
	return *(_CATALOGUE[search_CAT(tblname)][4])# -1;
}

/* writeln(size("CATALOGUE")); */

func typerel {
	para tblname;
	return tail((*(_CATALOGUE[search_CAT(tblname)][4]))[1]);
}

/* writeln(typerel("CATALOGUE")); */

func typedom {
	para tblname;
	return (*(_CATALOGUE[search_CAT(tblname)][4]))[1][1];
}

/* writeln(typedom("CATALOGUE")); */

func relvartype {
	para tblname;
	return _CATALOGUE[search_CAT(tblname)][2];
}

/* writeln(relvartype("CATALOGUE")); */

func viewdefn {
	para tblname;
	return _CATALOGUE[search_CAT(tblname)][3];
}

func searchCAT {
	para tablename;
	auto cat, i, result;
	cat = CATALOGUE;
	i= 1;
	result = 0;
	shift cat;
	while (cat!=[]) {
		i++;
		if (cat[1][1] == tablename) result = i;
		shift cat;
	}
	return result;
}	

proc describe {
	para tblname;
	if (searchCAT(tblname)!= 0) {
		writeln(tblname // " is a " // relvartype(tblname));
		if (relvartype(tblname)=="view")
			writeln("\tdefn: " // viewdefn(tblname));
		write("\ttype: "); writeln(typedom(tblname));
		write("\tattr: "); writeln(typerel(tblname));
		write("\tsize: "); writeln(size(tblname));
	}
	else writeln ("There is no table or view ", tblname);
}

eddi_statement = ["suffix", ";", "eddi_statement_0", ["fail", "eddi_statement_0"]];

eddi_statement_0 = ["prefix", "??", ["describetbl"], ["fail", "eddi_statement_1"]];

describetbl = ["read_all", [], ["script", ["execute", "if (searchCAT(\"%%\")!=0) describe(\"%%\"); else writeln(\"%%\" // \" is not in the catalogue\");", "v_string", "v_string", "v_string"]]];


eddi_statement_6 = ["pivot", "=", ["table_name", "rel_exp"], ["script", ["declare", "relname", "expr"], ["setparas", ["relname"], ["expr"]], ["later", "if (search_CAT(%%)==0) { if (%%!=@) {$$ = %%; _CATALOGUE = addvals (_CATALOGUE, [\"$$\", \"table\", \"\", &$$]);} else writeln(\"Invalid assignment\"); } else writeln(\"Table name already in use\");", "relname", "expr", "relname", "expr", "relname", "relname"], ["execute", "curr_agent=6;"]], ["fail", "eddi_statement_7"]];

eddi_statement_5 = ["pivot", "is", ["table_name", "rel_exp"], ["script", ["declare", "relname", "expr"], ["setparas", ["relname"], ["expr"]], ["execute", "curr_agent=5; instr = v_string;"], ["later", "if (search_CAT(%%)==0) { if (%%!=@) {$$ is %%; _CATALOGUE = addvals (_CATALOGUE, [\"$$\", \"view\", instr, &$$]);} else writeln(\"Invalid definition\"); } else writeln(\"Table name already in use\");", "relname", "expr", "relname", "expr", "relname", "relname"]], ["fail", "eddi_statement_6"]];


##
## Original file newproject.e (length 3268, dated Oct 23 09:35) follows...
##
%eden

/* 22/10/01
WMB attempts to prevent serious errors when projection called with invalid arguments.  Now check to see whether list of attrs in projection is valid, and whether really have a table value to project from.  If invalid, returns @ rather than [[[]]]
*/

func isinlist {
	para elt, lst;
	auto result;
	result = 0;
	while(lst!=[]) {
		if (elt==lst[1]) result = 1;
		shift lst;
	}
	return result;
}

func inclist {
	para l1, l2;
	auto result;
	result = 1;
	while (l2!=[]) {
		if (!isinlist(l2[1], l1)) result = 0;
		shift l2;
	}
	return result;
}

/*

func project
/* t2 = project(t1,c_list) */
{
	auto i,j,k;
	/* writeln("Project called with pars ", $1, " ", $2); */
	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for project.");
		return @;
	} else {
		if ($1==@)
		{
			writeln("EDEN: ERROR: project has received an "//
			"undefined table.");
			return @;
		} else
			if (!inclist(tail($1[1]), $2)){
				writeln("EDEN: ERROR: invalid attribute "//
				"in projection.");
				return @;
			}
	  }
				
	tlist = [[[]]];
	
	/* For renaming attrs: c_list can contain [col_name,new_name] - ME*/
	for (i=1; i<=$2#; i++)
		if (type($2[i]) == "list")
		{
			append tlist[1],$2[i][2];
			$2[i] = $2[i][1];
		}
		else
			append tlist[1],$2[i];
			
        for (i=2; i<=$1#; i++)
                append tlist,[];
	for (i=1; i<=$2#; i++)
	{
		addcol = getcolumn($1,$2[i]);
		append tlist[1][1], $1[1][1][addcol];
		for (j=2; j<=$1#; j++)
			append tlist[j], $1[j][addcol];
	}
	return makedistinct(tlist);
}

*/

func extractattrs {
	para attrlist;
	auto result;
	result = [];
	while (attrlist != []) {
		result = result // [(type(attrlist[1])=="list")?attrlist[1][1]:attrlist[1]];
		shift attrlist;
	}
	return result;
}

func project {
        auto i,j,k,attr;

	/* project takes as its 2nd argument a single attribute name
				or an (attribute name, rename) pair  */
						 
        /* writeln("Project called with pars ", $1, " ", $2); */
        if ($#<1)
        {
                writeln("EDEN: ERROR: table not provided for project.");
                return @;
        } else {
                if ($1==@)
                {
                        writeln("EDEN: ERROR: project has received an "//
                        "undefined table.");
                        return @;
                } else	
        	    if (!inclist(tail($1[1]), extractattrs($2))) {
                        writeln("EDEN: ERROR: invalid attribute "//
              	      			"in projection.");
			return @;
        	    }
											
          }

        tlist = [[[]]];

        /* For renaming attrs: c_list can contain [col_name,new_name] - ME*/
        for (i=1; i<=$2#; i++)
                if (type($2[i]) == "list")
                {
                        append tlist[1],$2[i][2];
                        $2[i] = $2[i][1];
                }
                else
                        append tlist[1],$2[i];

        for (i=2; i<=$1#; i++)
                append tlist,[];
       
	for (i=1; i<=$2#; i++)
        {
                addcol = getcolumn($1,$2[i]);
                append tlist[1][1], $1[1][1][addcol];
                for (j=2; j<=$1#; j++)
                        append tlist[j], $1[j][addcol];
        }
        return makedistinct(tlist);
}


##
## Original file renameattrs.e (length 445, dated Oct 22 21:47) follows...
##
attr_list = ["split", ",", "col_naming", ["script", ["allparas", "attrs"], ["execute", "%% is %%;", "v_paras[1]", "attrs"]]];

col_naming = ["pivot", ">>", ["col_name", "col_name"], ["script",["declare", "nameL", "nameR"], ["setparas", ["nameL"], ["nameR"]], ["execute", "%% is [%%, %%];", "v_paras[1]", "nameL", "nameR"]], ["fail", "col_name"]]; 

col_name = ident_ex ([["script", ["execute", "%% = \"%%\";", "v_paras[1]", "v_string"]]]);

##
## Original file comment.e (length 816, dated Oct 25 22:16) follows...
##
eddi_statement = ["suffix", ";", "eddi_comment", ["fail", "eddi_comment"]];

eddi_comment = ["prefix", "##", ["anything"], ["fail", "eddi_statement_0"]];

eddi_notation = ["\n", "eddi_statement", []];

/*
eddi_comment = ["prefix", "##", ["anyline"], ["fail", "eddi_statement_0"]];

anyline = ["read_line", []];

func read_line {
	para instr;
	auto i, result;
	result = "";
	i=1;
	if (instr#>0)
		while ((i<=instr#) && (instr[i]!='\n')) {
				result = result // instr[i];
				i++;
		}
	return result;
} 

*/

/* having problems with this - with read_all comments are eating into lines until terminated by a semi-colon, and above is causing index errors. Previous attempts giving lower precedence to the match with prefix ## interfered with comments with keywords (such as 'is') in them! */

##
## Original file deps.e (length 3753, dated Nov 20 15:56) follows...
##
func dependants {
	para tblname;
	auto result, symbolinfo, currvar, ddcurrvar;
	result = [[], []];
	symbolinfo = symboldetail(tblname)[4];
	/* writeln(symboldetail(tblname)[4]); */
	if (symbolinfo!=[])
		while (symbolinfo!=[]) {
			currvar = symbolinfo[1];
			if (search_CAT(currvar)!=0)
				result[1] = result[1] // [currvar];
			else result[2] = result[2] // [currvar];
			ddcurrvar = dependants(currvar);
			result[1] = result[1] // ddcurrvar[1];
			result[2] = result[2] // ddcurrvar[2];
			shift symbolinfo;
		}
	result[1] = Makedistinct(result[1]);
	result[2] = Makedistinct(result[2]);
	return result;
}


func dependees {
	para tblname;
	auto result, symbolinfo, currvar, ddcurrvar;
	result = [[], []];
	symbolinfo = symboldetail(tblname)[5];
	/* writeln(symboldetail(tblname)[4]); */
	if (symbolinfo!=[])
		while (symbolinfo!=[]) {
			currvar = symbolinfo[1];
			if (search_CAT(currvar)!=0)
				result[1] = result[1] // [currvar];
			else result[2] = result[2] // [currvar];
			ddcurrvar = dependees(currvar);
			result[1] = result[1] // ddcurrvar[1];
			result[2] = result[2] // ddcurrvar[2];
			shift symbolinfo;
		}
	result[1] = Makedistinct(result[1]);
	result[2] = Makedistinct(result[2]);	
	return result;
}

/* Makedistinct invocation introduced here by WMB on 20/11/01 */ 

/*
proc garbage_collect {
	auto i, j, dCAT;
	for (i=3; i<=CATALOGUE#; i++) {
		dCAT = dependants(CATALOGUE[i][1]);
		writeln("i = ", i); writeln(dCAT); writeln((dCAT[2])#);
		for (j=1; j<=dCAT[2]#; j++) {
			writeln(dependants(dCAT[2][j]));
			if ((dependants(dCAT[2][j])[1])==[]) {
				writeln(dCAT[2][j]);
				
			}
		}
	}
}
*/

/* idea is to inspect the list of dependants of variables in the CATALOGUE
	that are of the form var_ ... , and perform x=x; for each one that
	has no dependant in the CATALOGUE
*/

proc garbage_collect {
	auto i, j, dCAT;
	for (i=2; i<=CATALOGUE#; i++) {
		dCAT = dependants(CATALOGUE[i][1]);
	/* 	writeln("i = ", i); writeln(dCAT); writeln((dCAT[2])#); */
		for (j=1; j<=dCAT[2]#; j++) {
	/*		writeln(dependants(dCAT[2][j]));  */
			if ((dependants(dCAT[2][j])[1])==[]) {
	/*			writeln(dCAT[2][j]);				*/
				self_asgn(dCAT[2][j]);
			}
		}
	}
}

proc self_asgn {
	para varname;
	execute (varname // "=" // varname //";");
}

/* this removes all links to var_n variables that aren't used to maintain views - could also execute forget(varname); to delete entirely */

eddi_statement = ["suffix", ";", "eddi_comment", ["script", ["later", "garbage_collect();"]], ["fail", "eddi_comment"]];

/* eliminate inappropriate dependencies after each eddi_statement */


proc describe {
	para tblname;
	if (searchCAT(tblname)!= 0) {
		writeln();
		writeln(tblname // " is a " // relvartype(tblname));
		if (relvartype(tblname)=="view")
			writeln("\tdefn: " // viewdefn(tblname));
		write("\ttype: "); writeln(typedom(tblname));
		write("\t\attr: "); writeln(typerel(tblname));
		write("\tsize: "); writeln(size(tblname));
		write("The list of views dependent on ", tblname, " is : ");
		writeln(dependants(tblname)[1]);
		writeln();
	}
	else writeln ("There is no table or view ", tblname);
}


eddi_statement_2 = ["prefix", "~", "table_name", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "if ((%%[1]!='_') && (search_CAT(%%)>2) && (dependants(%%)[1]==[])) { delrelvar(%%); delete _CATALOGUE, search_CAT(%%);} else {if (search_CAT(%%)==2) writeln (\"Can't delete the catalogue\"); else {if ((search_CAT(%%)>2) && (dependants(%%)[1]!=[])) writeln(\"Cannot delete table / view with dependants\"); else writeln(\"Table / view name is not in the catalogue\");}}", "relname", "relname", "relname", "relname", "relname", "relname", "relname", "relname"], ["execute", "curr_agent=2;"]], ["fail", "eddi_statement_3"]];


##
## Original file checktype.e (length 5671, dated Oct 31 08:05) follows...
##

/* these observation rules need not be changed - include for info:

eddi_statement_7 = ["pivot", "(", ["table_name", "create_state"], ["script", ["declare", "relname", "cdata"], ["setparas", ["relname"], ["cdata"]], ["later", "if (search_CAT(%%)==0) { $$ = create ($$); _CATALOGUE = addvals (_CATALOGUE, [\"$$\", \"table\", \"\", &$$]); } else writeln(\"Table name already in use\");", "relname", "relname", "cdata", "relname", "relname"], ["execute", "curr_agent=7;"]], ["fail", "eddi_statement_8"]];

create_state   = ["suffix", ")", "create_state_1", ["script", ["declare", "cdata"], ["setparas", ["cdata"]], ["execute", "%% is convertcols (%%);", "v_paras[1]", "cdata"]]];
create_state_1 = ["split", ",", "col_info", ["script", ["allparas", "cols"], ["execute", "%% is %%;", "v_paras[1]", "cols"]]];

col_info   = ["pivot", " ", ["col_name", "col_info_2"], ["script", ["declare", "cname", "cdata"], ["setparas", ["cname"], ["cdata"]], ["execute", "%% is [%%, %%];", "v_paras[1]", "cname", "cdata"]]];
col_info_2 = ["suffix", "key", "anything", ["script", ["execute", "%% = \"#\";", "v_paras[1]"]], ["fail", "col_info_3"]];

*/

col_info_3 = ["read_all", [], ["script", ["execute", "%% = \"%%\";", "v_paras[1]", "v_string"]]];

/* modifying col_info_3 to return the type of the domain for col */ 

/*
func create {
        auto i, tlist;
        tlist = [[[]]];
        for (i=1; i<=$#; i+=2)
        {
                append tlist[1],$[i];
                if (($[i+1] == "CHAR")||($[i+1] == "char"))
                        append tlist[1][1],"string";
                else if (($[i+1] == "REAL")||($[i+1] == "real"))
                        append tlist[1][1],"float";
                else append tlist[1][1],"int";
        }
        return tlist;
}
*/

/* for type checking in tuple introduction not to pose problems initially, must ensure that _CATALOGUE has typeseq as given by _CATALOGUE[1][1] =  ["string", "string", "string", "pointer"];  
*/

func create {
        auto i, tlist;
/*	for (i=1; i<=$#; i++) writeln($[i]);  */
        tlist = [[[]]];
        for (i=1; i<=$#; i+=2)
        {
                append tlist[1],$[i];
                if (($[i+1] == "CHAR")||($[i+1] == "char"))
                        append tlist[1][1],"string";
                else if (($[i+1] == "REAL")||($[i+1] == "real"))
                        append tlist[1][1],"float";
                else if (($[i+1] == "INT")||($[i+1] == "int"))
                        append tlist[1][1],"int";
                else if (($[i+1] == "POINTER")||($[i+1] == "pointer"))
                        append tlist[1][1],"pointer";
                else { writeln("Unrecognised type - defaults to int");
				append tlist[1][1], "int";}
        }
        return tlist;
}


/* also need to restrict add and delete tuples to views

eddi_statement_3 = ["pivot", "<<", ["table_name", "tuples"], ["script", ["declare", "relname"], ["setparas", ["relname"], []], ["later", "$$ = addvals ($$, %%);", "relname", "relname", "v_substrs[2]"]], ["fail", "eddi_statement_4"]];

*/

func istablevar {
	para tblname;
	return ((search_CAT(tblname)!=0) &&
			(CATALOGUE[search_CAT(tblname)][2]=="table"));
}

/*
writeln(istablevar("allfruits"));
writeln(istablevar("allfruit"));
writeln(istablevar("FRUITS"));
*/

eddi_statement_3 = ["pivot", "<<", ["table_name", "tuples"], ["script", ["declare", "relname"], ["setparas", ["relname"], []], ["execute", "curr_agent=3;"],["later", "if(istablevar(\"$$\")) $$ = addvals ($$, %%); else writeln(\"Can't add tuples to a view / non-existent table\");", "relname", "relname", "relname", "v_substrs[2]"]], ["fail", "eddi_statement_4"]];

eddi_statement_4 = ["pivot", "!!", ["table_name", "tuples"], ["script", ["declare", "relname"], ["setparas", ["relname"], []], ["execute", "curr_agent=4;"], ["later", "if(istablevar(\"$$\")) $$ = delvals ($$, %%); else writeln(\"Can't delete tuples from a view / non-existent table\");", "relname", "relname", "relname", "v_substrs[2]"]], ["fail", "eddi_statement_5"]];

/* eddi_statement_3 and eddi_statement_4 have been modified to prevent adding to / deleting from a view: require no further modification - only addvals needs to be changed to prevent inappropriately typed tuples from being introduced */ 

func addvals
/* table2 = addvals(t1,tup1,tup2,...,tupN) */
{
	auto i;
	
	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for addvals.");
		return [[[]]];
	} else if ($1==@)
	{
		writeln("EDEN: ERROR: addvals has received an "//
		"undefined table.");
		return [[[]]];
	}
	
        for (i=2; i<=$#; i++)
	{
		if ($1[1]#-1 == $[i]#)
		{
			if (typeseq($[i])==$1[1][1]) {
				if (notin($1,$[i])==1) {
					append $1,$[i];
				/*	writeln("Tuple added to table"); */
				} else
					writeln("EDDI/EDEN ERROR: tuple exists already.");
			} else writeln("EDEN: ERROR: Tuple of incorrect datatype");
		}
		else
			writeln("EDEN: ERROR: incorrect number of values.");
	}
	return $1;
}

/* typeseq returns the list of types of tuple elts in a list */

func typeseq {
	para tple;
	auto result;
	result = [];
	while (tple!=[]) {
		result = result // [type(tple[1])];
		shift tple;
	}
	return result;
}

func ucompatdom
/* bool = ucompat(t1,t2): union compatible on domain */
{
	return ($1[1][1] == $2[1][1]);
}

func ucompatrel
/* bool = ucompat(t1,t2): union compatible on attrname */
{
	return (tail($1[1]) == tail($2[1]));
}

/* propose to define
	ucompat(x,y) as ucompatdom(x,y) && ucompatdom(x,y);
*/

func ucompat {
	para x,y;
	return ucompatdom(x,y) && ucompatrel(x,y);
}

##
## Original file error.e (length 2401, dated Oct 31 08:03) follows...
##
eddi_statement_8 = ["literal", "#", ["script", ["execute", "curr_agent = 8; showrel (CATALOGUE);"]], ["fail", "error_unrecog"]];

error_unrecog = ["read_all", [], ["script", ["execute", "writeln(\"Unrecognised EDDI statement\");"]]];

table_name = ident_ex ([["script", ["execute", "%% = \"%%\";", "v_paras[1]", "v_string"]], ["fail", "error_tblname"]]);
table_val = ident_ex ([["script", ["execute", "if (search_CAT(%%) != 0) %% is %%; else writeln(\"Invalid table\"", "v_string", "v_paras[1]", "v_string"]], ["fail", "error_tblval"]]);

/*
table_val = ident_ex ([["script", ["execute", "%% is %%;", "v_paras[1]", "v_string"]], ["fail", "error_tblval"]]);
*/

table_val = ident_ex ([["script", ["execute", "if (search_CAT(\"%%\")!=0) %% is %%; else writeln(\"Invalid table reference\");", "v_string", "v_paras[1]", "v_string"]], ["fail", "error_tblval"]]);

error_tblval = ["read_all", [], ["script", ["execute", "writeln(\"Unrecognised table value\");"]]];
error_tblname = ["read_all", [], ["script", ["execute", "writeln(\"Unrecognised table name\");"]]];

/* other error issue addressed 27/10/01 is response to ?select; in eddi: don't invoke showrel(tblname) unless the table name is in the catalogue - modified table_val above is to fix this */

alphanum = ["read_all", [["a", "z"], ["A", "Z"], ["_"], ["0", "9"]], ["fail", "error_ident"]];
error_ident = ["read_all", [], ["script", ["execute", "writeln(\"Unrecognised EDDI identifier\");"]]];

col_name = ident_ex ([["script", ["execute", "%% = \"%%\";", "v_paras[1]", "v_string"]], ["fail", "error_col_name"]]);

error_col_name = ["read_all", [], ["script", ["execute", "writeln(\"EDDI: unrecognised column name\");"]]];

col_info   = ["pivot", " ", ["col_name", "col_info_2"], ["script", ["declare", "cname", "cdata"], ["setparas", ["cname"], ["cdata"]], ["execute", "%% is [%%, %%];", "v_paras[1]", "cname", "cdata"]], ["fail", "error_col_info"]];

error_col_info = ["read_all", [], ["script", ["execute", "writeln(\"EDDI: unrecognised column for projection\");"]]];

create_state   = ["suffix", ")", "create_state_1", ["script", ["declare", "cdata"], ["setparas", ["cdata"]], ["execute", "%% is convertcols (%%);", "v_paras[1]", "cdata"]], ["fail", "error_create_state"]];

error_create_state = ["read_all", [], ["script", ["execute", "writeln(\"EDDI: unrecognised tuple list in table create\");"]]];





##
## Original file truncate.e (length 1629, dated Oct 29 13:00) follows...
##
/* this introduces ~~X; for DROP and ~X; for TRUNCATE */

/*
eddi_statement_2 = ["prefix", "~~", "table_name", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "if ((%%[1]!='_') && (search_CAT(%%)>2)) { delrelvar(%%); delete _CATALOGUE, search_CAT(%%);} else {if (search_CAT(%%)==2) writeln (\"Can't delete the catalogue\"); else writeln(\"Table / view name is not in the catalogue\");}", "relname", "relname", "relname", "relname", "relname"], ["execute", "curr_agent=2;"]], ["fail", "eddi_statement_2a"]];
*/

eddi_statement_2a = ["prefix", "~", "table_name", ["script",
["declare", "relname"], ["setparas", ["relname"]], ["later", "if ((%%[1]!='_') && (search_CAT(%%)!=0)) {if (CATALOGUE[search_CAT(%%)][2]==\"table\") $$ = [$$[1]]; else writeln(\"Can't truncate a view\");} else writeln(\"Table / view name is not in the catalogue\");", "relname", "relname", "relname", "relname", "relname"],["execute", "curr_agent = 2;"]],["fail", "eddi_statement_3"]];

eddi_statement_2 = ["prefix", "~~", "table_name", ["script", ["declare", "relname"], ["setparas", ["relname"]], ["later", "if ((%%[1]!='_') && (search_CAT(%%)>2) && (dependants(%%)[ 1]==[])) { delrelvar(%%); delete _CATALOGUE, search_CAT(%%);} else {if (search_CAT(%%)==2) writeln (\"Can't delete the catalogue\"); else {if ((search_CAT(%%)>2) && (dependants(%%)[1]!=[])) writeln(\"Cannot delete table / view with dependants\"); else writeln(\"Table / view name is not in the catalogue\");}}", "relname", "relname", "relname", "relname", "relname", "relname", "relname", "relname"], ["execute", "curr_agent=2;"]], ["fail", "eddi_statement_2a"]];

##
## Original file unnjoin.e (length 957, dated Oct 31 23:22) follows...
##
/* this is the SQL style unnatural join that replaces natural join */

func unnjoin
{
	auto i,j,k,x,y,z;

	if ($#<2)
	{
		writeln("EDEN: ERROR: two tables not provided for njoin.");
		return @;
	} else if (($1==@) || ($2==@))
	{
		writeln("EDEN: ERROR: njoin has received at least one "//
		"undefined table.");
		return @;
	}

        tlist1 = [];
	vals1 = [];
	vals2 = [];
	nvals1 = [];
	nvals2 = [];
      append tlist1, $1[1];
	matcols = matchcols($1,$2);
	for (i=1; i<=matcols[1]#; i++) {
		$1[1][matcols[1][i]] =  $1[1][matcols[1][i]] // "_1";
		$2[1][matcols[2][i]] =  $2[1][matcols[2][i]] // "_2";
	}
	/* writeln($1[1]); */
	attr = $1[1];
	attr[1] = attr[1] // $2[1][1];
	/* writeln($2[1]); */
	for (i=2; i<=$2[1]#; i++)
          	append attr, $2[1][i];
      tlist = [attr];
	/* writeln(tlist); */
	for (x=2;x<=$1#;x++)
		for (y=2; y<=$2#; y++) {
			append tlist, ($1[x] // $2[y]);
		}
	return tlist;
}


##
## Original file uneddify.e (length 909, dated Nov 1 17:08) follows...
##

%eden
## the uneddifying interface

func ucompatdomrel {
	para x,y;
	return ucompatdom(x,y) && ucompatrel(x,y);
}

distinctvals = [1,0];
ucompatval = [ucompatdomrel, ucompatdom, ucompatrel];
joinval = ["njoin", "unnjoin"];

/* these descriptive identifiers aren't used except to initialise
	variables temporarily, but indicate
	the semantics of the various options for ucompatix etc
*/

CHECKDOMREL = 1;
CHECKDOM = 2;
CHECKREL = 3;

NODUPROWS = 1;
DUPROWS = 2;

NATJOIN = 1;
UNNATJOIN = 2;

ucompatix = CHECKDOMREL;
distinctix = NODUPROWS;
joinix = NATJOIN;

ucompat is ucompatval[ucompatix];
EDDI_distinct is distinctvals[distinctix];
EDDI_join is joinval[joinix];

operators is [[':',"select_wrapper"],['%',"project"],['.',"inter"],['*',EDDI_join],['+',"union"],['-',"diff"]];

rel_exp_5 is op_exp('*', "rel_exp_6");

proc changejoin: joinix {
	touch(&op_exp);
}

##
## Original file ignoreva.e (length 559, dated Nov 29 19:13) follows...
##
%eden

/* Fix by Ash: Ignore virtual agent statements */
eddi_comment = ["prefix", "##", ["anything"], ["fail", "eddi_virtualagent1"]];
eddi_virtualagent1 = ["prefix", ">>", ["anything"], ["fail", "eddi_virtualagent2"]];
eddi_virtualagent2 = ["prefix", "<>", ["anything"], ["fail", "eddi_virtualagent3"]];
eddi_virtualagent3 = ["prefix", "><", ["anything"], ["fail", "eddi_virtualagent4"]];
eddi_virtualagent4 = ["prefix", "<<", ["anything"], ["fail", "eddi_virtualagent5"]];
eddi_virtualagent5 = ["prefix", ">~", ["anything"], ["fail", "eddi_statement_0"]];

##
## Original file newaddvals.e (length 730, dated Nov 29 09:25) follows...
##
/* this modified version of addvals allows duplicate tuples to be added
to a table when EDDI is working in "allow duplicate tuple" evaluation mode */

func addvals
/* table2 = addvals(t1,tup1,tup2,...,tupN) */
{
	auto i;
	
	if ($#<1)
	{
		writeln("EDEN: ERROR: table not provided for addvals.");
		return @;
	} else if ($1==@)
	{
		writeln("EDEN: ERROR: addvals has received an "//
		"undefined table.");
		return @;
	}
	
        for (i=2; i<=$#; i++)
	{
		if ($1[1]#-1 == $[i]#)
		{
			if ((notin($1,$[i])==1) || EDDI_distinct==0)
				append $1,$[i];
			else
				writeln("EDDI/EDEN ERROR: tuple exists already.");
		}
		else
			writeln("EDEN: ERROR: incorrect number of values.");
	}
	return $1;
}
##
## Original file commafix.e (length 173, dated Feb 27 20:49) follows...
##
/* Allows strings to contain commas - fix by Ash 24-2-2002 */
quotes=[["\"", "\""], ["quotes"]];
addblocks("quotes");
tuple_2=["split",",","tuple_3",["ignore",["quotes"]]];
