RUReReAD can automatically detect all relationships between requirements according to rules that user defined. RUReReAD provides an easy-learning formal language to enable user to write their own definitions of various kinds of requirements, and their detection rules of relationships. RUReReAD can traversal all requirements to detect relationships automatically with a nice performance.
User should use it by 4 steps:
- Input definitions of requirements' models in file model.txt. Specific syntax rules are shown below.
- Input definitions of relationships recognition rules in file rule.txt. Specific syntax rules are shown below.
- Input requirements to be detected in file requirement.json.
- Run main function in file api.Main.java.
The syntax of language is familiar to other programming language, there can be any number of space or newline between tokens. However, there should be no space in an identifier.
All identifiers should be consisted of 26 letters (both upper and lower) and _, and can not use these keywords:
boolean, integer, float, string, list, set, map, type, requirement, rule, function,
size_of, is_null, and, or, not, all, any, max, min, synonym, antonym, include, merge, from, to, find, substring
A requirement model is consisted of all semantic elements, including their names and types. Users can define requirement models, like:
requirement <requirement_name> {
<element_name_1> <element_type_1> [= <default_value>] ;
<element_name_2> <element_type_2> [= <default_value>] ;
...
}
The <requirement_name> and <element_name> are identifiers.
The <default_value> is a value of type <element_type>, which represent the default value of this field.
For basic types, it fit this format.
For customized types, it should be the ID of the entity.
The <element_type> is a type signature, which has 3 conditions:
- basic types:
boolean:trueorfalse, the default isfalse;integer: range from -2147483648 to 2147483647, the default is 0;float: double float value, the default is 0.0;string: any string like Java String, the default is empty string"";
- collection types:
listsetmap, the default is emptylist: an array of elements in a same type with a specific order, for examplelist<string>set: a set of elements in a same type without any order, for exampleset<integer>map: a reflection relationship from one type to another, also without any order, for examplemap<integer, string>
- user-defined types: a type defined by users, using syntax like:
The default is
type <type_name> { <field_name_1> <field_type_1> ; <field_name_2> <field_type_2> ; ... }null.
Notice: user-defined types should be defined before used.
The EBNF formats are:
| Nonterminal Character | Definition |
|---|---|
<requirements_definitions> |
{ { <requirement_definition> }+ { <type_definition> } } |
<requirement_definition> |
requirement <definition> |
<type_definition> |
type <definition> |
<definition> |
<identifier> '{' <element_definition> '}' |
<element_definition> |
{ <element_name> <element_type> ; }+ |
<element_name> |
<identifier> |
<element_type> |
<base_type> | <collection_type> | <user-defined_type> |
<default_value> |
<boolean> | <integer> | <float> | <string> |
<basic_type> |
boolean | integer | float | string |
<collection_type> |
<list_type> | <set_type> | <map_type> |
<list_type> |
list '<' <element_type> '>' |
<set_type> |
set '<' <element_type> '>' |
<map_type> |
map '<' <element_type> , <element_type> '>' |
<user-defined_type> |
<identifier> |
A recognition rule of requirement relationship is defined like:
rule <rule_name> (<parameters_list>) -> boolean {
<logic_body>
}
<rule_name> is an identifier.
<parameters_list> is a list of parameter types, separated by ,, like: type1, type2, type3.
<logic_body> is the main part of the rule, specific syntax will be introduced later.
Besides, for a 2 parameters rule with the same requirement type, user can define it as a reversible rule to eliminate the duplicated judgement.
For example, paras (req1, req2) and paras (req2, req1) are same to reversible rule.
The definition format is to replace rule at beginning with revrule.
Users can also define some functions to simplify rules, like:
function <function_name> (<parameters_list>) -> <return_type> {
<field_name_1> : {
<logic_body_2>
};
<field_name_2> : {
<logic_body_2>
};
...
}
<function_name> is identifier.
<return_type> is the type of return value, which only be basic types and user-defined types.
If <return_type> is a basic type, definition can be written like rule's as:
function <function_name> (<parameters_list>) -> <basic_return_type> {
<logic_body>
}
However, there is a difference of <parameters_list>: user can define different types of one parameter, like: type1, type2 / type3, type4.
It means the two parameters can be type1 and type2, or type3 and type4.
<logic_body> is consisted of a nested <element>, whose type is the <return_type>.
An <element> has many conditions:
- single element: parameter, variable, field of entity, list or map getting
- operator statement: unary operator statement, binary operator statement, multi-para operator statement, loop statement, string statement
- user-define function statement: statement of calling function defined by users
- literal type: such as:
true,666,0.1,"hello" - parameter:
% <parameter_order_number> %, for example,%2%means the 2nd parameter - variable: use the identifier defined before
- field of entity:
<entity>.<field_name>, for example,ele.fmeans fieldfinele - list or map getting:
<collection> [ <index> ], for example,list_demo[3]means the 3rd element inlist_demo
The format is: { <unary_symbol> <element> }, for example: {-2}, {! boolean_value}.
Notice: '{' and '}' can not be omitted.
All unary operators are:
| Operator | Symbol | Parameter Type | Return Type | Meaning |
|---|---|---|---|---|
| logical not | ! | boolean | boolean | calculate not logic |
| opposite number | - | integer / float | same as parameter | calculate the opposite number |
| collection size | size_of | list / set / map | integer | count the size of collection |
| check nullable | is_null | any user-defined type | boolean | whether the entity is null |
The format is: { <element> <binary_symbol> <element> }, for example: {3 + 2}, {true or false}.
Notice: '{' and '}' can not be omitted.
All binary operators are:
| Operator | Symbol | Parameters Type | Return Type | Meaning |
|---|---|---|---|---|
| number addition | + | both integer / float | float if has float, otherwise integer | calculate plus |
| number subtraction | - | both integer / float | float if has float, otherwise integer | calculate sub |
| number multiplication | * | both integer / float | float if has float, otherwise integer | calculate multiple |
| number division | / | both integer / float | float if has float, otherwise integer | calculate divide |
| logical and | and | both boolean | boolean | calculate and logic |
| logical or | or | both boolean | boolean | calculate or logic |
| equal relation | == | any same type | boolean | whether the two elements are equal |
| not equal relation | != | any same type | boolean | whether the two elements are not equal |
| greater relation | > | both integer / float | boolean | whether the former is greater than the latter |
| less relation | < | both integer / float | boolean | whether the former is less than the latter |
| not less relation | >= | both integer / float | boolean | whether the former is not less than the latter |
| not greater relation | <= | both integer / float | boolean | whether the former is not greater than the latter |
| collection include | include | same type of list / set / map | boolean | whether all elements of the latter are in the former |
| collection in | in | element_type + collection_type | boolean | whether the element is in the collection (keys of map) |
| set intersection | inter | same type of set | set | calculate the intersection of the two sets |
| set union | union | same type of set | set | calculate the union of the two sets |
| synonym words | synonym | both string | boolean | whether the two strings are synonyms |
| antonym words | antonym | both string | boolean | whether the two strings are antonyms |
The format is: <symbol> ( <element>, <element>, ... ), in which <element>s are separated by ,.
There can be at least one <element>. In this case, however, <symbol> has no effect.
Therefore, there are usually two or more <element>s.
For example, + (1, 2, 3, 4), merge (list_1, liet_2).
All multi-para operators are:
| Operator | Symbol | Parameters Type | Return Type | Meaning |
|---|---|---|---|---|
| summation of numbers | + | all integer / float | float if has float, otherwise integer | calculate the summation of all numbers |
| product of numbers | * | all integer / float | float if has float, otherwise integer | calculate the product of all numbers |
| maximum | max | all integer / float | float if has float, otherwise integer | maximum of all numbers |
| minimum | min | all integer / float | float if has float, otherwise integer | minimum of all numbers |
| logical and | and | all boolean | boolean | calculate and of all boolean values |
| logical or | or | all boolean | boolean | calculate or of all boolean values |
| collection merge | merge | same type of list / set / map | same as parameters | merge all collections into one |
The format is: <function_name> (<element>, <element>, ...), like multi-para operator statement, in which <element>s are separated by ,.
The number of <element> depends on the definition of function.
For example, function_1(para1, para2).
<function_name> is identifiers.
Notice: functions should be defined before, then can be used.
The loop format is: for <quantifier> <loop_variable> <range> '(' <loop_statement> ')'.
<quantifier> has 2 conditions: any (existential quantification) or all(universal quantification).
<loop_variable> is the identifier of variable in all the loop, represents every <element> in <range>.
<range> has 2 conditions:
in <element>: means every element in<element>, where<element>should be collection type.from <begin> to <end>: means every integer in [<begin>,<end>), where<begin>and<end>should be integer type, and<begin>should less than<end>.
The string format has 2 conditions:
substring '(' <string>, <begin>, <end> ')': the substring of<string>of index of [<begin>,<end>), where<string>is the string to be cut,<begin>and<end>should be integer type, and<begin>should less than<end>.find '(' <range>, <from_index>, <target> ')': the index of<target>in<range>from index<from_index>, where<range>and<target>are string type, and<from_index>is integer type. If not exists, return-1instead. For example,find ("abab", 1, "ab")return2.
Requirements and entities are written in JSON format, which should satisfy the definitions of their models.
The basic format is: [ <entity>, <entity>, ... ], in where <entity>s are seperated by , and has 4 conditions:
- basic element:
- boolean: JSON boolean value,
true/false - integer or float: JSON number value, like
3or2.15 - string: JSON string: like
"hello"
- boolean: JSON boolean value,
- collection type:
- list:
{ "[]": [ <entity>, <entity>, ... ] } - set:
{ "()": [ <entity>, <entity>, ... ] } - map:
{ "{}": [ {"K": <entity>, "V": <entity>}, ... ] }
- list:
- entity type: includes requirement and entity. Basic format is:
In this,
{ "#": <string of entity ID>, "*": <entity type>, ":": <string for comment>, <field_name> : <field_entity>, <field_name> : <field_entity>, ... }<entity_ID>is a JSON string, represents the ID of entity, using in entity-link below. It should be unique for each entity in a single type, yet can be duplicated in different types.
<field_name>is the identifier of field, and<field_entity>is also an<entity>.
Any field has no assignment in this way is initialized with default value. - entity-link: a way to refer other entity using its ID. Basic format is:
{ <entity_type> : <entity_ID> }. In this,<entity_type>is the type of the linked entity, and<entity_ID>is its ID.
If a field of entity is not specified, it should be the default, see this.
├── generated (auto-generated classes, including classes of customized types and class of rule)
│ ├── <requirement dataset name>
│ │ ├── $<customized type name>.java
│ │ ├── ... ...
│ │ └── $rule$.java
│ └── ... ...
├── java
│ ├── api
│ │ └── Main.java
│ ├── types
│ │ ├── BaseEntity.java
│ │ ├── primitive
│ │ │ ├── BasePrimitiveEntity.java
│ │ │ ├── BoolEntity.java
│ │ │ ├── IntEntity.java
│ │ │ ├── FloatEntity.java
│ │ │ └── StringEntity.java
│ │ └── collection
│ │ ├── BaseCollectionEntity.java
│ │ ├── ListEntity.java
│ │ ├── SetEntity.java
│ │ └── MapEntity.java
│ ├── generator
│ │ ├── JavaHeaderGenerator.java
│ │ ├── LogicParser.java
│ │ ├── ModelJsonParser.java
│ │ └── RuleParser.java
│ ├── dynamics
│ │ ├── Builder.java
│ │ ├── Compiler.java
│ │ └── TypeManager.java
│ ├── exceptions
│ │ ├── TokenInvalidException.java
│ │ └── TypeInvalidException.java
│ ├── grpc
│ │ ├── Request.java
│ │ ├── Response.java
│ │ ├── RequestOrBuilder.java
│ │ ├── ResponseOrBuilder.java
│ │ ├── Requirement.java
│ │ ├── StructurationGrpc.java
│ │ └── Client.java
│ ├── judge
│ │ └── Processor.java
│ ├── parser
│ │ ├── BaseParser.java
│ │ ├── ModelTextParser.java
│ │ └── RuleTextParser.java
│ ├── serializator
│ │ ├── EntityParser.java
│ │ └── RequirementParser.java
│ └── util
│ ├── FormatsConsts.java
│ ├── ModeEnum.java
│ ├── OperatorConsts.java
│ ├── PathCosts.java
│ ├── TextReader.java
│ ├── ThesaurusReader.java
│ └── TypeEnum.java
├── proto: Protobuf files
│ └── requirement.proto (defining natrual language requirement request and structuralization response)
└── resources
├── log
│ ├── <log name>.log
│ └── log4j2.xml
├── entities
│ ├── entity_schema.json
│ ├── <requirement dataset name>
│ │ ├── <requirements dataset>.txt
│ │ ├── <requirement type>.json
│ │ ├── ... ...
│ │ ├── <entity name>.json
│ │ └── ... ...
│ └── ... ...
├── models
│ ├── model_schema.json
│ ├── <requirement dataset name>
│ │ ├── <file name>.r4dl
│ │ ├── ... ...
│ │ ├── <file name>.json
│ │ └── ... ...
│ └── ... ...
├── rules
│ ├── rule_schema.json
│ ├── <requirement dataset name>
│ │ ├── <file name>.r4dl
│ │ ├── ... ...
│ │ ├── <file name>.json
│ │ └── ... ...
│ └── ... ...
├── thesaurus
│ ├── antonym (dictionary of antonym words)
│ └── synonym (dictionary of synonym words)
└── properties
├── config.properties
├── formats.properties
└── operators.properties