SCHEMA express;
CONSTANT
    tx_null:		STRING	:= '?';
    tx_self:		STRING	:= 'SELF';
    tx_const_e:		STRING	:= 'CONST_E';
    tx_pi:		STRING	:= 'PI';
    tx_false:		STRING	:= 'FALSE';
    tx_true:		STRING	:= 'TRUE';
    tx_unknown:		STRING	:= 'UNKNOWN';
    tx_abs:		STRING	:= 'ABS';
    tx_acos:		STRING	:= 'ACOS';
    tx_asin:		STRING	:= 'ASIN';
    tx_atan:		STRING	:= 'ATAN';
    tx_blength:		STRING	:= 'BLENGTH';
    tx_cos:		STRING	:= 'COS';
    tx_exists:		STRING	:= 'EXISTS';
    tx_exp:		STRING	:= 'EXP';
    tx_format:		STRING	:= 'FORMAT';
    tx_hibound:		STRING	:= 'HIBOUND';
    tx_hiindex:		STRING	:= 'HIINDEX';
    tx_length:		STRING	:= 'LENGTH';
    tx_lobound:		STRING	:= 'LOBOUND';
    tx_log:		STRING	:= 'LOG';
    tx_log2:		STRING	:= 'LOG2';
    tx_log10:		STRING	:= 'LOG10';
    tx_loindex:		STRING	:= 'LOINDEX';
    tx_nvl:		STRING	:= 'NVL';
    tx_odd:		STRING	:= 'ODD';
    tx_rolesof:		STRING	:= 'ROLESOF';
    tx_sin:		STRING	:= 'SIN';
    tx_sizeof:		STRING	:= 'SIZEOF';
    tx_sqrt:		STRING	:= 'SQRT';
    tx_tan:		STRING	:= 'TAN';
    tx_typeof:		STRING	:= 'TYPEOF';
    tx_usedin:		STRING	:= 'USEDIN';
    tx_value:		STRING	:= 'VALUE';
    tx_insert:		STRING	:= 'INSERT';
    tx_remove:		STRING	:= 'REMOVE';
    int_one:		integer_literal := integer_literal(1);
END_CONSTANT;
ENTITY element;
END_ENTITY;
TYPE char = STRING(1) FIXED;
END_TYPE;
TYPE identifier = STRING;
    WHERE
	valid_identifier:	    is_identifier(SELF);
	is_not_keyword:	    NOT (uppercase(SELF) IN express_keywords());
	is_not_reserved:	    NOT (uppercase(SELF) IN express_built_in());
END_TYPE;
FUNCTION is_letter(c: char): LOGICAL;
    RETURN ({'a' <= c <= 'z'} OR {'A' <= c <= 'Z'});
END_FUNCTION;
FUNCTION is_digit(c: char): LOGICAL;
    RETURN ({'0' <= c <= '9'});
END_FUNCTION;
FUNCTION is_identifier(s: STRING): LOGICAL;
    IF NOT EXISTS(s)
    THEN
	RETURN (UNKNOWN);
    END_IF;
    REPEAT i := 1 TO LENGTH(s);
	IF is_letter(s[i]) OR
	   (is_digit(s[i]) OR s[i] = '_') AND i <> 1
	THEN
	    SKIP;
	ELSE
	    RETURN (FALSE);
	END_IF;
    END_REPEAT;
    RETURN (TRUE);
END_FUNCTION;
FUNCTION express_keywords: SET OF STRING;
    RETURN (1);
END_FUNCTION;
FUNCTION express_built_in: SET OF STRING;
    RETURN (1);
