Project

General

Profile

Feature #1745

Feature #9635: TRPL 2.0

review, decide upon and document the 1.0 features which will be retained in 2.0

Added by Greg Shah over 13 years ago. Updated about 1 year ago.

Status:
Hold
Priority:
Normal
Target version:
Start date:
Due date:
% Done:

90%

Estimated time:
40.00 h
billable:
No
vendor_id:
GCD
case_num:
version_reported:
version_resolved:
reviewer:
production:
No
env_name:
topics:

tracker_20250324_154648.log Magnifier (4.93 KB) Octavian Adrian Gavril, 03/24/2025 09:48 AM

trpl_feature_errors.txt Magnifier (4.7 KB) Octavian Adrian Gavril, 03/24/2025 09:49 AM

trpl_feature_errors.txt Magnifier (5.63 KB) Octavian Adrian Gavril, 04/07/2025 09:01 AM


Related issues

Related to TRPL - Bug #9835: The same rules files are loaded and compiled multiple times WIP

History

#1 Updated by Greg Shah over 13 years ago

  • Target version set to Code Improvements

#2 Updated by Greg Shah over 9 years ago

  • Target version changed from Code Improvements to TRPL 2.0

#3 Updated by Greg Shah over 9 years ago

  • Estimated time changed from 24.00 to 40.00

#4 Updated by Greg Shah over 1 year ago

  • Parent task set to #9635

#5 Updated by Greg Shah over 1 year ago

  • Assignee set to Octavian Adrian Gavril

#6 Updated by Greg Shah over 1 year ago

Our existing documentation is here:

  • Writing TRPL Rule-Sets - This defines the language at the level of statements, control flow and program structure. All of this is defined in XML format and is read by the ConfigLoader class. Overall these parts of TRPL are implemented in the com.goldencode.p2j.pattern.* package, see the PatternEngine for the main "runner" of a TRPL ruleset.
  • Writing TRPL Expressions - This defines the expressions executed (as part of control flow or as a standalone rule/action) to actually do something. We compile these expressions using the com.goldencode.expr.Compiler which uses the expression.g grammar (see the expression() rule) to parse each expression.

Please review the documentation and code in detail. Make sure every TRPL v1 feature is documented somewhere in that documentation so that we have a complete list.

After that, we want to instrument the ConfigLoader and expression Compiler to track the usage of each feature. We can process all of the TRPL rules we have to then see what features are critical and what features can possibly be dropped.

#7 Updated by Octavian Adrian Gavril over 1 year ago

I reviewed ConfigLoader.java along with Writing_TRPL_Rule-Sets and these are some features that I found undocumented:

ATTRIBUTES CONSTANT VALUES FUNCTIONALITIES
execute-condition view parameter() doesn't extract init attribute
drop-condition tree(no usage) ruleSet(): depth is used but not documented
depth ruleSet(): execute-condition is used but not documented
optional(ATTR_OPTIONAL/ATTR_OPT) ruleSet(): drop-condition is used but not documented
namespace ruleSet(): optional is used but not documented
mode(no usages) worker(): namespace is used but not documented

Continue the same with Compiler and Writing_TRPL_Expressions.

#8 Updated by Octavian Adrian Gavril over 1 year ago

  • Status changed from New to WIP

#9 Updated by Octavian Adrian Gavril over 1 year ago

I've reviewed Writing_TRPL_Expressions along with the associated code and it seems fully documented to me. I'm moving on to find a way to track the usage of each TRPL feature.

#10 Updated by Octavian Adrian Gavril over 1 year ago

Greg, where is PatternEngine.main called in order to run the entire TRPL rule-set? I saw some targets in build_db.xml but I don't think this is related as it ran for import.db.pg.

#11 Updated by Greg Shah over 1 year ago

Look for any location that instantiates new PatternEngine(). For example, in TransformDriver.processTrees().

#12 Updated by Greg Shah over 1 year ago

Octavian Adrian Gavril wrote:

I've reviewed Writing_TRPL_Expressions along with the associated code and it seems fully documented to me. I'm moving on to find a way to track the usage of each TRPL feature.

I'm worried that these Expression Features are not documented in detail. We mention that they are available but we provide no comprehensive explanation. Worse: the features are hidden deep in the compiler because they are implemented directly in the generated bytecode. Please take a look at these features (auto-boxing, automatic type conversion, automatic null checking and property notatation).

#13 Updated by Octavian Adrian Gavril over 1 year ago

Greg Shah wrote:

I'm worried that these Expression Features are not documented in detail. We mention that they are available but we provide no comprehensive explanation. Worse: the features are hidden deep in the compiler because they are implemented directly in the generated bytecode. Please take a look at these features (auto-boxing, automatic type conversion, automatic null checking and property notatation).

I've updated the description of the first two features from Expression Features. Should I include more details about the used methods? (e.g. Compiler.convertToRequiredType and how the bytecode is generated using those helper classes)

Greg, please let me know if I should use the same structure for the others or if improvements are needed.

#14 Updated by Octavian Adrian Gavril over 1 year ago

I added some documentation for Property Notation feature. Still looking for the Automatic Null Checking implementation to expand its documentation.

#15 Updated by Greg Shah over 1 year ago

I've updated the description of the first two features from Expression Features.

The changes are really good.

Should I include more details about the used methods? (e.g. Compiler.convertToRequiredType and how the bytecode is generated using those helper classes)

More details are always useful, especially when we are going to rework the language to reimplement these features.

Greg, please let me know if I should use the same structure for the others or if improvements are needed.

Your approach is really good.

#16 Updated by Greg Shah over 1 year ago

Still looking for the Automatic Null Checking implementation to expand its documentation.

Eric: Can you please point us to the proper code?

#17 Updated by Octavian Adrian Gavril over 1 year ago

