Giter Club home page Giter Club logo

trlc's Introduction

Treat Requirements Like Code (TRLC)

TRLC is a domain-specific language developed at BMW for writing (and linking) requirements with meta-data.

The repository contains:

The implementation is not very fast, but designed to be pedantically correct in following the language definition. The tools also include a powerful static analysis tool to find issues with types and user-defined check rules.

The Python implementation can be used for several purposes:

  • It can be used to validate other TRLC implementations.

  • It can be used to validate a body of requirements (e.g. a CI check that all requirements are well formed)

  • The API can be used to write other tools based on TRLC (for example a tool to render the requirements in HTML, a tool to diff requirements or perform an impact analysis, or a tool to perform software traceability, etc.)

Documentation

For normal users

For advanced users

For TRLC developers

Dependencies

Run-time

  • 3.8 <= Python3 <= 3.11
  • PyVCG

Optional dependencies (they are not installed automatically):

  • PyPI CVC5 (Linux or OSX only, required when using the --verify option)
  • Binary CVC5 (An alternative to PyPI CVC5, make sure to rename the binary to cvc5 and put it on your PATH).

trlc's People

Contributors

akashsurwase1 avatar castler avatar christophkloeffel avatar florianschanda avatar markusrosskopf avatar mleegwt avatar mugdhadhole1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

trlc's Issues

mark types as abstract

You might want to build a hierarchy of types, but you may want to stop people from directly using non-leaf nodes.

Translate regular expressions

  • Document precisely the regular expression language supported by TRLC (instead of just a recommendation)
  • Translate to ReLan
  • Get rid of the UF

deprecate .check files

Check files are kinda bad from a language design:

  • You can have only one rsl file for a package
  • BUT you can have multiple check files
  • If you then have a global rsl file for your project requirement...
  • Some random person can create an additional check file that adds additional checks for the global requirement

deal with longer user-defined errors

Proposal:

checks T {
   x > 0, "must be positive"
   '''there are excellent reasons for this
      and this string explains in detail why''',
   x
}

LRM change:

check_declaration ::= expression ',' 
                      [ severity ] STRING_message [ STRING_extrainfo ]
                      [ ',' IDENTIFIER_component_name ]

extended integer domain

Extend and subtype Integer.

  • Extended_Integer (-∞ .. +∞, HEAD)
  • Integer is Extended_Integer range -∞ .. +∞
  • Natural is Integer range 0 .. +∞
  • Positive is Natural range 1 .. +∞
  • Version is Extended_Integer range 0 .. HEAD

With the following definition of HEAD:

  • ∀ x in Extended_Integer => x ≤ HEAD

At certain points we force type constraints, specifically on assignment for checks (based on what the user wants), array indexing (Natural), and arithmetic (Integer).

partial parsing (unsound)

This requires #47 (the sound version of this).

Use case:

  • provide include directories with new switch (e.g. -I)
  • provide one file we're interested in
  • validate just this file but ignore global issues
  • determine the set of file (not package) dependencies
  • parse subject file
  • resolve names only for items declared in subject file

alternative modelling of decimals

We can model decimals as integers and then divide them by a suitably large power of ten. This is not sound, but it is then complete, which may be in the spirit of this tool anyway.

We could make this configurable from the command-line.

Validate counter-examples

We could create a TRLC object with the values suggested by the CE to double-check it's correct, in which case we can remove the possible "incomplete" warning if it does indeed create an error.

talking about specific records in checks

We can check if a reference is null or not null. But we cannot check if a certain reference is there or not, because in the check file the symbol wouldn't be know. For example this is not valid:

checks Requirement {
  base_safety_case in trlc_links, warning "the base safety case is not mentioned"
}

We could do this through lookup functions perhaps:

checks Requirement {
  Requirement("general.base_safety_case") in trlc_links, warning "the base safety case is not mentioned"
}

So:

  • each record type T introduces a str -> T function
  • this function looks up the (qualified) name in the current symbol table at run-time
  • specifying a requirement that does not exist creates a run-time error (like div 0)
  • specifying a requirement that does not match in type creates a run-time error
  • following lsp, you can of course make a view from a more specialized extension to its parent type
  • but not the other way around

I do not want to permit general.base_safety_case without the sugar because then we could not spell-check check typos.

partial parsing (sound)