END_FUNCTION;
FUNCTION uppercase(s: STRING): STRING;
    LOCAL
	r: STRING;
    END_LOCAL;
    r := '';
    REPEAT i := 1 TO LENGTH(s);
	IF { 'a' <= s[i] <= 'z' }
	THEN
	    CASE s[i] OF
	    'a':	r := r + 'A';
	    'b':	r := r + 'B';
	    'c':	r := r + 'C';
	    'd':	r := r + 'D';
	    'e':	r := r + 'E';
	    'f':	r := r + 'F';
	    'g':	r := r + 'G';
	    'h':	r := r + 'H';
	    'i':	r := r + 'I';
	    'j':	r := r + 'J';
	    'k':	r := r + 'K';
	    'l':	r := r + 'L';
	    'm':	r := r + 'M';
	    'n':	r := r + 'N';
	    'o':	r := r + 'O';
	    'p':	r := r + 'P';
	    'q':	r := r + 'Q';
	    'r':	r := r + 'R';
	    's':	r := r + 'S';
	    't':	r := r + 'T';
	    'u':	r := r + 'U';
	    'v':	r := r + 'V';
	    'w':	r := r + 'W';
	    'x':	r := r + 'X';
	    'y':	r := r + 'Y';
	    'z':	r := r + 'Z';
	    END_CASE;
	ELSE
	    r := r + s[i];
	END_IF;
    END_REPEAT;
    RETURN (r);
END_FUNCTION;
TYPE literal_type = SELECT (integer_type, real_type, binary_type, string_type, logical_type);
END_TYPE;
ENTITY literal
    ABSTRACT SUPERTYPE OF (ONEOF(	binary_literal, integer_literal, logical_literal,
					real_literal, string_literal))
    SUBTYPE OF (expression);
	content:				literal_type;
    DERIVE
	SELF\expression.eval:		literal	    := SELF;
END_ENTITY;
ENTITY binary_literal
    SUBTYPE OF (literal);
	SELF\literal.content:			BINARY;
    DERIVE
	SELF\expression.domain:			binary_type
	    := binary_type(integer_literal(BLENGTH(content)), TRUE);
END_ENTITY;
ENTITY integer_literal
    SUBTYPE OF (literal);
	SELF\literal.content:			INTEGER;
    DERIVE
	SELF\expression.domain:			integer_type
	    := integer_type();
END_ENTITY;
ENTITY logical_literal
    SUBTYPE OF (literal);
	SELF\literal.content:			LOGICAL;
    DERIVE
	SELF\expression.domain:			logical_type
	    := logical_type();
END_ENTITY;
ENTITY real_literal
    SUBTYPE OF (literal);
	SELF\literal.content:			REAL;
    DERIVE
	SELF\expression.domain:			real_type
	    := real_type(integer_literal(real_precision(content)));
END_ENTITY;
FUNCTION trunc(n: NUMBER): INTEGER;
    RETURN (n DIV 1);
END_FUNCTION;
FUNCTION real_precision(r: REAL): INTEGER;
    LOCAL
	i: INTEGER := 0;
	p: REAL;
    END_LOCAL;
    p := r;
    REPEAT WHILE (p - trunc(p)) <> 0;
	i := i + 1;
	p := (p - trunc(p)) * 10;
    END_REPEAT;
    RETURN (i);
END_FUNCTION;
ENTITY string_literal
    SUBTYPE OF (literal);
	SELF\literal.content:			STRING;
    DERIVE
	SELF\expression.domain:			string_type
	    := string_type(integer_literal(LENGTH(content)), TRUE);
END_ENTITY;
ENTITY express_type
    ABSTRACT SUPERTYPE OF (ONEOF(simple_type, aggregation_type, constructed_type, named_type, generalized_type))
    SUBTYPE OF (element);
END_ENTITY;
ENTITY simple_type
    ABSTRACT SUPERTYPE OF (ONEOF(number_type, logical_type,indexable_type))
    SUBTYPE OF (express_type);
END_ENTITY;
ENTITY number_type
    SUPERTYPE OF (ONEOF(integer_type, real_type))
    SUBTYPE OF (simple_type);
END_ENTITY;
ENTITY real_type
    SUBTYPE OF (number_type);
	precision_spec:			OPTIONAL expression;
    WHERE
	precision_is_numeric:    numeric_expression(NVL(precision_spec, int_one));