Eric, is Automatic Null Checking related to code sections similar to this?


         // Create a bogus AST which represents the destination of a jump
         // in the case where the object reference under test is determined
         // to be non-null.
         ExtraAst notNullDest = new ExtraAst();
         notNullDest.setType(NOT_NULL);
         notNullDest.setText("null check dest");
         notNullDest.setExtra(finishUnit);

#18 Updated by Greg Shah over 1 year ago

Question from Octavian:

Should I configure ConfigLoader and Compiler to track each .rules file/.xml file/rule-set/function? Is there something I missed?

We might need that information (eventually) but for now I am more worried about getting a count of how many times each language feature is used. It seems to me that some features are parsed via the ConfigLoader and some parsed by the expression.g. We can count many features by instrumenting these pieces of code and then loading all the rules. There are also features that can only be seen by the compiler because they are implemented implicitly during compilation, so it seems that some instrumentation there could also be needed to get a full count.

The objective is to see if there are features of the language that are not really being used. Dropping those features would make it easier to implement TRPL v2.

#19 Updated by Octavian Adrian Gavril over 1 year ago

Is it OK if I start with the items mentioned in the table in Writing TRPL Rule-Sets, as these are methods implemented in ConfigLoader.java. Then I continue with features mentioned in Features section. After that, we'll see what else can be included.

#20 Updated by Greg Shah over 1 year ago

Yes, that works.

#21 Updated by Eric Faulhaber over 1 year ago

Octavian Adrian Gavril wrote:

Eric, is Automatic Null Checking related to code sections similar to this?

[...]

Wow, this is some of the oldest code in FWD. I wrote that almost 20 years ago.

But yes, this implements the behavior that a boolean (sub-)expression which evaluates to null is treated as evaluating to false, so we can avoid NPEs being thrown from within TRPL expressions. One has to be aware of this behavior when writing those TRPL expressions.

If we want to get rid of this, the treatment of (branches of) logical expressions evaluating to null will need to be handled more explicitly somehow.

#22 Updated by Eric Faulhaber over 1 year ago

Greg Shah wrote:

Still looking for the Automatic Null Checking implementation to expand its documentation.

Eric: Can you please point us to the proper code?

I don't recall that well from so long ago, but I think the implementation is mostly in the Compiler.convertToRequiredType method (which Octavian already found). Look also at the Compiler.assembleNullTest method, though I think that may only be used for explicit null tests (not the implicit auto null-check).

It may be elsewhere as well. Review places where the IS_NULL and NOT_NULL constants are used (though these may be used for other purposes as well, which are not auto null-check related).

#23 Updated by Octavian Adrian Gavril over 1 year ago

Updated the Expression Features documentation. I added an introduction to the classes used as tools to implement these features. Then I detailed each feature and described what the core implementation looks like. I have also included code sections for a better understanding of the behavior of the features.

#24 Updated by Octavian Adrian Gavril over 1 year ago

Please, let me know if improvements are needed.

#25 Updated by Octavian Adrian Gavril over 1 year ago

I committed the initial implementation of TRPL feature tracking system into task branch 1745a/15792. I added a class responsible for logging, another for handling the results in a map, and another class for deciding which features are critical or not.

I converted this file start.p:

message "Hello world!".

The csv output file looks like this:

Feature Number of usages
<parameter> 69148
<rule> 263591
<walk-rules> 258
<cfg> 28
<worker> 1704
<variable> 77889
<action> 195980
<post-rules> 110
<ast-spec> 0
<return> 49110
<continue> 203
<rule-set> 853
<expression> 5607
<ascent-rules> 132
<init-rules> 184
<while> 8593
<include> 348
<next-child-rules> 9
<descent-rules> 50
<break> 1287
<func-library> 439
<function> 65815
Observation: Usage statistics: {<parameter>=69148, <rule>=263591, <walk-rules>=258, <cfg>=28, <worker>=1704, <variable>=77889, <action>=195980, <post-rules>=110, <ast-spec>=0, <return>=49110, <continue>=203, <rule-set>=853, <expression>=5607, <ascent-rules>=132, <init-rules>=184, <while>=8593, <include>=348, <next-child-rules>=9, <descent-rules>=50, <break>=1287, <func-library>=439, <function>=65815}
Observation: Critical features: [<parameter>, <rule>, <walk-rules>, <cfg>, <worker>, <variable>, <action>, <post-rules>, <return>, <continue>, <rule-set>, <expression>, <ascent-rules>, <init-rules>, <while>, <include>, <descent-rules>, <break>, <func-library>, <function>]
Observation: Features that can be removed: [<ast-spec>, <next-child-rules>]

Not sure if these results should differ from the converted project. Basically, I don't know if the conversion goes through all the rules regardless of the project.

Please take a look to see if I can go ahead with this.

#26 Updated by Greg Shah over 1 year ago

Updated the Expression Features documentation. I added an introduction to the classes used as tools to implement these features. Then I detailed each feature and described what the core implementation looks like. I have also included code sections for a better understanding of the behavior of the features.

This is really good.

#27 Updated by Greg Shah over 1 year ago

I committed the initial implementation of TRPL feature tracking system

These are interesting results. Some feedback:

1. We can't just run conversion, that will only load rules files that are used in that pipeline. This is most of the rule files, but not all. It would be missing things like the rules used for reports, database import, AST search, customer-specific rules and so forth.

Instead of relying upon conversion, we should dynamically lookup all .xml and .rules files in the pattern path and load them using your instrumented loader.

2. Some of the numbers are quite accurate while others are not obvious. For example, there aren't 8593 <while> elements in all our rules. The actual number is closer to 550. The number of <function instances is similarly incorrect (there should be around 1000 of them and instead nearly 70000 are reported). I suspect this comes from referencing some rules (e.g. common-progress.rules) from many places. This suggests 2 things:

  • Once we've loaded a given file, don't add to our numbers when the file is processed again.
  • Do we have an optimization opportunity here? Why would we load and compile the same rules file more than once? I think we should be able to reuse the same loaded code in many places, though we will have to ensure that we fix usage of "global data" such that we don't rely upon any variable references outside of the current file-level scope. I wonder what performance improvement we can get by this.