Use-case:

  • provide include directories with new switch (e.g. -I)
  • provide set of files we're interested in
  • want to parse all files that we need to generate all possible messages relating to these files
  • move preamble parsing from check and trlc files to the register step (like we do for rsl files)
  • discover all files in include dirs
  • build package dependency graph in source manager
  • parse the transitive closure of the files or dirs we need (effectively equivalent to manually specifying only the necessary files)

Relax ordering constraints for check blocks

Multiple check blocks for the same type are evaluated in unspecified order.

Currently in vcg we assume the same order that TRLC has used; but we should not do that. We can emulate this with an overapproximation: we can execute all check blocks in parallel.

corner-case for ''' strings

In the LRM we have something like this:

  bnf = '''
    foo ::= bar
            { wibble }
  '''

This comes out as

foo ::= bar
{ wibble }

It would be better if it came out like this:

foo ::= bar
        { wibble }

We could change the rules to only ignore absolute first line (i.e. the stuff on the same line as the ''' when figuring out common whitespace). But still ignore blank lines. But this is rapidly becoming a mess.

let expressions in checks

We could support something like this:

checks T {
   let { fraction = a / b }
   1 <= fraction and fraction <= 10, warning "potato"
}

type extensions with frozen components

When extending a type it could be possible to nail down a particular value:

type T {
  b optional Integer
}
type U extends T {
  b is 0
}

Attempting to re-define b in U or any subtype of it would be a static error. In the API when you get objects of type U you see all the values, including b = 0.

new type: Decimal

Add support for decimal (rational) numbers.

In the Python API they would come out as an instance of rational, not float, in order to preserve precision.

Expressions with Integer and Decimal are not compatible and you need to explicitly cast between them, for example:

   Decimal(i + 1) + 0.3 < d

Semantics for rounding are the classic ones (round nearest away).

string subtype allowing references

Add a new string subtype Markup_String with the following additional features:

  • initially allows [[id]] references that can name other TRLC objects
  • naming resolution is like any other record reference (i.e. you need to qualify + import foreign objects)
  • quantification over these yields references
  • new builtin function isinstance to check if a given reference is a subtype of some other record; for example
(forall ref in description => isinstance(ref, Definition) or isinstance(ref, Constant)),
  error "You can only reference Definitions or Constants in the description",
  description

Needs a reasonable API as well.

keep the whole token stream and link each token to the most appropriate AST object

Motivation: Access the AST object behind a click or hover action within the vscode extention while only providing it's location. Common features like go-to def, show references or show user defined documentation need the correct AST object to work properly.