END_ENTITY;
FUNCTION numeric_expression(x: expression): LOGICAL;
    IF NOT EXISTS(x)
    THEN
	RETURN (UNKNOWN);
    END_IF;
    IF NOT EXISTS(expression.domain)
    THEN
	RETURN (UNKNOWN);
    END_IF;
    RETURN ('INTEGER_TYPE' IN TYPEOF(expression.domain));
END_FUNCTION;
ENTITY integer_type
    SUBTYPE OF (number_type);
END_ENTITY;
ENTITY logical_type
    SUBTYPE OF (simple_type);
END_ENTITY;
ENTITY boolean_type
    SUBTYPE OF (logical_type);
END_ENTITY;
ENTITY indexable_type
    ABSTRACT SUPERTYPE OF (ONEOF(string_type, binary_type))
    SUBTYPE OF (simple_type);
	width:				OPTIONAL expression;
	is_fixed:				BOOLEAN;
    WHERE
	width_is_numeric:	    numeric_expression(NVL(width, int_one));
	fixed_needs_width:	    NOT is_fixed OR EXISTS(width);
	positive_width:		    NVL(NVL(width, int_one).eval, 1) > 0;
END_ENTITY;
ENTITY string_type
    SUBTYPE OF (indexable_type);
END_ENTITY;
ENTITY binary_type
    SUBTYPE OF (indexable_type);
END_ENTITY;
ENTITY bound_spec;
	bound1:				expression;
	bound2:				OPTIONAL expression;
    INVERSE
	aggregate_id  :	aggregation_type FOR bounds;
    WHERE
	bounds_check:	    bound1.eval <= NVL(bound2.eval, bound1.eval+1);
	for_aggregate:	    EXISTS(aggregate_id);
	cardinality_check:   cardinality_ok(SELF);
END_ENTITY;
FUNCTION cardinality_ok(b: bound_spec): LOGICAL;
    IF NOT EXISTS(b)
    THEN
	RETURN (UNKNOWN);
    END_IF;
    IF NOT EXISTS(b.aggregate_id)
    THEN
	RETURN (UNKNOWN);
    END_IF;
    IF 'ARRAY_TYPE' IN TYPEOF(b)
    THEN
	RETURN (EXISTS(b.bound2));
    ELSE
	RETURN (NVL(b.bound1.eval, 0) >= 0);
    END_IF;
END_FUNCTION;
ENTITY aggregation_type
    ABSTRACT SUPERTYPE OF (ONEOF(array_type, list_type, bag_type))
    SUBTYPE OF (express_type);
	bounds:				OPTIONAL bound_spec;
	base:				base_type;
END_ENTITY;
ENTITY array_type
    SUBTYPE OF (aggregation_type);
	SELF\aggregation_type.bounds:	bound_spec;
	is_optional:			BOOLEAN;
	is_unique:			BOOLEAN;
END_ENTITY;
ENTITY list_type
    SUBTYPE OF (aggregation_type);
	is_unique:			BOOLEAN;
END_ENTITY;
ENTITY bag_type
    SUPERTYPE OF (set_type)
    SUBTYPE OF (aggregation_type);
END_ENTITY;
ENTITY set_type
    SUBTYPE OF (bag_type);
END_ENTITY;
ENTITY named_type
    SUBTYPE OF (reference_id, express_type);
    WHERE
	is_entity_or_type:    reference_check(SELF, ['ENTITY_DECL', 'TYPE_DECL']);
END_ENTITY;
TYPE string_tree_node = SELECT (string_literal, string_tree);
END_TYPE;
TYPE string_tree = LIST OF string_tree_node;
END_TYPE;
FUNCTION reference_check(r: reference_id; t: string_tree): LOGICAL;
    IF NOT EXISTS(r) OR NOT EXISTS(t)
    THEN
	RETURN (UNKNOWN);
    END_IF;
    IF NOT EXISTS(r.resolution)
    THEN
	RETURN (UNKNOWN);
    END_IF;
    RETURN (rec_reference_check(TYPEOF(r.resolution), t, TRUE));