Observation: Features that can be removed: [<ast-spec>, <next-child-rules>]

ast-spec is a deprecated feature and definitely will be dropped.

next-child-rules is actually needed. 9 instances just means that only 9 rulesets use it, but those rules are quite helpful.

#28 Updated by Octavian Adrian Gavril over 1 year ago

I added another class (TRPLFeatureTracker) to search for all .xml files and process them with the processTrees method. This way all .xml files from p2j/rules are loaded. Therefore, we will have 58 <cfg> tags because 58 .xml files were found. Now, the results are increased compared to #1745-25. This happens because all files are involved, but I need to check if .rules are loaded more than once. (they can be called from two different .xml files).

I also added an error trace while processing the .xml files and logged the errors to trpl_feature_errors.txt. This way I discovered files like dbref/collect_refs.xml which uses "dbref.xml". This file doesn't exist.

I continue implementing multiple load checking for .rules files.

I made these changes in the task branch 1745a/15793.

The new results look like this:

Feature Number of usages
<parameter> 77036
<rule> 293021
<walk-rules> 270
<cfg> 58
<worker> 1917
<variable> 86545
<action> 217423
<post-rules> 130
<ast-spec> 0
<return> 54805
<continue> 221
<rule-set> 903
<expression> 6222
<ascent-rules> 134
<init-rules> 215
<while> 9531
<include> 393
<next-child-rules> 7
<descent-rules> 43
<break> 1425
<func-library> 491
<function> 73335
Observation: Usage statistics: {<parameter>=77036, <rule>=293021, <walk-rules>=270, <cfg>=58, <worker>=1917, <variable>=86545, <action>=217423, <post-rules>=130, <ast-spec>=0, <return>=54805, <continue>=221, <rule-set>=903, <expression>=6222, <ascent-rules>=134, <init-rules>=215, <while>=9531, <include>=393, <next-child-rules>=7, <descent-rules>=43, <break>=1425, <func-library>=491, <function>=73335}
Observation: Critical features: [<parameter>, <rule>, <walk-rules>, <cfg>, <worker>, <variable>, <action>, <post-rules>, <return>, <continue>, <rule-set>, <expression>, <ascent-rules>, <init-rules>, <while>, <include>, <descent-rules>, <break>, <func-library>, <function>]
Observation: Features that can be removed: [<ast-spec>, <next-child-rules>]

I attached the tracker log and trpl_feature_errors.txt.

#29 Updated by Octavian Adrian Gavril over 1 year ago

I've added some changes to avoid multiple uploads of the same .rules file. The numbers seem accurate, so I hope I've found the right places for this check.

Feature Number of usages
<parameter> 1318
<rule> 17717
<walk-rules> 257
<cfg> 58
<worker> 631
<variable> 5476
<action> 21163
<post-rules> 124
<ast-spec> 0
<return> 674
<continue> 17
<rule-set> 508
<expression> 209
<ascent-rules> 126
<init-rules> 207
<while> 481
<include> 196
<next-child-rules> 7
<descent-rules> 39
<break> 50
<func-library> 102
<function> 990
Observation: Usage statistics: {<parameter>=1318, <rule>=17717, <walk-rules>=257, <cfg>=58, <worker>=631, <variable>=5476, <action>=21163, <post-rules>=124, <ast-spec>=0, <return>=674, <continue>=17, <rule-set>=508, <expression>=209, <ascent-rules>=126, <init-rules>=207, <while>=481, <include>=196, <next-child-rules>=7, <descent-rules>=39, <break>=50, <func-library>=102, <function>=990}
Observation: Critical features: [<parameter>, <rule>, <walk-rules>, <cfg>, <worker>, <variable>, <action>, <post-rules>, <return>, <continue>, <rule-set>, <expression>, <ascent-rules>, <init-rules>, <while>, <include>, <descent-rules>, <break>, <func-library>, <function>]
Observation: Features that can be removed: [<ast-spec>, <next-child-rules>]

I committed the changes in revision 15794.

#30 Updated by Octavian Adrian Gavril over 1 year ago

  • Related to Bug #9835: The same rules files are loaded and compiled multiple times added

#31 Updated by Octavian Adrian Gavril over 1 year ago

Greg, as you suggested in the last call, I created a new task about that performance gap described in #1745-27.

#32 Updated by Octavian Adrian Gavril over 1 year ago

  • % Done changed from 0 to 70

I've added the elements mentioned in Features to be tracked. I've also included customer-specific rules, and the new results look like this:

Feature Number of usages
<parameter> 1328
<walk-rules> 260
<variable> 5601
<action> 21915
<post-rules> 124
PROPERTY NOTATION 3103
<continue> 17
<rule-set> 515
<ascent-rules> 128
<while> 485
<next-child-rules> 7
<descent-rules> 39
<rule> 18041
<cfg> 64
<worker> 653
AUTO-BOXING 4904
<ast-spec> 5
<return> 680
AUTO TYPE CONVERSION 189
AUTOMATIC NULL CHECKING 49
<expression> 217
<init-rules> 211
<include> 204
<break> 50
<func-library> 104
<function> 1000

I've committed these changes to 1745a/15795.

Greg, what do you think about the numbers above? Also, what should I continue tracking with?

#33 Updated by Octavian Adrian Gavril over 1 year ago

Octavian Adrian Gavril wrote:

I reviewed ConfigLoader.java along with Writing_TRPL_Rule-Sets and these are some features that I found undocumented:

ATTRIBUTES CONSTANT VALUES FUNCTIONALITIES
execute-condition view parameter() doesn't extract init attribute
drop-condition tree(no usage) ruleSet(): depth is used but not documented
depth ruleSet(): execute-condition is used but not documented
optional(ATTR_OPTIONAL/ATTR_OPT) ruleSet(): drop-condition is used but not documented
namespace ruleSet(): optional is used but not documented
mode(no usages) worker(): namespace is used but not documented