Tasks:

  • add ast_link to Token class, initially None
  • add set_ast_link method to AST Node class, which sets the link to self (we do it this way round to avoid having a circular dependency between token / ast nodes)
  • create a new lexer class (Token_Stream) that basically just delegates to the existing lexer class, but which remember the entire token stream (see https://github.com/florianschanda/miss_hit/blob/master/miss_hit_core/m_lexer.py#L1203 for an example)
  • (this is the big step) when building the AST in the parser, pedantically call set_ast_link for every token. Note that this needs to capture all tokens, including e.g. brackets
  • (optional, but a good idea to find bugs) when using the Token_Stream, do a post-processing step to assert that all tokens in the stream have an assigned ast object after parsing

After this you can go from source location to the correct token by just going over the list comparing start/end lexpos, and then you can follow ast_link to find the AST object relating to this token.

change default operation

Make -I . the default mode of operation.

Add new parameter --no-default-include or similar to restore the current behaviour.

tuples

Proposal:

tuple Dimension {
  x Integer
  y Integer
}

tuple Codebeamer {
  item Integer
  separator @
  version optional Integer = HEAD
}

checks Codebeamer {
  item >= 1, error "CB Reference must be strictly positive", item
  version >= 1, error "CB Version must be strictly positive", version
}

type Requirement {
  description String
  dim         Dimension
  cb_link     Codebeamer
}

checks Requirement {
  cb_link.item >= 10000, warning "CB Item is suspiciously low", cb_link
  cb_link.version != HEAD, warning "Please link to a specific version", cb_link
}

And usage:

Requirement Good_Potato {
  description = "This is a nice potato."
  dim         = (42, 666)  // Normal tuple syntax
  cb_link     = 12345@5    // Custom separator syntax
}

Requirement Bad_Potato {
  description = "This is a dodgy potato."
  dim         = (42, 666)
  cb_link     = 12345      // Equivalent to 12345@HEAD
}

Notes:

  • nesting tuples is fine, as long as the container tuple doesn't have custom separators. otherwise:
tuple T {
  x Integer
  separator foo
  y optional T
}
1 foo 2 foo 3
  • lint warnings a record has a field F and another tuple field Y that contains a separator with literal F

--brief mode for CI

T Test {
  ^^^^ foo.trlc:3: check warning: 16: bad % (2/4)

->

foo.trlc:3: trlc check warning: 16: bad % (2/4)

Requirement "Name_resolution LRM.Sufficiently_Distinct" not met

the following requirement is not met

Name_Resolution Sufficiently_Distinct {
text = '''When declaring record objects there are wider rules that
indicate name clashes. Specifically a record
may not be declared if its "simplified name"
clashes with any other "simplified name". A
"simplified name" is the name converted to
lowercase and all underscored removed.'''
}

either remove the requirement from the LRM or implement the missing feature

TRLC performance analysis and improvements

The worst offenders are for tests-system/bulk are:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   31.589   31.589 trlc/trlc.py:21(<module>)
        1    0.000    0.000   31.571   31.571 trlc/trlc.py:490(main)
        1    0.000    0.000   31.558   31.558 trlc/trlc.py:422(process)
        1    0.000    0.000   27.343   27.343 trlc/trlc.py:364(parse_trlc_files)
       85    0.037    0.000   27.338    0.322 trlc/parser.py:1705(parse_trlc_file)
    63859    0.044    0.000   27.257    0.000 trlc/parser.py:1577(parse_trlc_entry)
    63859    0.887    0.000   27.084    0.000 trlc/parser.py:1530(parse_record_object_declaration)
  1217740    0.433    0.000   19.282    0.000 trlc/parser.py:167(match)
  1217930    0.643    0.000   18.853    0.000 trlc/parser.py:139(advance)
  1217930    3.994    0.000   18.210    0.000 trlc/lexer.py:332(token)
   319609    0.692    0.000   10.996    0.000 trlc/parser.py:1352(parse_value)
  6214992    3.212    0.000    4.665    0.000 trlc/lexer.py:215(is_alnum)
   581360    0.591    0.000    4.360    0.000 trlc/ast.py:3060(lookup_direct)
        1    0.017    0.017    4.212    4.212 trlc/trlc.py:391(resolve_record_references)
    63859    0.144    0.000    4.160    0.000 trlc/ast.py:2873(resolve_references)
   109334    0.077    0.000    4.030    0.000 trlc/ast.py:1063(resolve_references)
    74685    0.032    0.000    3.853    0.000 trlc/ast.py:904(resolve_references)
  9752278    3.774    0.000    3.774    0.000 trlc/lexer.py:238(advance)
       10    0.298    0.030    3.659    0.366 /usr/lib/python3.8/difflib.py:688(get_close_matches)
    94872    0.136    0.000    2.933    0.000 trlc/parser.py:328(parse_qualified_name)
   638740    1.912    0.000    2.813    0.000 /usr/lib/python3.8/difflib.py:647(quick_ratio)
  1217930    0.876    0.000    2.442    0.000 trlc/lexer.py:232(skip_whitespace)
    63859    0.096    0.000    2.229    0.000 trlc/ast.py:2816(__init__)
  1217844    1.020    0.000    1.905    0.000 trlc/lexer.py:71(__init__)
    63859    0.531    0.000    1.846    0.000 trlc/ast.py:2821(<dictcomp>)
  1021744    0.720    0.000    1.316    0.000 trlc/ast.py:546(__init__)
  1217844    0.765    0.000    1.242    0.000 trlc/lexer.py:162(__init__)
  1217844    0.798    0.000    1.188    0.000 trlc/lexer.py:200(is_alpha)

This is not unexpected:

  • token() is the worst offender with 18s (number crunching)
  • parse_trlc_files() takes around 9s once you remove the lexing (which likely seems unavoidable)
  • and process() takes 4 seconds, which is entirely due to resolve_record_references (unavoidable, this is work that needs to happen sooner or later)

There are some immediate ideas:

  • is_alpha, is_alum, and is_digit could be replaced by more builtiny functions (but we need to take care of unicode stuff, so it's not as easy as just using the builtins)
  • implement #47
  • implement #48
  • token() could be optimised in some other way
  • token() could be replaced by a hand-written c lexer (but this adds portability concerns)

There is one more issue that could manifest on windows with large repos: if you have millions of files (most of which are not trlc files) then the initial traversal for register_dir could take a lot of time.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.