END_FUNCTION;
FUNCTION rec_reference_check(r: SET OF STRING; t: string_tree; b: BOOLEAN): LOGICAL;
    LOCAL
	res:	LOGICAL := NOT b;
    END_LOCAL;
    IF SIZEOF(t) = 0
    THEN
	RETURN (FALSE);
    END_IF;
    REPEAT i := 1 TO SIZEOF(t);
	IF b
	THEN
	    IF 'LIST' IN TYPEOF(t[i])
	    THEN
		res := res OR rec_reference_check(r, t[i], NOT b);
	    ELSE
		res := res OR (t[i] IN r);
	    END_IF;
	ELSE
	    IF 'LIST' IN TYPEOF(t[i])
	    THEN
		res := res AND rec_reference_check(r, t[i], NOT b);
	    ELSE
		res := res AND (t[i] IN r);
	    END_IF;
	END_IF;
    END_REPEAT;
    RETURN (res);
END_FUNCTION;
ENTITY constructed_type
    ABSTRACT SUPERTYPE OF (ONEOF(enumeration_type, select_type))
    SUBTYPE OF (express_type);
END_ENTITY;
ENTITY enumeration_value_spec
    SUBTYPE OF (declaration);
END_ENTITY;
ENTITY enumeration_type
    SUBTYPE OF (constructed_type, scope);
	elements:			LIST [1:?] OF UNIQUE identifier;
    DERIVE
	SELF\scope.local_decls:	SET OF enumeration_value_spec
	    := enumeration_value_set(elements);
END_ENTITY;
FUNCTION enumeration_value_set(l: LIST [1:?] OF UNIQUE identifier):
						SET OF enumeration_value_spec;
    LOCAL
	s: SET OF enumeration_value_spec := [];
    END_LOCAL;
    REPEAT i := 1 TO SIZEOF(l);
       s := s + [enumeration_value_spec(l[i])];
    END_REPEAT;
    RETURN (s);
END_FUNCTION;
ENTITY select_type
    SUBTYPE OF (constructed_type);
	named_types:			LIST [1:?] OF UNIQUE identifier;
 
END_ENTITY;
ENTITY generalized_type
    ABSTRACT SUPERTYPE OF (ONEOF(aggregate_type, general_aggregation_type, generic_type))
    SUBTYPE OF (express_type);
END_ENTITY;
TYPE base_type = SELECT (aggregation_type, simple_type, named_type);
END_TYPE;
TYPE parameter_type = SELECT (generalized_type, named_type, simple_type);
END_TYPE;
FUNCTION reference_is_type_ref(t: underlying_type): LOGICAL;
    IF NOT EXISTS(t)
    THEN
	RETURN (UNKNOWN);
    END_IF;
    IF NOT ('REFERENCE' IN TYPEOF(t))
    THEN
	RETURN (TRUE);
    END_IF;
    IF NOT EXISTS(t.resolution)
    THEN
	RETURN (UNKNOWN);
    END_IF;
    RETURN ('TYPE_DECL' IN TYPEOF(t.resolution));
END_FUNCTION;
TYPE underlying_type = SELECT (constructed_type, aggregation_type, simple_type);
END_TYPE;
ENTITY constrained_decl
    ABSTRACT SUPERTYPE OF (ONEOF(type_decl, entity_decl, rule_decl))
    SUBTYPE OF (declaration);
	constraints:			OPTIONAL where_clause;
END_ENTITY;
ENTITY type_decl
    SUBTYPE OF (constrained_decl);
	domain:				underlying_type;
END_ENTITY;
ENTITY labelled_logic_expr;
	label:				OPTIONAL identifier;
	logical_expr:			expression;
END_ENTITY;
ENTITY where_clause
    SUBTYPE OF (local_rule);
	domain_rules:			SET [1:?] OF labelled_logic_expr;
    INVERSE
	target_decl:			constrained_decl FOR constraints;