Continue the same with Compiler and Writing_TRPL_Expressions.

Added properly documentation for parameters of rule-set/worker from Writing TRPL Rule-Sets.

#34 Updated by Greg Shah over 1 year ago

Greg, what do you think about the numbers above? Also, what should I continue tracking with?

Please instrument expression.g and add those numbers to the results. This will tell us which expression features are used and how much.

#35 Updated by Octavian Adrian Gavril over 1 year ago

Greg Shah wrote:

Greg, what do you think about the numbers above? Also, what should I continue tracking with?

Please instrument expression.g and add those numbers to the results. This will tell us which expression features are used and how much.

Sure!

#36 Updated by Octavian Adrian Gavril over 1 year ago

  • Status changed from WIP to Review
  • % Done changed from 70 to 100
  • reviewer Greg Shah added

Instrumented expression.g, both rules and tokens, into 1745a/15796. Now, the results look like this:

Feature Number of usages
<action> 21915
<ascent-rules> 128
<ast-spec> 5
<break> 50
<cfg> 64
<continue> 17
<descent-rules> 39
<expression> 217
<func-library> 104
<function> 1000
<include> 204
<init-rules> 211
<next-child-rules> 7
<parameter> 1328
<post-rules> 124
<return> 680
<rule-set> 515
<rule> 18041
<variable> 5601
<walk-rules> 260
<while> 485
<worker> 653
AUTO TYPE CONVERSION 189
AUTO-BOXING 4904
AUTOMATIC NULL CHECKING 49
PROPERTY NOTATION 3103
RULE: bit_and_expr 12600
RULE: bit_or_expr 10233
RULE: bit_xor_expr 12600
RULE: cast 207
RULE: compare_expr 12640
RULE: equality_expr 12600
RULE: expr 10196
RULE: expression 4268
RULE: literal 9353
RULE: log_and_expr 10215
RULE: method 6266
RULE: primary_expr 12828
RULE: prod_expr 12651
RULE: shift_expr 12651
RULE: sum_expr 12651
RULE: un_expr 12651
Token: ASSIGN 176
Token: BIT_OR 2366
Token: COMMA 2794
Token: DIGIT 556
Token: DSTRING 559
Token: EQUALS 27
Token: GT 0
Token: GTE 9
Token: HASH 207
Token: LETTER 120659
Token: LPARENS 3379
Token: MINUS 6
Token: NOT 12
Token: NOT_EQ 11
Token: NUM_LITERAL 10522
Token: RPARENS 3380
Token: SSTRING 806
Token: STRING 1366
Token: SYMBOL 21371
Token: SYM_CHAR 13920
Token: VALID_SYM_CHAR 113335
Token: WS 9304
Observation: Usage statistics: {<parameter>=1328, RULE: expr=10196, Token: ASSIGN=176, <walk-rules>=260, <action>=21915, PROPERTY NOTATION=3103, Token: LPARENS=3379, RULE: bit_and_expr=12600, Token: WS=9304, <continue>=17, RULE: log_and_expr=10215, RULE: bit_or_expr=10233, <while>=485, <next-child-rules>=7, Token: EQUALS=27, Token: RPARENS=3380, RULE: equality_expr=12600, Token: STRING=1366, Token: DIGIT=556, RULE: method=6266, AUTO TYPE CONVERSION=189, RULE: prod_expr=12651, AUTOMATIC NULL CHECKING=49, RULE: expression=4268, Token: NUM_LITERAL=10522, Token: GT=0, <include>=204, Token: NOT=12, <func-library>=104, Token: LETTER=120659, <variable>=5601, <post-rules>=124, RULE: compare_expr=12640, <rule-set>=515, Token: HASH=207, <ascent-rules>=128, Token: NOT_EQ=11, Token: COMMA=2794, Token: SSTRING=806, RULE: un_expr=12651, <descent-rules>=39, Token: BIT_OR=2366, Token: DSTRING=559, RULE: sum_expr=12651, Token: SYMBOL=21371, RULE: shift_expr=12651, <rule>=18041, RULE: literal=9353, Token: SYM_CHAR=13920, <cfg>=64, <worker>=653, AUTO-BOXING=4904, RULE: bit_xor_expr=12600, <ast-spec>=5, <return>=680, RULE: cast=207, <expression>=217, <init-rules>=211, Token: VALID_SYM_CHAR=113335, RULE: primary_expr=12828, Token: GTE=9, Token: MINUS=6, <break>=50, <function>=1000}
Observation: Critical features: [<parameter>, RULE: expr, Token: ASSIGN, <walk-rules>, <action>, PROPERTY NOTATION, Token: LPARENS, RULE: bit_and_expr, Token: WS, <continue>, RULE: log_and_expr, RULE: bit_or_expr, <while>, Token: EQUALS, Token: RPARENS, RULE: equality_expr, Token: STRING, Token: DIGIT, RULE: method, AUTO TYPE CONVERSION, RULE: prod_expr, AUTOMATIC NULL CHECKING, RULE: expression, Token: NUM_LITERAL, <include>, Token: NOT, <func-library>, Token: LETTER, <variable>, <post-rules>, RULE: compare_expr, <rule-set>, Token: HASH, <ascent-rules>, Token: NOT_EQ, Token: COMMA, Token: SSTRING, RULE: un_expr, <descent-rules>, Token: BIT_OR, Token: DSTRING, RULE: sum_expr, Token: SYMBOL, RULE: shift_expr, <rule>, RULE: literal, Token: SYM_CHAR, <cfg>, <worker>, AUTO-BOXING, RULE: bit_xor_expr, <return>, RULE: cast, <expression>, <init-rules>, Token: VALID_SYM_CHAR, RULE: primary_expr, <break>, <function>]
Observation: Features that can be removed: [<next-child-rules>, Token: GT, <ast-spec>, Token: GTE, Token: MINUS]

#37 Updated by Greg Shah over 1 year ago

