SCHEMA ISO13584_generic_expressions_schema;

ENTITY generic_expression
ABSTRACT SUPERTYPE OF(ONEOF(simple_generic_expression,
								unary_generic_expression,
								binary_generic_expression,
								multiple_arity_generic_expression));
WHERE 
	WR1: is_acyclic(SELF);
END_ENTITY;

ENTITY simple_generic_expression
ABSTRACT SUPERTYPE OF (ONEOF(generic_literal, generic_variable))
SUBTYPE OF (generic_expression);
END_ENTITY;

ENTITY generic_literal
ABSTRACT SUPERTYPE
SUBTYPE OF (simple_generic_expression);
END_ENTITY; 

ENTITY generic_variable
ABSTRACT SUPERTYPE
SUBTYPE OF (simple_generic_expression);
INVERSE
	interpretation :
			environment FOR syntactic_representation;
END_ENTITY;

ENTITY variable_semantics
ABSTRACT SUPERTYPE;
END_ENTITY;

ENTITY environment;
	syntactic_representation: generic_variable;
	semantics: variable_semantics;
END_ENTITY;

ENTITY unary_generic_expression
ABSTRACT SUPERTYPE
SUBTYPE OF(generic_expression);
	operand: generic_expression;
END_ENTITY;

ENTITY binary_generic_expression
ABSTRACT SUPERTYPE
SUBTYPE OF(generic_expression);
	operands: LIST [2:2] OF generic_expression;
END_ENTITY;

ENTITY multiple_arity_generic_expression
ABSTRACT SUPERTYPE
SUBTYPE OF(generic_expression);
	operands: LIST [2:?] OF generic_expression;
END_ENTITY;

FUNCTION is_acyclic (arg: generic_expression): BOOLEAN;
RETURN (acyclic (arg, []));
END_FUNCTION ; -- is_acyclic

FUNCTION acyclic (arg1: generic_expression; 
			arg2: SET OF generic_expression): BOOLEAN;

LOCAL
	result: BOOLEAN;
END_LOCAL;

IF ('ISO13584_GENERIC_EXPRESSIONS_SCHEMA.SIMPLE_GENERIC_EXPRESSION'
	IN TYPEOF (arg1)) 
THEN
	RETURN (TRUE);
END_IF;

IF arg1 IN arg2 
THEN 
	RETURN (FALSE);
END_IF;

IF 'ISO13584_GENERIC_EXPRESSIONS_SCHEMA.UNARY_GENERIC_EXPRESSION' 
	IN TYPEOF (arg1) 
THEN 
	RETURN 
	(acyclic(arg1\unary_generic_expression.operand,arg2+[arg1]));
END_IF;

IF 'ISO13584_GENERIC_EXPRESSIONS_SCHEMA.BINARY_GENERIC_EXPRESSION' 
	IN TYPEOF (arg1) 
THEN 
	RETURN 
	(acyclic(arg1\binary_generic_expression.operands[1],arg2+[arg1])
	AND
	acyclic(arg1\binary_generic_expression.operands[2],arg2+[arg1]));
END_IF;

IF 
'ISO13584_GENERIC_EXPRESSIONS_SCHEMA.MULTIPLE_ARITY_GENERIC_EXPRESSION' 
	IN TYPEOF (arg1) 
THEN 
	result := TRUE;
	REPEAT i := 1 TO 
			SIZEOF (arg1\multiple_arity_generic_expression.operands);
		result := result AND
		acyclic(arg1\multiple_arity_generic_expression.operands[i], arg2+[arg1]);
	END_REPEAT;

	RETURN (result);
END_IF;

END_FUNCTION; -- acyclic

FUNCTION used_variables (arg : generic_expression) : 
			SET OF generic_variable;

LOCAL
	result : SET OF generic_variable := [];
END_LOCAL;

IF 'ISO13584_GENERIC_EXPRESSIONS_SCHEMA.GENERIC_VARIABLE' 
	IN TYPEOF (arg) 
THEN 
	RETURN ([arg]);
END_IF;

IF 'ISO13584_GENERIC_EXPRESSIONS_SCHEMA.UNARY_GENERIC_EXPRESSION' 
	IN TYPEOF (arg)
THEN 
	RETURN (used_variables (arg\unary_generic_expression.operand));
END_IF;

IF 'ISO13584_GENERIC_EXPRESSIONS_SCHEMA.BINARY_GENERIC_EXPRESSION'
	IN TYPEOF (arg)
THEN 
	RETURN(used_variables(arg\binary_generic_expression.operands[1])
		+ used_variables (arg\binary_generic_expression.operands[2]));
END_IF;

IF
'ISO13584_GENERIC_EXPRESSIONS_SCHEMA.MULTIPLE_ARITY_GENERIC_EXPRESSION' 
	IN TYPEOF (arg)
THEN
	REPEAT i := 1 TO 
		SIZEOF(arg\multiple_arity_generic_expression.operands);
		result := result + used_variables(
			arg\multiple_arity_generic_expression.operands[i]);
	END_REPEAT;
	
	RETURN (result);
END_IF;
RETURN ([ ]);      -- in this case the subtype shall not contain
			            -- any variable (see IP1 in generic_expression)
END_FUNCTION; -- used_variables

END_SCHEMA; 