END_ENTITY;
ENTITY entity_decl
    SUBTYPE OF (constrained_decl, scope);
	local_attrs:			LIST OF UNIQUE attribute_decl;
	instantiable:			BOOLEAN;
	supertype_names:		LIST OF identifier;
	subtype_expr:			OPTIONAL subtype_expression;
	unique_rule:			OPTIONAL unique_clause;
    DERIVE
	SELF\scope.local_decls:	SET OF attribute_decl    := setof(local_attrs);
END_ENTITY;
FUNCTION list_of_refs(l: LIST OF identifier): LIST OF reference_id;
    LOCAL
	r: LIST OF reference_id := [];
    END_LOCAL;
    IF NOT EXISTS(l)
    THEN
	RETURN (?);
    END_IF;
    REPEAT i := 1 TO SIZEOF(l);
	r := r + [reference_id(l[i])];
    END_REPEAT;
    RETURN (r);
END_FUNCTION;
FUNCTION setof(l: AGGREGATE OF GENERIC: t): SET OF GENERIC: t;
    LOCAL
	s: SET OF GENERIC: t;
    END_LOCAL;
    REPEAT i := LOINDEX(l) TO HIINDEX(l);
       s := s + [l[i]];
    END_REPEAT;
    RETURN (s);
END_FUNCTION;
ENTITY attribute_decl
    ABSTRACT SUPERTYPE OF (ONEOF(explicit_attr, derived_attr, inverse_attr))
    SUBTYPE OF (declaration);
	domain:				base_type;
	group_name:			OPTIONAL identifier;
    DERIVE
	group_ref:			reference_id := reference_id(group_name);
    WHERE
	reference_check:	    NOT EXISTS(group_name) OR
	    reference_check(group_ref, ['ENTITY_DECL']);
END_ENTITY;
ENTITY explicit_attr
    SUBTYPE OF (attribute_decl);
	mandatory:			BOOLEAN;
END_ENTITY;
ENTITY derived_attr
    SUBTYPE OF (attribute_decl);
	rvalue:				expression;
END_ENTITY;
ENTITY inv_cardinality;
	is_unique:			BOOLEAN;
	bounds:				OPTIONAL bound_spec;
END_ENTITY;
ENTITY inverse_attr
    SUBTYPE OF (attribute_decl);
	entity_ref:			reference_id;
	attribute_ref:			identifier;
	cardinality:			OPTIONAL inv_cardinality;
END_ENTITY;
ENTITY local_rule
    ABSTRACT SUPERTYPE OF (ONEOF(unique_clause, where_clause))
    SUBTYPE OF (element);
END_ENTITY;
ENTITY labelled_attrib_list;
	label:				OPTIONAL identifier;
	attributes:			LIST [1:?] OF attribute_decl;
    INVERSE
	source_unique:			unique_clause FOR constraints;
	WHERE
	attribute_check: SIZEOF(QUERY(attr <* attributes | NOT (attr IN source_unique.target_entity.local_decls))) = 0;
END_ENTITY;
ENTITY unique_clause
    SUBTYPE OF (local_rule);
	constraints:			SET [1:?] OF labelled_attrib_list;
    INVERSE
	target_entity:			entity_decl FOR unique_rule;
END_ENTITY;
ENTITY subtype_expression
	SUBTYPE OF (element);
	subtypes:			SET OF identifier;
END_ENTITY;
ENTITY schema_decl
    SUBTYPE OF (scope, declaration);
	dependencies:			LIST OF schema_interface;
END_ENTITY;
ENTITY constant_decl
    SUBTYPE OF (declaration);
	domain:				base_type;
	rvalue:				expression;
END_ENTITY;
ENTITY algorithm
    ABSTRACT SUPERTYPE OF (ONEOF(function_decl, procedure_decl, rule_decl))
    SUBTYPE OF (scope);
	programation	:		LIST OF statement; 