Please try to confirm all of your numbers using other matching techniques (even something like grep). Many of the numbers don't seem correct. There are thousands of token NOT_EQ which is the text != but the numbers above say there are 11. There are thousands of CAST nodes (not 207) and even the next-child should be 8 not 7.

#38 Updated by Octavian Adrian Gavril over 1 year ago

  • % Done changed from 100 to 90
  • Status changed from Review to WIP

#39 Updated by Octavian Adrian Gavril over 1 year ago

Greg Shah wrote:

Please try to confirm all of your numbers using other matching techniques (even something like grep). Many of the numbers don't seem correct. There are thousands of token NOT_EQ which is the text != but the numbers above say there are 11. There are thousands of CAST nodes (not 207) and even the next-child should be 8 not 7.

I think there might be some .rules files that are not referenced by any .xml files. dmo_common.rules, for example, has many uses of !=, but this file is not referenced. I'm working to fix this.

#40 Updated by Octavian Adrian Gavril over 1 year ago

After some investigation, I believe the only way the TRPL expression can be compiled is by processing it together with a specific AST.

See PatternEngine.run(String profile):

         // Run global init rules.
         applyGlobal(RULE_INIT);

         Configuration config = Configuration.getInstance();

         // Process each stored AST or walk call graph, depending on the mode of operation.
         Iterator<String> iter = targetPaths.iterator();
         while (iter.hasNext())
         {
            String path = iter.next();

            config.withFileProfile(path);

            if (graph != null)
            {
               Aast ast = AstManager.get().loadTree(path);
               long id = ast.getId();
               Vertex node = nodeFilter.acceptNode(id);
               if (node != null)
               {
                  walkGraph(node);
               }
            }
            else
            {
               processAst(path);
            }
         }

Those countered occurrences of NOT_EQ only come from the applyGlobal(RULE_INIT); call. If I track the usages during a conversion, then the results are totally different because processAst() is called and Compiler is involved.

Greg, what do you think?

#41 Updated by Octavian Adrian Gavril over 1 year ago

I tried different ways to compile expressions without any ast, but without success. I used AstSymbolResolver.getResolver() in these cases:
  • In ConfigLoader.rule() I wanted to compile only the rule condition:
          // at this point, lastRule is the rule that was just created, now we
          // set whether this new rule is a WHILE or an IF/ELSE
          lastRule.setLoop(loop);
    
          new Expression(AstSymbolResolver.getResolver(), expr).execute();
    
          boolean oldInLoop = inLoop;

    Here I had some problems with using namespaces because they were not yet compiled.
  • In ConfigLoader.loadImpl() I wanted to apply all the rules from lastRuleContainer after the load is finished:
             if (Objects.equals(suffix, SUFFIX_RULES))
             {
                lastRuleContainer.apply(AstSymbolResolver.getResolver(), RuleContainer.RULE_WALK);
                loadedRules.add(name);
             }

    Here I had some problems with rule type. In RuleContainer.apply(), each rule is applied with the same type. Therefore, compiling with only one rule type was not a good idea:
             RuleListElement next;
             for (int i = 0; i < size; i++)
             {
                next = rules.get(i);
                next.apply(resolver, type);
             }

In both cases, I get many NEP as there are some usage of CommonAstSupport.getSource() and CommonAstSupport.getCopy() are used during compiling.

#42 Updated by Octavian Adrian Gavril over 1 year ago

I'm starting a new approach similar to Expression.main() to compile expression rules.

#43 Updated by Greg Shah over 1 year ago

I think we will need a custom driver that loads everything (all rule set files) and forces all content to parse and all expressions to compile.

#44 Updated by Octavian Adrian Gavril over 1 year ago

Greg Shah wrote:

I think we will need a custom driver that loads everything (all rule set files) and forces all content to parse and all expressions to compile.

I created TRPLFeatureTracker to be the driver that loads everything using processTrees. I added trackerOn to indicate whether tracker mode is enabled or not. Using this flag, the ConfigLoader, Compiler, SymbolResolver, Verifier classes and expressiong.g are instrumented to track the usages of each TRPL tag, expression feature and expression rule. At the same time, TestResolver is used to simulate a compilation for each expression rule (see SymbolResolver.TestResolver.resolveFunction). This is implemented in ConfigLoader.rule. The Verifier class mocks the type of the operands when the environment is in tracker mode. The new results look like this:

Feature Number of usages Feature Number of usages
<action> 21635 <rule-set> 592
<ascent-rules> 127 <rule> 17964
<ast-spec> 5 <variable> 5576
<break> 50 <walk-rules> 259
<cfg> 65 <while> 480
<continue> 17 <worker> 656
<descent-rules> 39 AUTO TYPE CONVERSION 236
<expression> 213 AUTO-BOXING 4898
<func-library> 104 AUTOMATIC NULL CHECKING 5
<function> 1004 PROPERTY NOTATION 73341
<include> 203 RULE: bit_and_expr 64673
<init-rules> 211 RULE: bit_or_expr 59907
<next-child-rules> 7 RULE: bit_xor_expr 64673
<parameter> 1333 RULE: cast 758
<post-rules> 122 RULE: compare_expr 76120
<return> 685 RULE: equality_expr 64680
RULE: expr 50544 RULE: expression 18789
RULE: literal 23258 RULE: log_and_expr 54799
RULE: method 89043 RULE: primary_expr 78113
RULE: prod_expr 76602 RULE: shift_expr 76563
RULE: sum_expr 76563 RULE: un_expr 76612
Token: AND 0 Token: ASSIGN 1501
Token: BIT_AND 7 Token: BIT_COMP 0
Token: BIT_OR 4766 Token: BIT_XOR 0
Token: COMMA 14654 Token: DIGIT 3508
Token: DIVIDE 8 Token: DSTRING 8435
Token: EQUALS 9419 Token: GT 270
Token: GTE 59 Token: HASH 758
Token: HEXDIGIT 0 Token: LETTER 666247
Token: LPARENS 18431 Token: LSHIFT 0
Token: LT 102 Token: LTE 12
Token: MINUS 358 Token: MODULO 2
Token: MULTIPLY 0 Token: NOT 1145
Token: NOT_EQ 2021 Token: NUM_LITERAL 46166
Token: OR 41 Token: PLUS 23
Token: POSPARM 0 Token: RPARENS 18468
Token: RSHIFT 0 Token: SSTRING 1486
Token: STRING 9921 Token: SYMBOL 118015
Token: SYM_CHAR 42791 Token: VALID_SYM_CHAR 592114
Token: WS 75764 Token: ZRSHIFT 0