END_ENTITY;
ENTITY function_decl
    SUBTYPE OF (declaration, algorithm);
END_ENTITY;
ENTITY procedure_decl
    SUBTYPE OF (declaration, algorithm);
END_ENTITY;
ENTITY aggregate_type
    SUBTYPE OF (generalized_type);
	label:				OPTIONAL type_label;
	type_of:				parameter_type;
END_ENTITY;
ENTITY generic_type
    SUBTYPE OF (generalized_type);
	label:				OPTIONAL type_label;
END_ENTITY;
ENTITY general_aggregation_type
    ABSTRACT SUPERTYPE OF (ONEOF(general_array_type, general_bag_type, general_list_type, general_set_type))
    SUBTYPE OF (generalized_type);
	bounds:				OPTIONAL bound_spec;
	base:				parameter_type;
END_ENTITY;
ENTITY general_array_type
    SUBTYPE OF (general_aggregation_type);
	SELF\general_aggregation_type.bounds:	bound_spec;
	is_optional:			BOOLEAN;
	is_unique:			BOOLEAN;
    WHERE
	exists_bound2:			EXISTS(bounds.bound2);
END_ENTITY;
ENTITY general_bag_type
    SUBTYPE OF (general_aggregation_type);
	SELF\general_aggregation_type.bounds:	OPTIONAL bound_spec;
END_ENTITY;
ENTITY general_list_type
    SUBTYPE OF (general_aggregation_type);
	SELF\general_aggregation_type.bounds:	OPTIONAL bound_spec;
	is_unique:			BOOLEAN;
END_ENTITY;
ENTITY general_set_type
    SUBTYPE OF (general_aggregation_type);
	SELF\general_aggregation_type.bounds:	OPTIONAL bound_spec;
END_ENTITY;
ENTITY type_label
    SUBTYPE OF (declaration);
	domain:				generalized_type;
END_ENTITY;
ENTITY variable_decl
    ABSTRACT SUPERTYPE OF (ONEOF(local_decl, proc_par_decl, rule_par_decl))
    SUBTYPE OF (declaration);
	domain:				parameter_type;
END_ENTITY;
ENTITY local_decl
    SUBTYPE OF (variable_decl);
	initialization:			OPTIONAL expression;
END_ENTITY;
ENTITY proc_par_decl
    SUPERTYPE OF (func_par_decl)
    SUBTYPE OF (variable_decl);
	is_reference:			BOOLEAN;
END_ENTITY;
ENTITY func_par_decl
    SUBTYPE OF (proc_par_decl);
    DERIVE
	SELF\proc_par_decl.is_reference:	BOOLEAN	    := FALSE;
END_ENTITY;
ENTITY rule_par_decl
    SUBTYPE OF (variable_decl);
END_ENTITY;
ENTITY rule_decl
    SUBTYPE OF (constrained_decl, algorithm);
	domain:				LIST OF identifier;
	SELF\constrained_decl.constraints: where_clause;
END_ENTITY;

ENTITY scope
    ABSTRACT SUPERTYPE OF (ONEOF(enumeration_type, entity_decl, schema_decl, algorithm))
    SUBTYPE OF (element);		
	local_decls:			SET OF declaration;
    DERIVE
	all_decls:			SET OF declaration := local_decls;
END_ENTITY;
ENTITY declaration
    ABSTRACT SUPERTYPE OF (ONEOF(constant_decl, 
type_label, 
variable_decl, 
attribute_decl,
 function_decl,
 procedure_decl, 
schema_decl, 
constrained_decl
))
    SUBTYPE OF (element);
	name:				identifier;
    INVERSE
	scope:				scope FOR local_decls;
	referenced:			BAG OF reference_id FOR resolution;
    UNIQUE
	unique_names:			name, scope;
END_ENTITY;
ENTITY reference_id
    ABSTRACT SUPERTYPE OF (ONEOF(named_type, schema_ref, external_ref))
    SUBTYPE OF (expression);
	name:				identifier;
	scope:				scope;	
	resolution:			OPTIONAL declaration;
END_ENTITY;
ENTITY schema_ref
    SUPERTYPE OF (schema_interface)
    SUBTYPE OF (reference_id);
	SELF\reference_id.resolution:	OPTIONAL schema_decl;
END_ENTITY;
ENTITY schema_interface
    SUBTYPE OF (schema_ref);
	imports:			SET OF external_ref;
    INVERSE
	for_schema:		schema_decl FOR dependencies;
END_ENTITY;
ENTITY external_ref
    ABSTRACT SUPERTYPE OF (ONEOF(use_decl, reference_decl))
    SUBTYPE OF (declaration, reference_id);
	rename:				OPTIONAL identifier;
    DERIVE
	SELF\declaration.name:		identifier:= NVL(rename, SELF\reference_id.name);
    INVERSE
	interface:			schema_interface FOR imports;
END_ENTITY;
ENTITY use_decl
    SUBTYPE OF (external_ref);
	SELF\reference_id.resolution:	OPTIONAL named_type;
END_ENTITY;
ENTITY reference_decl
    SUBTYPE OF (external_ref);
END_ENTITY;
ENTITY expression
    ABSTRACT SUPERTYPE OF (ONEOF(literal, reference_id, operation))
    SUBTYPE OF (element);
	domain:				OPTIONAL express_type;
	eval:				OPTIONAL expression;
END_ENTITY;
ENTITY operation
    ABSTRACT SUPERTYPE OF (ONEOF(unary_op, binary_op, ternary_op, n_ary_op))
    SUBTYPE OF (expression);
	operands:			LIST [0:?] OF expression;
	    DERIVE
	arity:		INTEGER	    := SIZEOF(SELF\operation.operands);
END_ENTITY;
ENTITY unary_op
    ABSTRACT SUPERTYPE OF (ONEOF(pos_op, neg_op, not_op))
    SUBTYPE OF (operation);
	operand:			expression;
    DERIVE
	SELF\operation.operands:	LIST [1:1] OF expression	    := [operand];
END_ENTITY;
ENTITY binary_op
    ABSTRACT SUPERTYPE OF (ONEOF(
	lesser_op,	greater_op,	lesseql_op,	greateql_op,
	differ_op,	equal_op,	instdiff_op,	insteql_op,
	in_op,		like_op,
	add_op,		sub_op,		or_op,		xor_op,
	mul_op,		rdiv_op,		idiv_op,		mod_op,
	and_op,		complex_op,
	exp_op,		index_op,	ref_op,		group_op))
    SUBTYPE OF (operation);
	operand1:			expression;
	operand2:			expression;
    DERIVE
	SELF\operation.operands:	LIST [1:2] OF expression	    := [operand1, operand2];
END_ENTITY;
ENTITY ternary_op
    ABSTRACT SUPERTYPE OF (ONEOF(subidx_op, query_op))
    SUBTYPE OF (operation);
	operand1:			expression;
	operand2:			expression;
	operand3:			expression;
    DERIVE
	SELF\operation.operands:	LIST [1:3] OF expression	    := [operand1, operand2, operand3];
END_ENTITY;
ENTITY n_ary_op
    ABSTRACT SUPERTYPE OF (ONEOF(fcall_op, aggri_op, interv_op))
    SUBTYPE OF (operation);
END_ENTITY;
TYPE rel_op = SELECT (lesser_op, greater_op, lesseql_op, greateql_op, differ_op, equal_op, instdiff_op, insteql_op); END_TYPE;
TYPE rel_op_extended = SELECT (rel_op, in_op, like_op);
END_TYPE;
TYPE add_like_op = SELECT (add_op, sub_op, or_op, xor_op);
END_TYPE;
TYPE multiplication_like_op = SELECT (mul_op, rdiv_op, idiv_op, mod_op, and_op, complex_op);
END_TYPE;
ENTITY pos_op
    SUBTYPE OF (unary_op);
    DERIVE
	op_type:		LIST [1:?] OF express_type	    := [number_type];