Both load rule errors and expression compilation errors are logged in trpl_feature_errors.txt. In the current version, there are no expression compilation errors (thanks to mocking). The only errors detected are attached in trpl_feature_errors.txt. Please let me know if these are expected (some of them are related to some database-related schema or data structure issues) or if we should fix them ourselves. Perhaps these errors influence the current results.

I've committed these changes into task branch 1745/15798.

#45 Updated by Octavian Adrian Gavril over 1 year ago

The table in #1745-44 was incomplete due to an issue while attempting to reformat the data into multiple tables. Apologies for the confusion. The table has now been updated in #1745-44.

#46 Updated by Greg Shah over 1 year ago

I've done some quick checking of the results. Most of the numbers look pretty reasonable, even the ones that are very low.

For example, the bitwise operator counts look accurate (or at least close) as do the LTE, DIVIDE (maybe should be 9 not 8?).

On the other hand, CAST looks wrong (there should be around 2100) and LT seems wrong.

In addition to this, the matching in the expression.g rules is a problem because the counting is not done only for matches. It is unconditionally executed on exit from the rule. Since the expression precedence processing in ANTLR v2 requires nesting of the precedence levels in sepaarate rules, this leads to some rules getting very large counts which have no relation to the actual number of matches.

We are also missing counts for the keyword matching that happens here:

      keywords.put( "and",   Integer.valueOf(AND) );
      keywords.put( "false", Integer.valueOf(BOOL_FALSE) );
      keywords.put( "not",   Integer.valueOf(NOT) );
      keywords.put( "null",  Integer.valueOf(NULL) );
      keywords.put( "or",    Integer.valueOf(OR) );
      keywords.put( "true",  Integer.valueOf(BOOL_TRUE) );

#47 Updated by Octavian Adrian Gavril over 1 year ago

  • % Done changed from 100 to 90
  • Status changed from Review to WIP

Greg Shah wrote:

On the other hand, CAST looks wrong (there should be around 2100) and LT seems wrong.

I continue investigating in this regard.

In addition to this, the matching in the expression.g rules is a problem because the counting is not done only for matches. It is unconditionally executed on exit from the rule. Since the expression precedence processing in ANTLR v2 requires nesting of the precedence levels in sepaarate rules, this leads to some rules getting very large counts which have no relation to the actual number of matches.

I assumed that if logging occurs within the try block and no exception is thrown by match() up to that point, we could treat it as a valid match. I'm still exploring whether there's a more reliable approach.

We are also missing counts for the keyword matching that happens here:

[...]

I've committed some changes to fix this into 1745a/15799.

#48 Updated by Greg Shah over 1 year ago

I assumed that if logging occurs within the try block and no exception is thrown by match() up to that point, we could treat it as a valid match. I'm still exploring whether there's a more reliable approach.

You can still put the counter processing in the exit action, but you should only increment the count if the match has been made. The way to check this is to add a conditon like this:

un_expr
   :
      {
         String cls = null;
      }
      ( 
          m:MINUS^          { #m.setType( UN_MINUS ); }
        | BIT_COMP^
        | NOT^
        | h:HASH^ cls=cast! { #h.setType(CAST); #h.setText(cls); }
        | // empty alternative
      ) 
      primary_expr[false]
      {
         int type = (## == null) ? -1 : ##.getType();

         // HASH is counted in the cast rule
         if (TRPLFeatureTracker.trackerOn && (type == MINUS || type == BIT_COMP || type == NOT))
         {
            FeatureLogger.logFeatureUsage("RULE: un_expr");
         }
      }
   ;

This takes advantage of the fact that the root node for the returned AST can be referenced via ##.

#49 Updated by Greg Shah over 1 year ago

Also, we don't need to track protected lexer rules since they don't actually generate tokens used by the parser. I'm not even sure we want to track the token generation itself, but instead would rather count things at the parser level.

#50 Updated by Octavian Adrian Gavril over 1 year ago

Greg Shah wrote:

Also, we don't need to track protected lexer rules since they don't actually generate tokens used by the parser. I'm not even sure we want to track the token generation itself, but instead would rather count things at the parser level.

So, should I remove the logging of token rules?

#51 Updated by Greg Shah over 1 year ago

Octavian Adrian Gavril wrote:

Greg Shah wrote:

Also, we don't need to track protected lexer rules since they don't actually generate tokens used by the parser. I'm not even sure we want to track the token generation itself, but instead would rather count things at the parser level.

So, should I remove the logging of token rules?

Yes, as long as you have logging for the "feature" at the parser level. For example, instead of the DIVIDE or MULTIPY tokens we should count the matches of those operators in the parser.

#52 Updated by Greg Shah over 1 year ago

The idea here is that the language features match the parser structure, not the individual tokens.

#53 Updated by Octavian Adrian Gavril over 1 year ago

I've committed some updates to 15800, which include:
  • Added compilation support for <action> expressions. This improves logging for CAST and other problematic rules.
  • Changed the caching of compiled expressions by using a more reliable key. (Considering column numbers might also be beneficial.)

I still need to address to this issue:

Greg Shah wrote:

In addition to this, the matching in the expression.g rules is a problem because the counting is not done only for matches. It is unconditionally executed on exit from the rule. Since the expression precedence processing in ANTLR v2 requires nesting of the precedence levels in sepaarate rules, this leads to some rules getting very large counts which have no relation to the actual number of matches.

I did some experiments but I need to continue.

I've also updated some .rules files that weren't compiling correctly due to syntax issues—specifically, rules/annotations/native_api.rules and rules/include/report.rules.

The new results look like this:

Feature Number of usages
<action> 21275
<ascent-rules> 119
<ast-spec> 5
<break> 50
<cfg> 65
<continue> 23
<descent-rules> 36
<expression> 243
<func-library> 100
<function> 1019
<include> 203
<init-rules> 203
<next-child-rules> 6
<parameter> 1372
<post-rules> 118
<return> 691
<rule-set> 549
<rule> 17760
<variable> 5573
<walk-rules> 245
<while> 479
<worker> 639
AUTO TYPE CONVERSION 223
AUTO-BOXING 4893
AUTOMATIC NULL CHECKING 5
PROPERTY NOTATION 157328
Rule: bit_and_expr 149478
Rule: bit_or_expr 144641
Rule: bit_xor_expr 149478
Rule: cast 2698
Rule: compare_expr 166959
Rule: equality_expr 149492
Rule: expr 131033
Rule: expression 50751
Rule: literal 54910
Rule: log_and_expr 137460
Rule: method 198009
Rule: primary_expr 187912
Rule: prod_expr 168147
Rule: shift_expr 167651
Rule: sum_expr 167651
Rule: un_expr 168170
Token: AND 14363
Token: ASSIGN 39489
Token: BIT_AND 14
Token: BIT_COMP 0
Token: BIT_OR 4837
Token: BIT_XOR 0
Token: BOOL_FALSE 3177
Token: BOOL_TRUE 6478
Token: COMMA 39835
Token: DEC_LITERAL 0
Token: DIVIDE 11
Token: EQUALS 14015
Token: GT 416
Token: GTE 111
Token: HASH 2698
Token: HEX_LITERAL 41
Token: LPARENS 46292
Token: LSHIFT 0
Token: LT 151
Token: LTE 14
Token: MINUS 944
Token: MODULO 4
Token: MULTIPLY 8
Token: NOT 2031
Token: NOT_EQ 3452
Token: NULL 12215
Token: NUM_LITERAL 12895
Token: OR 12789
Token: PLUS 364
Token: RPARENS 46288
Token: RSHIFT 0
Token: STRING 31036
Token: SYMBOL 53580
Token: WS 0
Token: ZRSHIFT 0

It's clear that there are still some unnecessary logs that need to be excluded—even for CAST. As for WS, its count is 0 because it's not directly referenced by any other rule.

#54 Updated by Greg Shah over 1 year ago

Is AUTOMATIC NULL CHECKING really only used 5 times? That is suspicious.

#55 Updated by Octavian Adrian Gavril about 1 year ago

I've completed some rules testcases covering all the expression/token/tag rules I monitor. These are not loaded in 1745a. Based on these findings, I have added some other changes to the tracker to make the results more accurate. I'm continuing with this approach. The most recent changes are committed into task branch 1745a/15801.

#56 Updated by Octavian Adrian Gavril about 1 year ago

I've added a few changes that improve the results. These add the following fixes:
  • avoided double logging of keywords from SYMBOL rule;
  • turned off the tracking mode for included files to avoid double logging of function-library, include and worker tags;
  • fixed reports/rpt_nullable_vars.xml syntax as this file generated some syntax errors (an action used inside work-rules);
  • cleaned up expression.g.
These are the current results:
Feature Number of usages
<action> 22590
<ascent-rules> 136
<ast-spec> 5
<break> 62
<cfg> 66
<continue> 26
<descent-rules> 46
<expression> 216
<func-library> 119
<function> 1049
<include> 219
<init-rules> 239
<next-child-rules> 7
<parameter> 1422
<post-rules> 138
<return> 714
<rule-set> 780
<rule> 19145
<variable> 5953
<walk-rules> 287
<while> 541
<worker> 705
AUTO TYPE CONVERSION 13
AUTO-BOXING 4919
AUTOMATIC NULL CHECKING 6
PROPERTY NOTATION 153160
Rule: bit_and_expr 6
Rule: bit_or_expr 4768
Rule: cast 2735
Rule: compare_expr 710
Rule: equality_expr 17012
Rule: expr 2904
Rule: literal 52899
Rule: log_and_expr 6227
Rule: method 194589
Rule: primary_expr 3103
Rule: prod_expr 71
Rule: sum_expr 508
Rule: un_expr 5591
Token: AND 7560
Token: ASSIGN 17608
Token: BIT_AND 6
Token: BIT_OR 4767
Token: BOOL_FALSE 1275
Token: BOOL_TRUE 2533
Token: COMMA 40439
Token: DEC_LITERAL 3
Token: DIVIDE 15
Token: EQUALS 13628
Token: GT 428
Token: GTE 87
Token: HASH 2735
Token: HEX_LITERAL 20
Token: LPARENS 47316
Token: LT 157
Token: LTE 19
Token: MINUS 1032
Token: MODULO 6
Token: MULTIPLY 35
Token: NOT 1938
Token: NOT_EQ 3269
Token: NULL 5869
Token: NUM_LITERAL 12476
Token: OR 6321
Token: PLUS 343
Token: RPARENS 47313
Token: STRING 30717
Token: SYMBOL 54642
Some observations:
  • I found some rules that use data types from org.hibernate.*. These cause some files not to load.
  • When CallGraphWorker there were some errors related to the failure to open the db connection with JanusGraphFactory.open:
    public static JanusGraph open(ReadConfiguration configuration, String backupName) {
        ModifiableConfiguration config = new ModifiableConfiguration(GraphDatabaseConfiguration.ROOT_NS, (WriteConfiguration)configuration, Restriction.NONE);
        String graphName = config.has(GraphDatabaseConfiguration.GRAPH_NAME, new String[0]) ? (String)config.get(GraphDatabaseConfiguration.GRAPH_NAME, new String[0]) : backupName;
        JanusGraphManager jgm = JanusGraphManagerUtility.getInstance();
        if (null != graphName) {
            Preconditions.checkNotNull(jgm, "Gremlin Server must be configured to use the JanusGraphManager.");
            return (JanusGraph)jgm.openGraph(graphName, (gName) -> new StandardJanusGraph((new GraphDatabaseConfigurationBuilder()).build(configuration)));
        } else {
            if (jgm != null) {
                log.warn("You should supply \"graph.graphname\" in your .properties file configuration if you are opening a graph that has not already been opened at server start, i.e. it was defined in your YAML file. This will ensure the graph is tracked by the JanusGraphManager, which will enable autocommit and rollback functionality upon all gremlin script executions. Note that JanusGraphFactory#open(String === shortcut notation) does not support consuming the property \"graph.graphname\" so these graphs should be accessed dynamically by supplying a .properties file here or by using the ConfiguredGraphFactory.");
            }

            return new StandardJanusGraph((new GraphDatabaseConfigurationBuilder()).build(configuration));
        }
    }

In this case, graphName was null and graph.graphName was not accessible. To fix this, I ran CallGraphGenerator.main in TRPLFeatureTracker.main and it worked. After that, I removed the CallGraphGenerator.main call, but the tracker system still has a reference to that callgraph. This is the content of the trace log when CallGraphWorker is needed:
     [java] Generated unique-instance-id=c0a802c052490-aog1
     [java] Configuring index [search]
     [java] Initiated fixed thread pool of size 24
     [java] Configuring total store cache size: 5028244622
     [java] Gremlin script evaluation is disabled
     [java] Loaded unidentified ReadMarker start time 2025-04-28T13:58:04.321937Z into org.janusgraph.diskstorage.log.kcvs.KCVSLog$MessagePuller@24f3830c

All of these changes are committed into 1745a/15803.

#57 Updated by Octavian Adrian Gavril about 1 year ago

I believe that generating/using callgraph is necessary to make rules from rules/reports and rules/callgraph load/compile correctly. Since this feature has not been used before, the error log contains new errors about other rule syntax that have not been loaded before.

#58 Updated by Octavian Adrian Gavril about 1 year ago

I've committed new changes to 1745a/15804 covering the following:
  • Fixed the usage of CallGraphWorker;
  • Fixed logging for included files;
  • Avoided getting type for variable and parameter to ignore the usage of deprecated classes;
  • Cleaned up some .rules/.xml files which generated syntax errors;
  • Avoided applying rules from PatternEngine.run because the copy/source ast is null.

#59 Updated by Octavian Adrian Gavril about 1 year ago

I made some additional changes that fixed the way func-library children are processed. The main idea was to keep track of elements whether they are included or just loaded and take this into account the next time those elements appear. These changes are committed into 1745a/15805.

The current results are as follows:

Feature Number of usages
<action> 22584
<ascent-rules> 138
<ast-spec> 5
<break> 63
<cfg> 65
<continue> 26
<descent-rules> 46
<expression> 220
<func-library> 116
<function> 1044
<include> 198
<init-rules> 250
<next-child-rules> 8
<parameter> 1420
<post-rules> 148
<return> 713
<rule-set> 569
<rule> 19197
<variable> 5977
<walk-rules> 302
<while> 545
<worker> 434
AUTO TYPE CONVERSION 0
AUTO-BOXING 0
AUTOMATIC NULL CHECKING 0
PROPERTY NOTATION 140501
Rule: bit_and_expr 15
Rule: bit_or_expr 2410
Rule: bit_xor_expr 1
Rule: cast 2196
Rule: compare_expr 641
Rule: equality_expr 16636
Rule: expr 2580
Rule: expression 0
Rule: literal 40425
Rule: log_and_expr 5332
Rule: method 174129
Rule: primary_expr 2592
Rule: prod_expr 80
Rule: shift_expr 0
Rule: sum_expr 425
Rule: un_expr 4519
Token: AND 6421
Token: ASSIGN 16640
Token: BIT_AND 15
Token: BIT_COMP 0
Token: BIT_OR 2409
Token: BIT_XOR 1
Token: BOOL_FALSE 1147
Token: BOOL_TRUE 2512
Token: COMMA 34067
Token: DEC_LITERAL 5
Token: DIVIDE 24
Token: EQUALS 13680
Token: GT 376
Token: GTE 90
Token: HASH 2196
Token: HEX_LITERAL 42
Token: LPARENS 38448
Token: LSHIFT 0
Token: LT 151
Token: LTE 14
Token: MINUS 802
Token: MODULO 10
Token: MULTIPLY 37
Token: NOT 1615
Token: NOT_EQ 2853
Token: NULL 5357
Token: NUM_LITERAL 4505
Token: OR 6722
Token: PLUS 294
Token: RPARENS 38448
Token: RSHIFT 0
Token: STRING 26857
Token: SYMBOL 38393
Token: WS 0
Token: ZRSHIFT 0

I think the tracker is in a safe state now, because the results are pretty close to the real numbers. Tracking AUTO TYPE CONVERSION, AUTO-BOXING, AUTOMATIC NULL CHECKING and PROPERTY NOTATION is a bit more complicated than I thought. I used a TestResolver that can only recognize methods (including getters/setters) of type METH_GET_VAR. This way, all expression parsing completed successfully, but expression compilation did not. This happens because all variables or functions are seen as METH_GET_VAR and signature mismatches occur.

I posted some results for these features in the notes above, but all of them were due to the applyGlobal(RULE_INIT) and applyGlobal(RULE_POST) methods in PatternEngine.run. This applies the init/post rules in each .xml file. These method calls were ignored in 15804. PROPERTY NOTATION gets those results because its tracking is implemented in expression.g (independent of Compiler.process).

Greg, seeing these results, do you think this task can be safely paused?

#60 Updated by Greg Shah about 1 year ago

  • Status changed from WIP to Hold

Yes, it is safe to pause.

Also available in: Atom PDF