END_ENTITY;
ENTITY neg_op
    SUBTYPE OF (unary_op);
    DERIVE
	op_type:		LIST [1:?] OF express_type	    := [number_type];
END_ENTITY;
ENTITY not_op
    SUBTYPE OF (unary_op);
    DERIVE
	op_type:		LIST [1:?] OF express_type	    := [logical_type];
END_ENTITY;
ENTITY lesser_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY greater_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY lesseql_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY greateql_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY differ_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY equal_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY instdiff_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY insteql_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY in_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY like_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY add_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY sub_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY or_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY xor_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY mul_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY rdiv_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY idiv_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY mod_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY and_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY complex_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY exp_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY index_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY ref_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY group_op
    SUBTYPE OF (binary_op);
END_ENTITY;
ENTITY subidx_op
    SUBTYPE OF (ternary_op);
END_ENTITY;
ENTITY query_op
    SUBTYPE OF (ternary_op);
END_ENTITY;
ENTITY fcall_op
    SUBTYPE OF (n_ary_op);
END_ENTITY;
ENTITY aggri_op
    SUBTYPE OF (n_ary_op);
END_ENTITY;
ENTITY interv_op
    SUBTYPE OF (n_ary_op);
END_ENTITY;
ENTITY statement
    ABSTRACT SUPERTYPE OF (ONEOF(
	alias_stmt,	assignment_stmt,case_stmt,	compound_stmt,
	escape_stmt,	if_stmt,	null_stmt,	procedure_call_stmt,
	repeat_stmt,	return_stmt,	skip_stmt));
END_ENTITY;
ENTITY null_stmt
    SUBTYPE OF (statement);
END_ENTITY;
ENTITY alias_stmt
    SUBTYPE OF (statement, declaration);
	lvalue:				expression;
	stmts:				LIST [1:?] OF statement;
END_ENTITY;
ENTITY assignment_stmt
    SUBTYPE OF (statement);
    	lvalue:				expression;
    	rvalue:				expression;
END_ENTITY;
ENTITY case_action;
	case_labels:			LIST [1:?] OF expression;
	stmt:				statement;
END_ENTITY;
ENTITY case_stmt
    SUBTYPE OF (statement);
	case_actions:			LIST OF case_action;
	otherwise_stmt:			OPTIONAL statement;
END_ENTITY;
ENTITY compound_stmt
    SUBTYPE OF (statement);
	stmts:				LIST [1:?] OF statement;
END_ENTITY;
ENTITY escape_stmt
    SUBTYPE OF (statement);
END_ENTITY;
ENTITY if_stmt
    SUBTYPE OF (statement);
	logical_expression:		expression;
	then_stmts:			LIST [1:?] OF statement;
	else_stmts:			LIST OF statement;
END_ENTITY;
ENTITY procedure_call_stmt
    SUBTYPE OF (statement);
	procedure_name:			identifier;
	actual_parameters:		LIST OF expression;
END_ENTITY;
ENTITY repeat_stmt
    SUBTYPE OF (statement);
	increment_control:		OPTIONAL increment_control;
	while_control:			OPTIONAL while_control;
	until_control:			OPTIONAL until_control;
	stmts:				LIST [1:?] OF statement;
END_ENTITY;
ENTITY increment_control;
	bound1:				expression;
	bound2:				expression;
	increment:			OPTIONAL expression;
END_ENTITY;
ENTITY while_control;
	logical_expression:		expression;
END_ENTITY;
ENTITY until_control;
	logical_expression:		expression;
END_ENTITY;
ENTITY return_stmt
    SUBTYPE OF (statement);
	expression:			expression;
END_ENTITY;
ENTITY skip_stmt
    SUBTYPE OF (statement);
END_ENTITY;
END_SCHEMA;