From 07c477cc8befac2e6fc848d0223ba630232700a5 Mon Sep 17 00:00:00 2001 From: ralikio <74771103+ralikio@users.noreply.github.com> Date: Fri, 31 Jan 2025 19:17:24 +0100 Subject: [PATCH 1/3] Simple Expression Parsing with Antlr and Simple String Splitting --- RuleLexer.g4 | 29 + RuleParser.g4 | 48 + common/hyperscaler/rules/evaluator.go | 39 + .../rules/grammar/antlr/RuleLexer.interp | 56 + .../rules/grammar/antlr/RuleLexer.tokens | 23 + .../rules/grammar/antlr/RuleParser.interp | 51 + .../rules/grammar/antlr/RuleParser.tokens | 23 + .../rules/grammar/antlr/rule_lexer.go | 164 ++ .../grammar/antlr/ruleparser_base_listener.go | 106 + .../grammar/antlr/ruleparser_listener.go | 94 + .../rules/grammar/antlr/ruleparser_parser.go | 2005 +++++++++++++++++ common/hyperscaler/rules/grammar/listener.go | 32 + common/hyperscaler/rules/grammar/parser.go | 31 + .../hyperscaler/rules/grammar/parser_test.go | 11 + common/hyperscaler/rules/parser.go | 5 + common/hyperscaler/rules/parser_test_utils.go | 84 + common/hyperscaler/rules/rule.go | 24 + common/hyperscaler/rules/simple_parser.go | 52 + .../hyperscaler/rules/simple_parser_test.go | 9 + go.mod | 1 + go.sum | 2 + 21 files changed, 2889 insertions(+) create mode 100644 RuleLexer.g4 create mode 100644 RuleParser.g4 create mode 100644 common/hyperscaler/rules/evaluator.go create mode 100644 common/hyperscaler/rules/grammar/antlr/RuleLexer.interp create mode 100644 common/hyperscaler/rules/grammar/antlr/RuleLexer.tokens create mode 100644 common/hyperscaler/rules/grammar/antlr/RuleParser.interp create mode 100644 common/hyperscaler/rules/grammar/antlr/RuleParser.tokens create mode 100644 common/hyperscaler/rules/grammar/antlr/rule_lexer.go create mode 100644 common/hyperscaler/rules/grammar/antlr/ruleparser_base_listener.go create mode 100644 common/hyperscaler/rules/grammar/antlr/ruleparser_listener.go create mode 100644 common/hyperscaler/rules/grammar/antlr/ruleparser_parser.go create mode 100644 common/hyperscaler/rules/grammar/listener.go create mode 100644 common/hyperscaler/rules/grammar/parser.go create mode 100644 common/hyperscaler/rules/grammar/parser_test.go create mode 100644 common/hyperscaler/rules/parser.go create mode 100644 common/hyperscaler/rules/parser_test_utils.go create mode 100644 common/hyperscaler/rules/rule.go create mode 100644 common/hyperscaler/rules/simple_parser.go create mode 100644 common/hyperscaler/rules/simple_parser_test.go diff --git a/RuleLexer.g4 b/RuleLexer.g4 new file mode 100644 index 0000000000..3c90e55bb9 --- /dev/null +++ b/RuleLexer.g4 @@ -0,0 +1,29 @@ +// DELETE THIS CONTENT IF YOU PUT COMBINED GRAMMAR IN Parser TAB +lexer grammar RuleLexer; + +EQ : '=' ; +COMMA : ',' ; +LPAREN : '(' ; +RPAREN : ')' ; +ARROW : '->' ; +ASTERIX : '*' ; + +WS: [ \t\n\r\f]+ -> skip ; + +// TODO: fill in missing plans +PLAN: 'azure' + | 'azure_lite' + | 'aws' + | 'gcp' + | 'trial' + | 'free' + | 'sap-converged-cloud' + ; + +PR: 'PR'; +HR: 'HR'; + +S: 'S'; +EU: 'EU'; + +VAL: [a-zA-Z_-]*[a-zA-Z_0-9]+; \ No newline at end of file diff --git a/RuleParser.g4 b/RuleParser.g4 new file mode 100644 index 0000000000..b5847b981c --- /dev/null +++ b/RuleParser.g4 @@ -0,0 +1,48 @@ +grammar RuleParser; +options { tokenVocab=RuleLexer; } + +ruleEntry + : entry EOF + ; + +entry: PLAN + | PLAN ARROW outputAttrList + | PLAN inputAttrInParen + | PLAN inputAttrInParen ARROW outputAttrList + ; + +inputAttrInParen: LPAREN RPAREN + | LPAREN inputAttrList RPAREN + ; + +inputAttrList: inputAttrVal + | inputAttrVal COMMA inputAttrList + ; + +outputAttrList: outputAttrVal + | outputAttrVal COMMA outputAttrList + ; + +inputAttrVal: prVal + | hrVal + ; + +outputAttrVal: s + | eu + ; + +prVal: pr EQ val; + +hrVal: hr EQ val; + +pr: PR; + +hr: HR; + +s: S; + +eu: EU; + +val: VAL + | ASTERIX + ; \ No newline at end of file diff --git a/common/hyperscaler/rules/evaluator.go b/common/hyperscaler/rules/evaluator.go new file mode 100644 index 0000000000..2dfd1fe72b --- /dev/null +++ b/common/hyperscaler/rules/evaluator.go @@ -0,0 +1,39 @@ +package rules + +type Evaluator struct { + rules []*Rule +} + +func NewEvaluator(parser Parser) *Evaluator { + return &Evaluator{ + // rules: parser.Parse(), + } +} + +/** + * Validate rules. + */ +func (e *Evaluator) Validate() bool { + return true +} + +/** + * Evaluate rules and output search labels. + */ +func (e *Evaluator) Evaluate( /*srk*/ ) string { + matchedRules := e.findMatchedRules( /*srk*/ ) + + // sort rules by priority + matchedRules = e.sortRules(matchedRules) + + // apply one found rule + return matchedRules[0].Labels() +} + +func (e *Evaluator) sortRules(matchedRules []*Rule) []*Rule { + panic("unimplemented") +} + +func (e *Evaluator) findMatchedRules() []*Rule { + panic("unimplemented") +} diff --git a/common/hyperscaler/rules/grammar/antlr/RuleLexer.interp b/common/hyperscaler/rules/grammar/antlr/RuleLexer.interp new file mode 100644 index 0000000000..608427ef70 --- /dev/null +++ b/common/hyperscaler/rules/grammar/antlr/RuleLexer.interp @@ -0,0 +1,56 @@ +token literal names: +null +'=' +',' +'(' +')' +'->' +'*' +null +null +'PR' +'HR' +'S' +'EU' +null + +token symbolic names: +null +EQ +COMMA +LPAREN +RPAREN +ARROW +ASTERIX +WS +PLAN +PR +HR +S +EU +VAL + +rule names: +EQ +COMMA +LPAREN +RPAREN +ARROW +ASTERIX +WS +PLAN +PR +HR +S +EU +VAL + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE + +atn: +[4, 0, 13, 120, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 4, 6, 42, 8, 6, 11, 6, 12, 6, 43, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 97, 8, 7, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 12, 5, 12, 111, 8, 12, 10, 12, 12, 12, 114, 9, 12, 1, 12, 4, 12, 117, 8, 12, 11, 12, 12, 12, 118, 0, 0, 13, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 1, 0, 3, 3, 0, 9, 10, 12, 13, 32, 32, 4, 0, 45, 45, 65, 90, 95, 95, 97, 122, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 128, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 1, 27, 1, 0, 0, 0, 3, 29, 1, 0, 0, 0, 5, 31, 1, 0, 0, 0, 7, 33, 1, 0, 0, 0, 9, 35, 1, 0, 0, 0, 11, 38, 1, 0, 0, 0, 13, 41, 1, 0, 0, 0, 15, 96, 1, 0, 0, 0, 17, 98, 1, 0, 0, 0, 19, 101, 1, 0, 0, 0, 21, 104, 1, 0, 0, 0, 23, 106, 1, 0, 0, 0, 25, 112, 1, 0, 0, 0, 27, 28, 5, 61, 0, 0, 28, 2, 1, 0, 0, 0, 29, 30, 5, 44, 0, 0, 30, 4, 1, 0, 0, 0, 31, 32, 5, 40, 0, 0, 32, 6, 1, 0, 0, 0, 33, 34, 5, 41, 0, 0, 34, 8, 1, 0, 0, 0, 35, 36, 5, 45, 0, 0, 36, 37, 5, 62, 0, 0, 37, 10, 1, 0, 0, 0, 38, 39, 5, 42, 0, 0, 39, 12, 1, 0, 0, 0, 40, 42, 7, 0, 0, 0, 41, 40, 1, 0, 0, 0, 42, 43, 1, 0, 0, 0, 43, 41, 1, 0, 0, 0, 43, 44, 1, 0, 0, 0, 44, 45, 1, 0, 0, 0, 45, 46, 6, 6, 0, 0, 46, 14, 1, 0, 0, 0, 47, 48, 5, 97, 0, 0, 48, 49, 5, 122, 0, 0, 49, 50, 5, 117, 0, 0, 50, 51, 5, 114, 0, 0, 51, 97, 5, 101, 0, 0, 52, 53, 5, 97, 0, 0, 53, 54, 5, 122, 0, 0, 54, 55, 5, 117, 0, 0, 55, 56, 5, 114, 0, 0, 56, 57, 5, 101, 0, 0, 57, 58, 5, 95, 0, 0, 58, 59, 5, 108, 0, 0, 59, 60, 5, 105, 0, 0, 60, 61, 5, 116, 0, 0, 61, 97, 5, 101, 0, 0, 62, 63, 5, 97, 0, 0, 63, 64, 5, 119, 0, 0, 64, 97, 5, 115, 0, 0, 65, 66, 5, 103, 0, 0, 66, 67, 5, 99, 0, 0, 67, 97, 5, 112, 0, 0, 68, 69, 5, 116, 0, 0, 69, 70, 5, 114, 0, 0, 70, 71, 5, 105, 0, 0, 71, 72, 5, 97, 0, 0, 72, 97, 5, 108, 0, 0, 73, 74, 5, 102, 0, 0, 74, 75, 5, 114, 0, 0, 75, 76, 5, 101, 0, 0, 76, 97, 5, 101, 0, 0, 77, 78, 5, 115, 0, 0, 78, 79, 5, 97, 0, 0, 79, 80, 5, 112, 0, 0, 80, 81, 5, 45, 0, 0, 81, 82, 5, 99, 0, 0, 82, 83, 5, 111, 0, 0, 83, 84, 5, 110, 0, 0, 84, 85, 5, 118, 0, 0, 85, 86, 5, 101, 0, 0, 86, 87, 5, 114, 0, 0, 87, 88, 5, 103, 0, 0, 88, 89, 5, 101, 0, 0, 89, 90, 5, 100, 0, 0, 90, 91, 5, 45, 0, 0, 91, 92, 5, 99, 0, 0, 92, 93, 5, 108, 0, 0, 93, 94, 5, 111, 0, 0, 94, 95, 5, 117, 0, 0, 95, 97, 5, 100, 0, 0, 96, 47, 1, 0, 0, 0, 96, 52, 1, 0, 0, 0, 96, 62, 1, 0, 0, 0, 96, 65, 1, 0, 0, 0, 96, 68, 1, 0, 0, 0, 96, 73, 1, 0, 0, 0, 96, 77, 1, 0, 0, 0, 97, 16, 1, 0, 0, 0, 98, 99, 5, 80, 0, 0, 99, 100, 5, 82, 0, 0, 100, 18, 1, 0, 0, 0, 101, 102, 5, 72, 0, 0, 102, 103, 5, 82, 0, 0, 103, 20, 1, 0, 0, 0, 104, 105, 5, 83, 0, 0, 105, 22, 1, 0, 0, 0, 106, 107, 5, 69, 0, 0, 107, 108, 5, 85, 0, 0, 108, 24, 1, 0, 0, 0, 109, 111, 7, 1, 0, 0, 110, 109, 1, 0, 0, 0, 111, 114, 1, 0, 0, 0, 112, 110, 1, 0, 0, 0, 112, 113, 1, 0, 0, 0, 113, 116, 1, 0, 0, 0, 114, 112, 1, 0, 0, 0, 115, 117, 7, 2, 0, 0, 116, 115, 1, 0, 0, 0, 117, 118, 1, 0, 0, 0, 118, 116, 1, 0, 0, 0, 118, 119, 1, 0, 0, 0, 119, 26, 1, 0, 0, 0, 5, 0, 43, 96, 112, 118, 1, 6, 0, 0] \ No newline at end of file diff --git a/common/hyperscaler/rules/grammar/antlr/RuleLexer.tokens b/common/hyperscaler/rules/grammar/antlr/RuleLexer.tokens new file mode 100644 index 0000000000..34c37e2b96 --- /dev/null +++ b/common/hyperscaler/rules/grammar/antlr/RuleLexer.tokens @@ -0,0 +1,23 @@ +EQ=1 +COMMA=2 +LPAREN=3 +RPAREN=4 +ARROW=5 +ASTERIX=6 +WS=7 +PLAN=8 +PR=9 +HR=10 +S=11 +EU=12 +VAL=13 +'='=1 +','=2 +'('=3 +')'=4 +'->'=5 +'*'=6 +'PR'=9 +'HR'=10 +'S'=11 +'EU'=12 diff --git a/common/hyperscaler/rules/grammar/antlr/RuleParser.interp b/common/hyperscaler/rules/grammar/antlr/RuleParser.interp new file mode 100644 index 0000000000..1903f2824f --- /dev/null +++ b/common/hyperscaler/rules/grammar/antlr/RuleParser.interp @@ -0,0 +1,51 @@ +token literal names: +null +'=' +',' +'(' +')' +'->' +'*' +null +null +'PR' +'HR' +'S' +'EU' +null + +token symbolic names: +null +EQ +COMMA +LPAREN +RPAREN +ARROW +ASTERIX +WS +PLAN +PR +HR +S +EU +VAL + +rule names: +ruleEntry +entry +inputAttrInParen +inputAttrList +outputAttrList +inputAttrVal +outputAttrVal +prVal +hrVal +pr +hr +s +eu +val + + +atn: +[4, 1, 13, 93, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 43, 8, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 51, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 58, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 65, 8, 4, 1, 5, 1, 5, 3, 5, 69, 8, 5, 1, 6, 1, 6, 3, 6, 73, 8, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 0, 0, 14, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 0, 1, 2, 0, 6, 6, 13, 13, 86, 0, 28, 1, 0, 0, 0, 2, 42, 1, 0, 0, 0, 4, 50, 1, 0, 0, 0, 6, 57, 1, 0, 0, 0, 8, 64, 1, 0, 0, 0, 10, 68, 1, 0, 0, 0, 12, 72, 1, 0, 0, 0, 14, 74, 1, 0, 0, 0, 16, 78, 1, 0, 0, 0, 18, 82, 1, 0, 0, 0, 20, 84, 1, 0, 0, 0, 22, 86, 1, 0, 0, 0, 24, 88, 1, 0, 0, 0, 26, 90, 1, 0, 0, 0, 28, 29, 3, 2, 1, 0, 29, 30, 5, 0, 0, 1, 30, 1, 1, 0, 0, 0, 31, 43, 5, 8, 0, 0, 32, 33, 5, 8, 0, 0, 33, 34, 5, 5, 0, 0, 34, 43, 3, 8, 4, 0, 35, 36, 5, 8, 0, 0, 36, 43, 3, 4, 2, 0, 37, 38, 5, 8, 0, 0, 38, 39, 3, 4, 2, 0, 39, 40, 5, 5, 0, 0, 40, 41, 3, 8, 4, 0, 41, 43, 1, 0, 0, 0, 42, 31, 1, 0, 0, 0, 42, 32, 1, 0, 0, 0, 42, 35, 1, 0, 0, 0, 42, 37, 1, 0, 0, 0, 43, 3, 1, 0, 0, 0, 44, 45, 5, 3, 0, 0, 45, 51, 5, 4, 0, 0, 46, 47, 5, 3, 0, 0, 47, 48, 3, 6, 3, 0, 48, 49, 5, 4, 0, 0, 49, 51, 1, 0, 0, 0, 50, 44, 1, 0, 0, 0, 50, 46, 1, 0, 0, 0, 51, 5, 1, 0, 0, 0, 52, 58, 3, 10, 5, 0, 53, 54, 3, 10, 5, 0, 54, 55, 5, 2, 0, 0, 55, 56, 3, 6, 3, 0, 56, 58, 1, 0, 0, 0, 57, 52, 1, 0, 0, 0, 57, 53, 1, 0, 0, 0, 58, 7, 1, 0, 0, 0, 59, 65, 3, 12, 6, 0, 60, 61, 3, 12, 6, 0, 61, 62, 5, 2, 0, 0, 62, 63, 3, 8, 4, 0, 63, 65, 1, 0, 0, 0, 64, 59, 1, 0, 0, 0, 64, 60, 1, 0, 0, 0, 65, 9, 1, 0, 0, 0, 66, 69, 3, 14, 7, 0, 67, 69, 3, 16, 8, 0, 68, 66, 1, 0, 0, 0, 68, 67, 1, 0, 0, 0, 69, 11, 1, 0, 0, 0, 70, 73, 3, 22, 11, 0, 71, 73, 3, 24, 12, 0, 72, 70, 1, 0, 0, 0, 72, 71, 1, 0, 0, 0, 73, 13, 1, 0, 0, 0, 74, 75, 3, 18, 9, 0, 75, 76, 5, 1, 0, 0, 76, 77, 3, 26, 13, 0, 77, 15, 1, 0, 0, 0, 78, 79, 3, 20, 10, 0, 79, 80, 5, 1, 0, 0, 80, 81, 3, 26, 13, 0, 81, 17, 1, 0, 0, 0, 82, 83, 5, 9, 0, 0, 83, 19, 1, 0, 0, 0, 84, 85, 5, 10, 0, 0, 85, 21, 1, 0, 0, 0, 86, 87, 5, 11, 0, 0, 87, 23, 1, 0, 0, 0, 88, 89, 5, 12, 0, 0, 89, 25, 1, 0, 0, 0, 90, 91, 7, 0, 0, 0, 91, 27, 1, 0, 0, 0, 6, 42, 50, 57, 64, 68, 72] \ No newline at end of file diff --git a/common/hyperscaler/rules/grammar/antlr/RuleParser.tokens b/common/hyperscaler/rules/grammar/antlr/RuleParser.tokens new file mode 100644 index 0000000000..34c37e2b96 --- /dev/null +++ b/common/hyperscaler/rules/grammar/antlr/RuleParser.tokens @@ -0,0 +1,23 @@ +EQ=1 +COMMA=2 +LPAREN=3 +RPAREN=4 +ARROW=5 +ASTERIX=6 +WS=7 +PLAN=8 +PR=9 +HR=10 +S=11 +EU=12 +VAL=13 +'='=1 +','=2 +'('=3 +')'=4 +'->'=5 +'*'=6 +'PR'=9 +'HR'=10 +'S'=11 +'EU'=12 diff --git a/common/hyperscaler/rules/grammar/antlr/rule_lexer.go b/common/hyperscaler/rules/grammar/antlr/rule_lexer.go new file mode 100644 index 0000000000..0d4c3328b7 --- /dev/null +++ b/common/hyperscaler/rules/grammar/antlr/rule_lexer.go @@ -0,0 +1,164 @@ +// Code generated from RuleLexer.g4 by ANTLR 4.13.2. DO NOT EDIT. + +package parser + +import ( + "fmt" + "github.com/antlr4-go/antlr/v4" + "sync" + "unicode" +) + +// Suppress unused import error +var _ = fmt.Printf +var _ = sync.Once{} +var _ = unicode.IsLetter + +type RuleLexer struct { + *antlr.BaseLexer + channelNames []string + modeNames []string + // TODO: EOF string +} + +var RuleLexerLexerStaticData struct { + once sync.Once + serializedATN []int32 + ChannelNames []string + ModeNames []string + LiteralNames []string + SymbolicNames []string + RuleNames []string + PredictionContextCache *antlr.PredictionContextCache + atn *antlr.ATN + decisionToDFA []*antlr.DFA +} + +func rulelexerLexerInit() { + staticData := &RuleLexerLexerStaticData + staticData.ChannelNames = []string{ + "DEFAULT_TOKEN_CHANNEL", "HIDDEN", + } + staticData.ModeNames = []string{ + "DEFAULT_MODE", + } + staticData.LiteralNames = []string{ + "", "'='", "','", "'('", "')'", "'->'", "'*'", "", "", "'PR'", "'HR'", + "'S'", "'EU'", + } + staticData.SymbolicNames = []string{ + "", "EQ", "COMMA", "LPAREN", "RPAREN", "ARROW", "ASTERIX", "WS", "PLAN", + "PR", "HR", "S", "EU", "VAL", + } + staticData.RuleNames = []string{ + "EQ", "COMMA", "LPAREN", "RPAREN", "ARROW", "ASTERIX", "WS", "PLAN", + "PR", "HR", "S", "EU", "VAL", + } + staticData.PredictionContextCache = antlr.NewPredictionContextCache() + staticData.serializedATN = []int32{ + 4, 0, 13, 120, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, + 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, + 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, + 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 4, 6, 42, 8, 6, 11, + 6, 12, 6, 43, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, + 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, + 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, + 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, + 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 3, 7, 97, 8, 7, 1, 8, 1, 8, 1, 8, 1, 9, + 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 12, 5, 12, 111, 8, 12, + 10, 12, 12, 12, 114, 9, 12, 1, 12, 4, 12, 117, 8, 12, 11, 12, 12, 12, 118, + 0, 0, 13, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, + 10, 21, 11, 23, 12, 25, 13, 1, 0, 3, 3, 0, 9, 10, 12, 13, 32, 32, 4, 0, + 45, 45, 65, 90, 95, 95, 97, 122, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, + 128, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, + 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, + 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, + 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 1, 27, 1, 0, 0, 0, 3, 29, 1, 0, 0, 0, 5, + 31, 1, 0, 0, 0, 7, 33, 1, 0, 0, 0, 9, 35, 1, 0, 0, 0, 11, 38, 1, 0, 0, + 0, 13, 41, 1, 0, 0, 0, 15, 96, 1, 0, 0, 0, 17, 98, 1, 0, 0, 0, 19, 101, + 1, 0, 0, 0, 21, 104, 1, 0, 0, 0, 23, 106, 1, 0, 0, 0, 25, 112, 1, 0, 0, + 0, 27, 28, 5, 61, 0, 0, 28, 2, 1, 0, 0, 0, 29, 30, 5, 44, 0, 0, 30, 4, + 1, 0, 0, 0, 31, 32, 5, 40, 0, 0, 32, 6, 1, 0, 0, 0, 33, 34, 5, 41, 0, 0, + 34, 8, 1, 0, 0, 0, 35, 36, 5, 45, 0, 0, 36, 37, 5, 62, 0, 0, 37, 10, 1, + 0, 0, 0, 38, 39, 5, 42, 0, 0, 39, 12, 1, 0, 0, 0, 40, 42, 7, 0, 0, 0, 41, + 40, 1, 0, 0, 0, 42, 43, 1, 0, 0, 0, 43, 41, 1, 0, 0, 0, 43, 44, 1, 0, 0, + 0, 44, 45, 1, 0, 0, 0, 45, 46, 6, 6, 0, 0, 46, 14, 1, 0, 0, 0, 47, 48, + 5, 97, 0, 0, 48, 49, 5, 122, 0, 0, 49, 50, 5, 117, 0, 0, 50, 51, 5, 114, + 0, 0, 51, 97, 5, 101, 0, 0, 52, 53, 5, 97, 0, 0, 53, 54, 5, 122, 0, 0, + 54, 55, 5, 117, 0, 0, 55, 56, 5, 114, 0, 0, 56, 57, 5, 101, 0, 0, 57, 58, + 5, 95, 0, 0, 58, 59, 5, 108, 0, 0, 59, 60, 5, 105, 0, 0, 60, 61, 5, 116, + 0, 0, 61, 97, 5, 101, 0, 0, 62, 63, 5, 97, 0, 0, 63, 64, 5, 119, 0, 0, + 64, 97, 5, 115, 0, 0, 65, 66, 5, 103, 0, 0, 66, 67, 5, 99, 0, 0, 67, 97, + 5, 112, 0, 0, 68, 69, 5, 116, 0, 0, 69, 70, 5, 114, 0, 0, 70, 71, 5, 105, + 0, 0, 71, 72, 5, 97, 0, 0, 72, 97, 5, 108, 0, 0, 73, 74, 5, 102, 0, 0, + 74, 75, 5, 114, 0, 0, 75, 76, 5, 101, 0, 0, 76, 97, 5, 101, 0, 0, 77, 78, + 5, 115, 0, 0, 78, 79, 5, 97, 0, 0, 79, 80, 5, 112, 0, 0, 80, 81, 5, 45, + 0, 0, 81, 82, 5, 99, 0, 0, 82, 83, 5, 111, 0, 0, 83, 84, 5, 110, 0, 0, + 84, 85, 5, 118, 0, 0, 85, 86, 5, 101, 0, 0, 86, 87, 5, 114, 0, 0, 87, 88, + 5, 103, 0, 0, 88, 89, 5, 101, 0, 0, 89, 90, 5, 100, 0, 0, 90, 91, 5, 45, + 0, 0, 91, 92, 5, 99, 0, 0, 92, 93, 5, 108, 0, 0, 93, 94, 5, 111, 0, 0, + 94, 95, 5, 117, 0, 0, 95, 97, 5, 100, 0, 0, 96, 47, 1, 0, 0, 0, 96, 52, + 1, 0, 0, 0, 96, 62, 1, 0, 0, 0, 96, 65, 1, 0, 0, 0, 96, 68, 1, 0, 0, 0, + 96, 73, 1, 0, 0, 0, 96, 77, 1, 0, 0, 0, 97, 16, 1, 0, 0, 0, 98, 99, 5, + 80, 0, 0, 99, 100, 5, 82, 0, 0, 100, 18, 1, 0, 0, 0, 101, 102, 5, 72, 0, + 0, 102, 103, 5, 82, 0, 0, 103, 20, 1, 0, 0, 0, 104, 105, 5, 83, 0, 0, 105, + 22, 1, 0, 0, 0, 106, 107, 5, 69, 0, 0, 107, 108, 5, 85, 0, 0, 108, 24, + 1, 0, 0, 0, 109, 111, 7, 1, 0, 0, 110, 109, 1, 0, 0, 0, 111, 114, 1, 0, + 0, 0, 112, 110, 1, 0, 0, 0, 112, 113, 1, 0, 0, 0, 113, 116, 1, 0, 0, 0, + 114, 112, 1, 0, 0, 0, 115, 117, 7, 2, 0, 0, 116, 115, 1, 0, 0, 0, 117, + 118, 1, 0, 0, 0, 118, 116, 1, 0, 0, 0, 118, 119, 1, 0, 0, 0, 119, 26, 1, + 0, 0, 0, 5, 0, 43, 96, 112, 118, 1, 6, 0, 0, + } + deserializer := antlr.NewATNDeserializer(nil) + staticData.atn = deserializer.Deserialize(staticData.serializedATN) + atn := staticData.atn + staticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState)) + decisionToDFA := staticData.decisionToDFA + for index, state := range atn.DecisionToState { + decisionToDFA[index] = antlr.NewDFA(state, index) + } +} + +// RuleLexerInit initializes any static state used to implement RuleLexer. By default the +// static state used to implement the lexer is lazily initialized during the first call to +// NewRuleLexer(). You can call this function if you wish to initialize the static state ahead +// of time. +func RuleLexerInit() { + staticData := &RuleLexerLexerStaticData + staticData.once.Do(rulelexerLexerInit) +} + +// NewRuleLexer produces a new lexer instance for the optional input antlr.CharStream. +func NewRuleLexer(input antlr.CharStream) *RuleLexer { + RuleLexerInit() + l := new(RuleLexer) + l.BaseLexer = antlr.NewBaseLexer(input) + staticData := &RuleLexerLexerStaticData + l.Interpreter = antlr.NewLexerATNSimulator(l, staticData.atn, staticData.decisionToDFA, staticData.PredictionContextCache) + l.channelNames = staticData.ChannelNames + l.modeNames = staticData.ModeNames + l.RuleNames = staticData.RuleNames + l.LiteralNames = staticData.LiteralNames + l.SymbolicNames = staticData.SymbolicNames + l.GrammarFileName = "RuleLexer.g4" + // TODO: l.EOF = antlr.TokenEOF + + return l +} + +// RuleLexer tokens. +const ( + RuleLexerEQ = 1 + RuleLexerCOMMA = 2 + RuleLexerLPAREN = 3 + RuleLexerRPAREN = 4 + RuleLexerARROW = 5 + RuleLexerASTERIX = 6 + RuleLexerWS = 7 + RuleLexerPLAN = 8 + RuleLexerPR = 9 + RuleLexerHR = 10 + RuleLexerS = 11 + RuleLexerEU = 12 + RuleLexerVAL = 13 +) diff --git a/common/hyperscaler/rules/grammar/antlr/ruleparser_base_listener.go b/common/hyperscaler/rules/grammar/antlr/ruleparser_base_listener.go new file mode 100644 index 0000000000..08eedc4a92 --- /dev/null +++ b/common/hyperscaler/rules/grammar/antlr/ruleparser_base_listener.go @@ -0,0 +1,106 @@ +// Code generated from RuleParser.g4 by ANTLR 4.13.2. DO NOT EDIT. + +package parser // RuleParser + +import "github.com/antlr4-go/antlr/v4" + +// BaseRuleParserListener is a complete listener for a parse tree produced by RuleParserParser. +type BaseRuleParserListener struct{} + +var _ RuleParserListener = &BaseRuleParserListener{} + +// VisitTerminal is called when a terminal node is visited. +func (s *BaseRuleParserListener) VisitTerminal(node antlr.TerminalNode) {} + +// VisitErrorNode is called when an error node is visited. +func (s *BaseRuleParserListener) VisitErrorNode(node antlr.ErrorNode) {} + +// EnterEveryRule is called when any rule is entered. +func (s *BaseRuleParserListener) EnterEveryRule(ctx antlr.ParserRuleContext) {} + +// ExitEveryRule is called when any rule is exited. +func (s *BaseRuleParserListener) ExitEveryRule(ctx antlr.ParserRuleContext) {} + +// EnterRuleEntry is called when production ruleEntry is entered. +func (s *BaseRuleParserListener) EnterRuleEntry(ctx *RuleEntryContext) {} + +// ExitRuleEntry is called when production ruleEntry is exited. +func (s *BaseRuleParserListener) ExitRuleEntry(ctx *RuleEntryContext) {} + +// EnterEntry is called when production entry is entered. +func (s *BaseRuleParserListener) EnterEntry(ctx *EntryContext) {} + +// ExitEntry is called when production entry is exited. +func (s *BaseRuleParserListener) ExitEntry(ctx *EntryContext) {} + +// EnterInputAttrInParen is called when production inputAttrInParen is entered. +func (s *BaseRuleParserListener) EnterInputAttrInParen(ctx *InputAttrInParenContext) {} + +// ExitInputAttrInParen is called when production inputAttrInParen is exited. +func (s *BaseRuleParserListener) ExitInputAttrInParen(ctx *InputAttrInParenContext) {} + +// EnterInputAttrList is called when production inputAttrList is entered. +func (s *BaseRuleParserListener) EnterInputAttrList(ctx *InputAttrListContext) {} + +// ExitInputAttrList is called when production inputAttrList is exited. +func (s *BaseRuleParserListener) ExitInputAttrList(ctx *InputAttrListContext) {} + +// EnterOutputAttrList is called when production outputAttrList is entered. +func (s *BaseRuleParserListener) EnterOutputAttrList(ctx *OutputAttrListContext) {} + +// ExitOutputAttrList is called when production outputAttrList is exited. +func (s *BaseRuleParserListener) ExitOutputAttrList(ctx *OutputAttrListContext) {} + +// EnterInputAttrVal is called when production inputAttrVal is entered. +func (s *BaseRuleParserListener) EnterInputAttrVal(ctx *InputAttrValContext) {} + +// ExitInputAttrVal is called when production inputAttrVal is exited. +func (s *BaseRuleParserListener) ExitInputAttrVal(ctx *InputAttrValContext) {} + +// EnterOutputAttrVal is called when production outputAttrVal is entered. +func (s *BaseRuleParserListener) EnterOutputAttrVal(ctx *OutputAttrValContext) {} + +// ExitOutputAttrVal is called when production outputAttrVal is exited. +func (s *BaseRuleParserListener) ExitOutputAttrVal(ctx *OutputAttrValContext) {} + +// EnterPrVal is called when production prVal is entered. +func (s *BaseRuleParserListener) EnterPrVal(ctx *PrValContext) {} + +// ExitPrVal is called when production prVal is exited. +func (s *BaseRuleParserListener) ExitPrVal(ctx *PrValContext) {} + +// EnterHrVal is called when production hrVal is entered. +func (s *BaseRuleParserListener) EnterHrVal(ctx *HrValContext) {} + +// ExitHrVal is called when production hrVal is exited. +func (s *BaseRuleParserListener) ExitHrVal(ctx *HrValContext) {} + +// EnterPr is called when production pr is entered. +func (s *BaseRuleParserListener) EnterPr(ctx *PrContext) {} + +// ExitPr is called when production pr is exited. +func (s *BaseRuleParserListener) ExitPr(ctx *PrContext) {} + +// EnterHr is called when production hr is entered. +func (s *BaseRuleParserListener) EnterHr(ctx *HrContext) {} + +// ExitHr is called when production hr is exited. +func (s *BaseRuleParserListener) ExitHr(ctx *HrContext) {} + +// EnterS is called when production s is entered. +func (s *BaseRuleParserListener) EnterS(ctx *SContext) {} + +// ExitS is called when production s is exited. +func (s *BaseRuleParserListener) ExitS(ctx *SContext) {} + +// EnterEu is called when production eu is entered. +func (s *BaseRuleParserListener) EnterEu(ctx *EuContext) {} + +// ExitEu is called when production eu is exited. +func (s *BaseRuleParserListener) ExitEu(ctx *EuContext) {} + +// EnterVal is called when production val is entered. +func (s *BaseRuleParserListener) EnterVal(ctx *ValContext) {} + +// ExitVal is called when production val is exited. +func (s *BaseRuleParserListener) ExitVal(ctx *ValContext) {} diff --git a/common/hyperscaler/rules/grammar/antlr/ruleparser_listener.go b/common/hyperscaler/rules/grammar/antlr/ruleparser_listener.go new file mode 100644 index 0000000000..77b0be35ba --- /dev/null +++ b/common/hyperscaler/rules/grammar/antlr/ruleparser_listener.go @@ -0,0 +1,94 @@ +// Code generated from RuleParser.g4 by ANTLR 4.13.2. DO NOT EDIT. + +package parser // RuleParser + +import "github.com/antlr4-go/antlr/v4" + +// RuleParserListener is a complete listener for a parse tree produced by RuleParserParser. +type RuleParserListener interface { + antlr.ParseTreeListener + + // EnterRuleEntry is called when entering the ruleEntry production. + EnterRuleEntry(c *RuleEntryContext) + + // EnterEntry is called when entering the entry production. + EnterEntry(c *EntryContext) + + // EnterInputAttrInParen is called when entering the inputAttrInParen production. + EnterInputAttrInParen(c *InputAttrInParenContext) + + // EnterInputAttrList is called when entering the inputAttrList production. + EnterInputAttrList(c *InputAttrListContext) + + // EnterOutputAttrList is called when entering the outputAttrList production. + EnterOutputAttrList(c *OutputAttrListContext) + + // EnterInputAttrVal is called when entering the inputAttrVal production. + EnterInputAttrVal(c *InputAttrValContext) + + // EnterOutputAttrVal is called when entering the outputAttrVal production. + EnterOutputAttrVal(c *OutputAttrValContext) + + // EnterPrVal is called when entering the prVal production. + EnterPrVal(c *PrValContext) + + // EnterHrVal is called when entering the hrVal production. + EnterHrVal(c *HrValContext) + + // EnterPr is called when entering the pr production. + EnterPr(c *PrContext) + + // EnterHr is called when entering the hr production. + EnterHr(c *HrContext) + + // EnterS is called when entering the s production. + EnterS(c *SContext) + + // EnterEu is called when entering the eu production. + EnterEu(c *EuContext) + + // EnterVal is called when entering the val production. + EnterVal(c *ValContext) + + // ExitRuleEntry is called when exiting the ruleEntry production. + ExitRuleEntry(c *RuleEntryContext) + + // ExitEntry is called when exiting the entry production. + ExitEntry(c *EntryContext) + + // ExitInputAttrInParen is called when exiting the inputAttrInParen production. + ExitInputAttrInParen(c *InputAttrInParenContext) + + // ExitInputAttrList is called when exiting the inputAttrList production. + ExitInputAttrList(c *InputAttrListContext) + + // ExitOutputAttrList is called when exiting the outputAttrList production. + ExitOutputAttrList(c *OutputAttrListContext) + + // ExitInputAttrVal is called when exiting the inputAttrVal production. + ExitInputAttrVal(c *InputAttrValContext) + + // ExitOutputAttrVal is called when exiting the outputAttrVal production. + ExitOutputAttrVal(c *OutputAttrValContext) + + // ExitPrVal is called when exiting the prVal production. + ExitPrVal(c *PrValContext) + + // ExitHrVal is called when exiting the hrVal production. + ExitHrVal(c *HrValContext) + + // ExitPr is called when exiting the pr production. + ExitPr(c *PrContext) + + // ExitHr is called when exiting the hr production. + ExitHr(c *HrContext) + + // ExitS is called when exiting the s production. + ExitS(c *SContext) + + // ExitEu is called when exiting the eu production. + ExitEu(c *EuContext) + + // ExitVal is called when exiting the val production. + ExitVal(c *ValContext) +} diff --git a/common/hyperscaler/rules/grammar/antlr/ruleparser_parser.go b/common/hyperscaler/rules/grammar/antlr/ruleparser_parser.go new file mode 100644 index 0000000000..dfaf69643d --- /dev/null +++ b/common/hyperscaler/rules/grammar/antlr/ruleparser_parser.go @@ -0,0 +1,2005 @@ +// Code generated from RuleParser.g4 by ANTLR 4.13.2. DO NOT EDIT. + +package parser // RuleParser + +import ( + "fmt" + "strconv" + "sync" + + "github.com/antlr4-go/antlr/v4" +) + +// Suppress unused import errors +var _ = fmt.Printf +var _ = strconv.Itoa +var _ = sync.Once{} + +type RuleParserParser struct { + *antlr.BaseParser +} + +var RuleParserParserStaticData struct { + once sync.Once + serializedATN []int32 + LiteralNames []string + SymbolicNames []string + RuleNames []string + PredictionContextCache *antlr.PredictionContextCache + atn *antlr.ATN + decisionToDFA []*antlr.DFA +} + +func ruleparserParserInit() { + staticData := &RuleParserParserStaticData + staticData.LiteralNames = []string{ + "", "'='", "','", "'('", "')'", "'->'", "'*'", "", "", "'PR'", "'HR'", + "'S'", "'EU'", + } + staticData.SymbolicNames = []string{ + "", "EQ", "COMMA", "LPAREN", "RPAREN", "ARROW", "ASTERIX", "WS", "PLAN", + "PR", "HR", "S", "EU", "VAL", + } + staticData.RuleNames = []string{ + "ruleEntry", "entry", "inputAttrInParen", "inputAttrList", "outputAttrList", + "inputAttrVal", "outputAttrVal", "prVal", "hrVal", "pr", "hr", "s", + "eu", "val", + } + staticData.PredictionContextCache = antlr.NewPredictionContextCache() + staticData.serializedATN = []int32{ + 4, 1, 13, 93, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, + 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, + 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 1, 0, 1, 0, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 43, 8, 1, + 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 51, 8, 2, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 3, 3, 58, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 65, 8, 4, + 1, 5, 1, 5, 3, 5, 69, 8, 5, 1, 6, 1, 6, 3, 6, 73, 8, 6, 1, 7, 1, 7, 1, + 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 1, 11, 1, 11, + 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 0, 0, 14, 0, 2, 4, 6, 8, 10, 12, 14, + 16, 18, 20, 22, 24, 26, 0, 1, 2, 0, 6, 6, 13, 13, 86, 0, 28, 1, 0, 0, 0, + 2, 42, 1, 0, 0, 0, 4, 50, 1, 0, 0, 0, 6, 57, 1, 0, 0, 0, 8, 64, 1, 0, 0, + 0, 10, 68, 1, 0, 0, 0, 12, 72, 1, 0, 0, 0, 14, 74, 1, 0, 0, 0, 16, 78, + 1, 0, 0, 0, 18, 82, 1, 0, 0, 0, 20, 84, 1, 0, 0, 0, 22, 86, 1, 0, 0, 0, + 24, 88, 1, 0, 0, 0, 26, 90, 1, 0, 0, 0, 28, 29, 3, 2, 1, 0, 29, 30, 5, + 0, 0, 1, 30, 1, 1, 0, 0, 0, 31, 43, 5, 8, 0, 0, 32, 33, 5, 8, 0, 0, 33, + 34, 5, 5, 0, 0, 34, 43, 3, 8, 4, 0, 35, 36, 5, 8, 0, 0, 36, 43, 3, 4, 2, + 0, 37, 38, 5, 8, 0, 0, 38, 39, 3, 4, 2, 0, 39, 40, 5, 5, 0, 0, 40, 41, + 3, 8, 4, 0, 41, 43, 1, 0, 0, 0, 42, 31, 1, 0, 0, 0, 42, 32, 1, 0, 0, 0, + 42, 35, 1, 0, 0, 0, 42, 37, 1, 0, 0, 0, 43, 3, 1, 0, 0, 0, 44, 45, 5, 3, + 0, 0, 45, 51, 5, 4, 0, 0, 46, 47, 5, 3, 0, 0, 47, 48, 3, 6, 3, 0, 48, 49, + 5, 4, 0, 0, 49, 51, 1, 0, 0, 0, 50, 44, 1, 0, 0, 0, 50, 46, 1, 0, 0, 0, + 51, 5, 1, 0, 0, 0, 52, 58, 3, 10, 5, 0, 53, 54, 3, 10, 5, 0, 54, 55, 5, + 2, 0, 0, 55, 56, 3, 6, 3, 0, 56, 58, 1, 0, 0, 0, 57, 52, 1, 0, 0, 0, 57, + 53, 1, 0, 0, 0, 58, 7, 1, 0, 0, 0, 59, 65, 3, 12, 6, 0, 60, 61, 3, 12, + 6, 0, 61, 62, 5, 2, 0, 0, 62, 63, 3, 8, 4, 0, 63, 65, 1, 0, 0, 0, 64, 59, + 1, 0, 0, 0, 64, 60, 1, 0, 0, 0, 65, 9, 1, 0, 0, 0, 66, 69, 3, 14, 7, 0, + 67, 69, 3, 16, 8, 0, 68, 66, 1, 0, 0, 0, 68, 67, 1, 0, 0, 0, 69, 11, 1, + 0, 0, 0, 70, 73, 3, 22, 11, 0, 71, 73, 3, 24, 12, 0, 72, 70, 1, 0, 0, 0, + 72, 71, 1, 0, 0, 0, 73, 13, 1, 0, 0, 0, 74, 75, 3, 18, 9, 0, 75, 76, 5, + 1, 0, 0, 76, 77, 3, 26, 13, 0, 77, 15, 1, 0, 0, 0, 78, 79, 3, 20, 10, 0, + 79, 80, 5, 1, 0, 0, 80, 81, 3, 26, 13, 0, 81, 17, 1, 0, 0, 0, 82, 83, 5, + 9, 0, 0, 83, 19, 1, 0, 0, 0, 84, 85, 5, 10, 0, 0, 85, 21, 1, 0, 0, 0, 86, + 87, 5, 11, 0, 0, 87, 23, 1, 0, 0, 0, 88, 89, 5, 12, 0, 0, 89, 25, 1, 0, + 0, 0, 90, 91, 7, 0, 0, 0, 91, 27, 1, 0, 0, 0, 6, 42, 50, 57, 64, 68, 72, + } + deserializer := antlr.NewATNDeserializer(nil) + staticData.atn = deserializer.Deserialize(staticData.serializedATN) + atn := staticData.atn + staticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState)) + decisionToDFA := staticData.decisionToDFA + for index, state := range atn.DecisionToState { + decisionToDFA[index] = antlr.NewDFA(state, index) + } +} + +// RuleParserParserInit initializes any static state used to implement RuleParserParser. By default the +// static state used to implement the parser is lazily initialized during the first call to +// NewRuleParserParser(). You can call this function if you wish to initialize the static state ahead +// of time. +func RuleParserParserInit() { + staticData := &RuleParserParserStaticData + staticData.once.Do(ruleparserParserInit) +} + +// NewRuleParserParser produces a new parser instance for the optional input antlr.TokenStream. +func NewRuleParserParser(input antlr.TokenStream) *RuleParserParser { + RuleParserParserInit() + this := new(RuleParserParser) + this.BaseParser = antlr.NewBaseParser(input) + staticData := &RuleParserParserStaticData + this.Interpreter = antlr.NewParserATNSimulator(this, staticData.atn, staticData.decisionToDFA, staticData.PredictionContextCache) + this.RuleNames = staticData.RuleNames + this.LiteralNames = staticData.LiteralNames + this.SymbolicNames = staticData.SymbolicNames + this.GrammarFileName = "RuleParser.g4" + + return this +} + +// RuleParserParser tokens. +const ( + RuleParserParserEOF = antlr.TokenEOF + RuleParserParserEQ = 1 + RuleParserParserCOMMA = 2 + RuleParserParserLPAREN = 3 + RuleParserParserRPAREN = 4 + RuleParserParserARROW = 5 + RuleParserParserASTERIX = 6 + RuleParserParserWS = 7 + RuleParserParserPLAN = 8 + RuleParserParserPR = 9 + RuleParserParserHR = 10 + RuleParserParserS = 11 + RuleParserParserEU = 12 + RuleParserParserVAL = 13 +) + +// RuleParserParser rules. +const ( + RuleParserParserRULE_ruleEntry = 0 + RuleParserParserRULE_entry = 1 + RuleParserParserRULE_inputAttrInParen = 2 + RuleParserParserRULE_inputAttrList = 3 + RuleParserParserRULE_outputAttrList = 4 + RuleParserParserRULE_inputAttrVal = 5 + RuleParserParserRULE_outputAttrVal = 6 + RuleParserParserRULE_prVal = 7 + RuleParserParserRULE_hrVal = 8 + RuleParserParserRULE_pr = 9 + RuleParserParserRULE_hr = 10 + RuleParserParserRULE_s = 11 + RuleParserParserRULE_eu = 12 + RuleParserParserRULE_val = 13 +) + +// IRuleEntryContext is an interface to support dynamic dispatch. +type IRuleEntryContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + Entry() IEntryContext + EOF() antlr.TerminalNode + + // IsRuleEntryContext differentiates from other interfaces. + IsRuleEntryContext() +} + +type RuleEntryContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyRuleEntryContext() *RuleEntryContext { + var p = new(RuleEntryContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_ruleEntry + return p +} + +func InitEmptyRuleEntryContext(p *RuleEntryContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_ruleEntry +} + +func (*RuleEntryContext) IsRuleEntryContext() {} + +func NewRuleEntryContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *RuleEntryContext { + var p = new(RuleEntryContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_ruleEntry + + return p +} + +func (s *RuleEntryContext) GetParser() antlr.Parser { return s.parser } + +func (s *RuleEntryContext) Entry() IEntryContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IEntryContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IEntryContext) +} + +func (s *RuleEntryContext) EOF() antlr.TerminalNode { + return s.GetToken(RuleParserParserEOF, 0) +} + +func (s *RuleEntryContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *RuleEntryContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *RuleEntryContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterRuleEntry(s) + } +} + +func (s *RuleEntryContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitRuleEntry(s) + } +} + +func (p *RuleParserParser) RuleEntry() (localctx IRuleEntryContext) { + localctx = NewRuleEntryContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 0, RuleParserParserRULE_ruleEntry) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(28) + p.Entry() + } + { + p.SetState(29) + p.Match(RuleParserParserEOF) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IEntryContext is an interface to support dynamic dispatch. +type IEntryContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + PLAN() antlr.TerminalNode + ARROW() antlr.TerminalNode + OutputAttrList() IOutputAttrListContext + InputAttrInParen() IInputAttrInParenContext + + // IsEntryContext differentiates from other interfaces. + IsEntryContext() +} + +type EntryContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyEntryContext() *EntryContext { + var p = new(EntryContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_entry + return p +} + +func InitEmptyEntryContext(p *EntryContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_entry +} + +func (*EntryContext) IsEntryContext() {} + +func NewEntryContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *EntryContext { + var p = new(EntryContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_entry + + return p +} + +func (s *EntryContext) GetParser() antlr.Parser { return s.parser } + +func (s *EntryContext) PLAN() antlr.TerminalNode { + return s.GetToken(RuleParserParserPLAN, 0) +} + +func (s *EntryContext) ARROW() antlr.TerminalNode { + return s.GetToken(RuleParserParserARROW, 0) +} + +func (s *EntryContext) OutputAttrList() IOutputAttrListContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IOutputAttrListContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IOutputAttrListContext) +} + +func (s *EntryContext) InputAttrInParen() IInputAttrInParenContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IInputAttrInParenContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IInputAttrInParenContext) +} + +func (s *EntryContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *EntryContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *EntryContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterEntry(s) + } +} + +func (s *EntryContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitEntry(s) + } +} + +func (p *RuleParserParser) Entry() (localctx IEntryContext) { + localctx = NewEntryContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 2, RuleParserParserRULE_entry) + p.SetState(42) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + + switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 0, p.GetParserRuleContext()) { + case 1: + p.EnterOuterAlt(localctx, 1) + { + p.SetState(31) + p.Match(RuleParserParserPLAN) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + + case 2: + p.EnterOuterAlt(localctx, 2) + { + p.SetState(32) + p.Match(RuleParserParserPLAN) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(33) + p.Match(RuleParserParserARROW) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(34) + p.OutputAttrList() + } + + case 3: + p.EnterOuterAlt(localctx, 3) + { + p.SetState(35) + p.Match(RuleParserParserPLAN) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(36) + p.InputAttrInParen() + } + + case 4: + p.EnterOuterAlt(localctx, 4) + { + p.SetState(37) + p.Match(RuleParserParserPLAN) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(38) + p.InputAttrInParen() + } + { + p.SetState(39) + p.Match(RuleParserParserARROW) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(40) + p.OutputAttrList() + } + + case antlr.ATNInvalidAltNumber: + goto errorExit + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IInputAttrInParenContext is an interface to support dynamic dispatch. +type IInputAttrInParenContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + LPAREN() antlr.TerminalNode + RPAREN() antlr.TerminalNode + InputAttrList() IInputAttrListContext + + // IsInputAttrInParenContext differentiates from other interfaces. + IsInputAttrInParenContext() +} + +type InputAttrInParenContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyInputAttrInParenContext() *InputAttrInParenContext { + var p = new(InputAttrInParenContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_inputAttrInParen + return p +} + +func InitEmptyInputAttrInParenContext(p *InputAttrInParenContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_inputAttrInParen +} + +func (*InputAttrInParenContext) IsInputAttrInParenContext() {} + +func NewInputAttrInParenContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *InputAttrInParenContext { + var p = new(InputAttrInParenContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_inputAttrInParen + + return p +} + +func (s *InputAttrInParenContext) GetParser() antlr.Parser { return s.parser } + +func (s *InputAttrInParenContext) LPAREN() antlr.TerminalNode { + return s.GetToken(RuleParserParserLPAREN, 0) +} + +func (s *InputAttrInParenContext) RPAREN() antlr.TerminalNode { + return s.GetToken(RuleParserParserRPAREN, 0) +} + +func (s *InputAttrInParenContext) InputAttrList() IInputAttrListContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IInputAttrListContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IInputAttrListContext) +} + +func (s *InputAttrInParenContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *InputAttrInParenContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *InputAttrInParenContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterInputAttrInParen(s) + } +} + +func (s *InputAttrInParenContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitInputAttrInParen(s) + } +} + +func (p *RuleParserParser) InputAttrInParen() (localctx IInputAttrInParenContext) { + localctx = NewInputAttrInParenContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 4, RuleParserParserRULE_inputAttrInParen) + p.SetState(50) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + + switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 1, p.GetParserRuleContext()) { + case 1: + p.EnterOuterAlt(localctx, 1) + { + p.SetState(44) + p.Match(RuleParserParserLPAREN) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(45) + p.Match(RuleParserParserRPAREN) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + + case 2: + p.EnterOuterAlt(localctx, 2) + { + p.SetState(46) + p.Match(RuleParserParserLPAREN) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(47) + p.InputAttrList() + } + { + p.SetState(48) + p.Match(RuleParserParserRPAREN) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + + case antlr.ATNInvalidAltNumber: + goto errorExit + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IInputAttrListContext is an interface to support dynamic dispatch. +type IInputAttrListContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + InputAttrVal() IInputAttrValContext + COMMA() antlr.TerminalNode + InputAttrList() IInputAttrListContext + + // IsInputAttrListContext differentiates from other interfaces. + IsInputAttrListContext() +} + +type InputAttrListContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyInputAttrListContext() *InputAttrListContext { + var p = new(InputAttrListContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_inputAttrList + return p +} + +func InitEmptyInputAttrListContext(p *InputAttrListContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_inputAttrList +} + +func (*InputAttrListContext) IsInputAttrListContext() {} + +func NewInputAttrListContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *InputAttrListContext { + var p = new(InputAttrListContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_inputAttrList + + return p +} + +func (s *InputAttrListContext) GetParser() antlr.Parser { return s.parser } + +func (s *InputAttrListContext) InputAttrVal() IInputAttrValContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IInputAttrValContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IInputAttrValContext) +} + +func (s *InputAttrListContext) COMMA() antlr.TerminalNode { + return s.GetToken(RuleParserParserCOMMA, 0) +} + +func (s *InputAttrListContext) InputAttrList() IInputAttrListContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IInputAttrListContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IInputAttrListContext) +} + +func (s *InputAttrListContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *InputAttrListContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *InputAttrListContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterInputAttrList(s) + } +} + +func (s *InputAttrListContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitInputAttrList(s) + } +} + +func (p *RuleParserParser) InputAttrList() (localctx IInputAttrListContext) { + localctx = NewInputAttrListContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 6, RuleParserParserRULE_inputAttrList) + p.SetState(57) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + + switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 2, p.GetParserRuleContext()) { + case 1: + p.EnterOuterAlt(localctx, 1) + { + p.SetState(52) + p.InputAttrVal() + } + + case 2: + p.EnterOuterAlt(localctx, 2) + { + p.SetState(53) + p.InputAttrVal() + } + { + p.SetState(54) + p.Match(RuleParserParserCOMMA) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(55) + p.InputAttrList() + } + + case antlr.ATNInvalidAltNumber: + goto errorExit + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IOutputAttrListContext is an interface to support dynamic dispatch. +type IOutputAttrListContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + OutputAttrVal() IOutputAttrValContext + COMMA() antlr.TerminalNode + OutputAttrList() IOutputAttrListContext + + // IsOutputAttrListContext differentiates from other interfaces. + IsOutputAttrListContext() +} + +type OutputAttrListContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyOutputAttrListContext() *OutputAttrListContext { + var p = new(OutputAttrListContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_outputAttrList + return p +} + +func InitEmptyOutputAttrListContext(p *OutputAttrListContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_outputAttrList +} + +func (*OutputAttrListContext) IsOutputAttrListContext() {} + +func NewOutputAttrListContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *OutputAttrListContext { + var p = new(OutputAttrListContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_outputAttrList + + return p +} + +func (s *OutputAttrListContext) GetParser() antlr.Parser { return s.parser } + +func (s *OutputAttrListContext) OutputAttrVal() IOutputAttrValContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IOutputAttrValContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IOutputAttrValContext) +} + +func (s *OutputAttrListContext) COMMA() antlr.TerminalNode { + return s.GetToken(RuleParserParserCOMMA, 0) +} + +func (s *OutputAttrListContext) OutputAttrList() IOutputAttrListContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IOutputAttrListContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IOutputAttrListContext) +} + +func (s *OutputAttrListContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *OutputAttrListContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *OutputAttrListContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterOutputAttrList(s) + } +} + +func (s *OutputAttrListContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitOutputAttrList(s) + } +} + +func (p *RuleParserParser) OutputAttrList() (localctx IOutputAttrListContext) { + localctx = NewOutputAttrListContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 8, RuleParserParserRULE_outputAttrList) + p.SetState(64) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + + switch p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 3, p.GetParserRuleContext()) { + case 1: + p.EnterOuterAlt(localctx, 1) + { + p.SetState(59) + p.OutputAttrVal() + } + + case 2: + p.EnterOuterAlt(localctx, 2) + { + p.SetState(60) + p.OutputAttrVal() + } + { + p.SetState(61) + p.Match(RuleParserParserCOMMA) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(62) + p.OutputAttrList() + } + + case antlr.ATNInvalidAltNumber: + goto errorExit + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IInputAttrValContext is an interface to support dynamic dispatch. +type IInputAttrValContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + PrVal() IPrValContext + HrVal() IHrValContext + + // IsInputAttrValContext differentiates from other interfaces. + IsInputAttrValContext() +} + +type InputAttrValContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyInputAttrValContext() *InputAttrValContext { + var p = new(InputAttrValContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_inputAttrVal + return p +} + +func InitEmptyInputAttrValContext(p *InputAttrValContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_inputAttrVal +} + +func (*InputAttrValContext) IsInputAttrValContext() {} + +func NewInputAttrValContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *InputAttrValContext { + var p = new(InputAttrValContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_inputAttrVal + + return p +} + +func (s *InputAttrValContext) GetParser() antlr.Parser { return s.parser } + +func (s *InputAttrValContext) PrVal() IPrValContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IPrValContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IPrValContext) +} + +func (s *InputAttrValContext) HrVal() IHrValContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IHrValContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IHrValContext) +} + +func (s *InputAttrValContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *InputAttrValContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *InputAttrValContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterInputAttrVal(s) + } +} + +func (s *InputAttrValContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitInputAttrVal(s) + } +} + +func (p *RuleParserParser) InputAttrVal() (localctx IInputAttrValContext) { + localctx = NewInputAttrValContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 10, RuleParserParserRULE_inputAttrVal) + p.SetState(68) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + + switch p.GetTokenStream().LA(1) { + case RuleParserParserPR: + p.EnterOuterAlt(localctx, 1) + { + p.SetState(66) + p.PrVal() + } + + case RuleParserParserHR: + p.EnterOuterAlt(localctx, 2) + { + p.SetState(67) + p.HrVal() + } + + default: + p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil)) + goto errorExit + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IOutputAttrValContext is an interface to support dynamic dispatch. +type IOutputAttrValContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + S() ISContext + Eu() IEuContext + + // IsOutputAttrValContext differentiates from other interfaces. + IsOutputAttrValContext() +} + +type OutputAttrValContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyOutputAttrValContext() *OutputAttrValContext { + var p = new(OutputAttrValContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_outputAttrVal + return p +} + +func InitEmptyOutputAttrValContext(p *OutputAttrValContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_outputAttrVal +} + +func (*OutputAttrValContext) IsOutputAttrValContext() {} + +func NewOutputAttrValContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *OutputAttrValContext { + var p = new(OutputAttrValContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_outputAttrVal + + return p +} + +func (s *OutputAttrValContext) GetParser() antlr.Parser { return s.parser } + +func (s *OutputAttrValContext) S() ISContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(ISContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(ISContext) +} + +func (s *OutputAttrValContext) Eu() IEuContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IEuContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IEuContext) +} + +func (s *OutputAttrValContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *OutputAttrValContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *OutputAttrValContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterOutputAttrVal(s) + } +} + +func (s *OutputAttrValContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitOutputAttrVal(s) + } +} + +func (p *RuleParserParser) OutputAttrVal() (localctx IOutputAttrValContext) { + localctx = NewOutputAttrValContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 12, RuleParserParserRULE_outputAttrVal) + p.SetState(72) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + + switch p.GetTokenStream().LA(1) { + case RuleParserParserS: + p.EnterOuterAlt(localctx, 1) + { + p.SetState(70) + p.S() + } + + case RuleParserParserEU: + p.EnterOuterAlt(localctx, 2) + { + p.SetState(71) + p.Eu() + } + + default: + p.SetError(antlr.NewNoViableAltException(p, nil, nil, nil, nil, nil)) + goto errorExit + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IPrValContext is an interface to support dynamic dispatch. +type IPrValContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + Pr() IPrContext + EQ() antlr.TerminalNode + Val() IValContext + + // IsPrValContext differentiates from other interfaces. + IsPrValContext() +} + +type PrValContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyPrValContext() *PrValContext { + var p = new(PrValContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_prVal + return p +} + +func InitEmptyPrValContext(p *PrValContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_prVal +} + +func (*PrValContext) IsPrValContext() {} + +func NewPrValContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *PrValContext { + var p = new(PrValContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_prVal + + return p +} + +func (s *PrValContext) GetParser() antlr.Parser { return s.parser } + +func (s *PrValContext) Pr() IPrContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IPrContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IPrContext) +} + +func (s *PrValContext) EQ() antlr.TerminalNode { + return s.GetToken(RuleParserParserEQ, 0) +} + +func (s *PrValContext) Val() IValContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IValContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IValContext) +} + +func (s *PrValContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *PrValContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *PrValContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterPrVal(s) + } +} + +func (s *PrValContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitPrVal(s) + } +} + +func (p *RuleParserParser) PrVal() (localctx IPrValContext) { + localctx = NewPrValContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 14, RuleParserParserRULE_prVal) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(74) + p.Pr() + } + { + p.SetState(75) + p.Match(RuleParserParserEQ) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(76) + p.Val() + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IHrValContext is an interface to support dynamic dispatch. +type IHrValContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + Hr() IHrContext + EQ() antlr.TerminalNode + Val() IValContext + + // IsHrValContext differentiates from other interfaces. + IsHrValContext() +} + +type HrValContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyHrValContext() *HrValContext { + var p = new(HrValContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_hrVal + return p +} + +func InitEmptyHrValContext(p *HrValContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_hrVal +} + +func (*HrValContext) IsHrValContext() {} + +func NewHrValContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *HrValContext { + var p = new(HrValContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_hrVal + + return p +} + +func (s *HrValContext) GetParser() antlr.Parser { return s.parser } + +func (s *HrValContext) Hr() IHrContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IHrContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IHrContext) +} + +func (s *HrValContext) EQ() antlr.TerminalNode { + return s.GetToken(RuleParserParserEQ, 0) +} + +func (s *HrValContext) Val() IValContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IValContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IValContext) +} + +func (s *HrValContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *HrValContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *HrValContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterHrVal(s) + } +} + +func (s *HrValContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitHrVal(s) + } +} + +func (p *RuleParserParser) HrVal() (localctx IHrValContext) { + localctx = NewHrValContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 16, RuleParserParserRULE_hrVal) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(78) + p.Hr() + } + { + p.SetState(79) + p.Match(RuleParserParserEQ) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(80) + p.Val() + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IPrContext is an interface to support dynamic dispatch. +type IPrContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + PR() antlr.TerminalNode + + // IsPrContext differentiates from other interfaces. + IsPrContext() +} + +type PrContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyPrContext() *PrContext { + var p = new(PrContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_pr + return p +} + +func InitEmptyPrContext(p *PrContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_pr +} + +func (*PrContext) IsPrContext() {} + +func NewPrContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *PrContext { + var p = new(PrContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_pr + + return p +} + +func (s *PrContext) GetParser() antlr.Parser { return s.parser } + +func (s *PrContext) PR() antlr.TerminalNode { + return s.GetToken(RuleParserParserPR, 0) +} + +func (s *PrContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *PrContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *PrContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterPr(s) + } +} + +func (s *PrContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitPr(s) + } +} + +func (p *RuleParserParser) Pr() (localctx IPrContext) { + localctx = NewPrContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 18, RuleParserParserRULE_pr) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(82) + p.Match(RuleParserParserPR) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IHrContext is an interface to support dynamic dispatch. +type IHrContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + HR() antlr.TerminalNode + + // IsHrContext differentiates from other interfaces. + IsHrContext() +} + +type HrContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyHrContext() *HrContext { + var p = new(HrContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_hr + return p +} + +func InitEmptyHrContext(p *HrContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_hr +} + +func (*HrContext) IsHrContext() {} + +func NewHrContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *HrContext { + var p = new(HrContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_hr + + return p +} + +func (s *HrContext) GetParser() antlr.Parser { return s.parser } + +func (s *HrContext) HR() antlr.TerminalNode { + return s.GetToken(RuleParserParserHR, 0) +} + +func (s *HrContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *HrContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *HrContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterHr(s) + } +} + +func (s *HrContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitHr(s) + } +} + +func (p *RuleParserParser) Hr() (localctx IHrContext) { + localctx = NewHrContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 20, RuleParserParserRULE_hr) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(84) + p.Match(RuleParserParserHR) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// ISContext is an interface to support dynamic dispatch. +type ISContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + S() antlr.TerminalNode + + // IsSContext differentiates from other interfaces. + IsSContext() +} + +type SContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptySContext() *SContext { + var p = new(SContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_s + return p +} + +func InitEmptySContext(p *SContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_s +} + +func (*SContext) IsSContext() {} + +func NewSContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *SContext { + var p = new(SContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_s + + return p +} + +func (s *SContext) GetParser() antlr.Parser { return s.parser } + +func (s *SContext) S() antlr.TerminalNode { + return s.GetToken(RuleParserParserS, 0) +} + +func (s *SContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *SContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *SContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterS(s) + } +} + +func (s *SContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitS(s) + } +} + +func (p *RuleParserParser) S() (localctx ISContext) { + localctx = NewSContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 22, RuleParserParserRULE_s) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(86) + p.Match(RuleParserParserS) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IEuContext is an interface to support dynamic dispatch. +type IEuContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + EU() antlr.TerminalNode + + // IsEuContext differentiates from other interfaces. + IsEuContext() +} + +type EuContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyEuContext() *EuContext { + var p = new(EuContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_eu + return p +} + +func InitEmptyEuContext(p *EuContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_eu +} + +func (*EuContext) IsEuContext() {} + +func NewEuContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *EuContext { + var p = new(EuContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_eu + + return p +} + +func (s *EuContext) GetParser() antlr.Parser { return s.parser } + +func (s *EuContext) EU() antlr.TerminalNode { + return s.GetToken(RuleParserParserEU, 0) +} + +func (s *EuContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *EuContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *EuContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterEu(s) + } +} + +func (s *EuContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitEu(s) + } +} + +func (p *RuleParserParser) Eu() (localctx IEuContext) { + localctx = NewEuContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 24, RuleParserParserRULE_eu) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(88) + p.Match(RuleParserParserEU) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IValContext is an interface to support dynamic dispatch. +type IValContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + VAL() antlr.TerminalNode + ASTERIX() antlr.TerminalNode + + // IsValContext differentiates from other interfaces. + IsValContext() +} + +type ValContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyValContext() *ValContext { + var p = new(ValContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_val + return p +} + +func InitEmptyValContext(p *ValContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = RuleParserParserRULE_val +} + +func (*ValContext) IsValContext() {} + +func NewValContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ValContext { + var p = new(ValContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = RuleParserParserRULE_val + + return p +} + +func (s *ValContext) GetParser() antlr.Parser { return s.parser } + +func (s *ValContext) VAL() antlr.TerminalNode { + return s.GetToken(RuleParserParserVAL, 0) +} + +func (s *ValContext) ASTERIX() antlr.TerminalNode { + return s.GetToken(RuleParserParserASTERIX, 0) +} + +func (s *ValContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *ValContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *ValContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.EnterVal(s) + } +} + +func (s *ValContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(RuleParserListener); ok { + listenerT.ExitVal(s) + } +} + +func (p *RuleParserParser) Val() (localctx IValContext) { + localctx = NewValContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 26, RuleParserParserRULE_val) + var _la int + + p.EnterOuterAlt(localctx, 1) + { + p.SetState(90) + _la = p.GetTokenStream().LA(1) + + if !(_la == RuleParserParserASTERIX || _la == RuleParserParserVAL) { + p.GetErrorHandler().RecoverInline(p) + } else { + p.GetErrorHandler().ReportMatch(p) + p.Consume() + } + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} diff --git a/common/hyperscaler/rules/grammar/listener.go b/common/hyperscaler/rules/grammar/listener.go new file mode 100644 index 0000000000..f2f7fe499e --- /dev/null +++ b/common/hyperscaler/rules/grammar/listener.go @@ -0,0 +1,32 @@ +package grammar + +import ( + "github.com/kyma-project/kyma-environment-broker/common/hyperscaler/rules" + parser "github.com/kyma-project/kyma-environment-broker/common/hyperscaler/rules/grammar/antlr" +) + +type RuleListener struct { + *parser.BaseRuleParserListener + + processed *rules.Rule +} + +func (r RuleListener) EnterEntry(c *parser.EntryContext) { + r.processed.Plan = c.PLAN().GetText() +} + +func (r *RuleListener) EnterPrVal(c *parser.PrValContext) { + r.processed.PlatformRegion = c.Val().GetText() +} + +func (r *RuleListener) EnterHrVal(c *parser.HrValContext) { + r.processed.HyperscalerRegion = c.Val().GetText() +} + +func (s *RuleListener) EnterS(c *parser.SContext) { + s.processed.Shared = true +} + +func (s *RuleListener) EnterEu(c *parser.EuContext) { + s.processed.EuAccess = true +} diff --git a/common/hyperscaler/rules/grammar/parser.go b/common/hyperscaler/rules/grammar/parser.go new file mode 100644 index 0000000000..9a2f5aa3b3 --- /dev/null +++ b/common/hyperscaler/rules/grammar/parser.go @@ -0,0 +1,31 @@ +package grammar + +import ( + "github.com/antlr4-go/antlr/v4" + "github.com/kyma-project/kyma-environment-broker/common/hyperscaler/rules" + parser "github.com/kyma-project/kyma-environment-broker/common/hyperscaler/rules/grammar/antlr" +) + +type GrammarParser struct{ + +} + +func (g* GrammarParser) Parse(ruleEntry string) *rules.Rule { + // Setup the input + is := antlr.NewInputStream(ruleEntry) + + // Create the Lexer + lexer := parser.NewRuleLexer(is) + stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel) + + // Create the Parser + p := parser.NewRuleParserParser(stream) + + // Finally parse the expression + listener := &RuleListener{processed: &rules.Rule{}} + antlr.ParseTreeWalkerDefault.Walk(listener, p.RuleEntry()) + return listener.processed +} + + + diff --git a/common/hyperscaler/rules/grammar/parser_test.go b/common/hyperscaler/rules/grammar/parser_test.go new file mode 100644 index 0000000000..0a4209b559 --- /dev/null +++ b/common/hyperscaler/rules/grammar/parser_test.go @@ -0,0 +1,11 @@ +package grammar + +import "testing" + +import "github.com/kyma-project/kyma-environment-broker/common/hyperscaler/rules" + +func TestParser(t *testing.T) { + + rules.ParserTest(t, &GrammarParser{}) + +} \ No newline at end of file diff --git a/common/hyperscaler/rules/parser.go b/common/hyperscaler/rules/parser.go new file mode 100644 index 0000000000..8780a9beb1 --- /dev/null +++ b/common/hyperscaler/rules/parser.go @@ -0,0 +1,5 @@ +package rules + +type Parser interface { + Parse(ruleEntry string) *Rule +} \ No newline at end of file diff --git a/common/hyperscaler/rules/parser_test_utils.go b/common/hyperscaler/rules/parser_test_utils.go new file mode 100644 index 0000000000..18298a5766 --- /dev/null +++ b/common/hyperscaler/rules/parser_test_utils.go @@ -0,0 +1,84 @@ +package rules + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func ParserTest(t *testing.T, parser Parser) { + + t.Run("with plan", func(t *testing.T) { + rule := parser.Parse("azure") + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Empty(t, rule.PlatformRegion) + require.Empty(t, rule.HyperscalerRegion) + + require.Equal(t, false, rule.EuAccess) + require.Equal(t, false, rule.Shared) + }) + + t.Run("with plan and platform region", func(t *testing.T) { + rule := parser.Parse("azure(PR=westeurope)") + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Equal(t, "westeurope", rule.PlatformRegion) + require.Empty(t, rule.HyperscalerRegion) + + require.Equal(t, false, rule.EuAccess) + require.Equal(t, false, rule.Shared) + }) + + t.Run("with plan and hyperscaler region", func(t *testing.T) { + rule := parser.Parse("azure(HR=westeurope)") + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Equal(t, "westeurope", rule.HyperscalerRegion) + require.Empty(t, rule.PlatformRegion) + + require.Equal(t, false, rule.EuAccess) + require.Equal(t, false, rule.Shared) + }) + + t.Run("with plan, platform and hyperscaler region", func(t *testing.T) { + rule := parser.Parse("azure(PR=easteurope, HR=westeurope)") + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Equal(t, "westeurope", rule.HyperscalerRegion) + require.Equal(t, "easteurope", rule.PlatformRegion) + + require.False(t, rule.EuAccess) + require.False(t, rule.Shared) + }) + + t.Run("with plan and shared", func(t *testing.T) { + rule := parser.Parse("azure->S") + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Empty(t, rule.HyperscalerRegion) + require.Empty(t, rule.PlatformRegion) + + require.False(t, rule.EuAccess) + require.True(t, rule.Shared) + }) + + + t.Run("with plan, shared and euAccess", func(t *testing.T) { + rule := parser.Parse("azure->S,EU") + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Empty(t, rule.HyperscalerRegion) + require.Empty(t, rule.PlatformRegion) + + require.True(t, rule.EuAccess) + require.True(t, rule.Shared) + }) + +} \ No newline at end of file diff --git a/common/hyperscaler/rules/rule.go b/common/hyperscaler/rules/rule.go new file mode 100644 index 0000000000..7e82486d4f --- /dev/null +++ b/common/hyperscaler/rules/rule.go @@ -0,0 +1,24 @@ +package rules + +type Rule struct { + Plan string + PlatformRegion string + HyperscalerRegion string + EuAccess bool + Shared bool +} + +func (r *Rule) Labels() string { + if "azure" == r.Plan { + return "hyperscalerType: azure" + } + return "" +} + +func (r *Rule) Matched() bool { + if "azure" == r.Plan { + return true + } + + return false +} \ No newline at end of file diff --git a/common/hyperscaler/rules/simple_parser.go b/common/hyperscaler/rules/simple_parser.go new file mode 100644 index 0000000000..170278019c --- /dev/null +++ b/common/hyperscaler/rules/simple_parser.go @@ -0,0 +1,52 @@ +package rules + +import ( + "strings" +) + +type SimpleParser struct{ + +} + +func (g* SimpleParser) Parse(ruleEntry string) *Rule { + outputRule := &Rule{} + + outputInputPart := strings.Split(ruleEntry, "->") + + inputPart := outputInputPart[0] + + planAndInputAttr := strings.Split(inputPart, "(") + + outputRule.Plan = planAndInputAttr[0] + + if len(planAndInputAttr) > 1 { + inputPart := strings.TrimSuffix(planAndInputAttr[1], ")") + + inputAttrs := strings.Split(inputPart, ",") + + for _, inputAttr := range inputAttrs { + if strings.Contains(inputAttr, "PR") { + outputRule.PlatformRegion = strings.Split(inputAttr, "=")[1] + } + + if strings.Contains(inputAttr, "HR") { + outputRule.HyperscalerRegion = strings.Split(inputAttr, "=")[1] + } + } + + } + + if len(outputInputPart) > 1 { + outputAttrs := strings.Split(outputInputPart[1], ",") + + for _, outputAttr := range outputAttrs { + if outputAttr == "S" { + outputRule.Shared = true + } else if outputAttr == "EU" { + outputRule.EuAccess = true + } + } + } + + return outputRule +} diff --git a/common/hyperscaler/rules/simple_parser_test.go b/common/hyperscaler/rules/simple_parser_test.go new file mode 100644 index 0000000000..821f72d3a7 --- /dev/null +++ b/common/hyperscaler/rules/simple_parser_test.go @@ -0,0 +1,9 @@ +package rules + +import "testing" + +func TestParser(t *testing.T) { + + ParserTest(t, &SimpleParser{}) + +} \ No newline at end of file diff --git a/go.mod b/go.mod index fb56cdf834..71a8411c55 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/kyma-project/kyma-environment-broker go 1.23.5 require ( + github.com/antlr4-go/antlr/v4 v4.13.1 code.cloudfoundry.org/lager v2.0.0+incompatible github.com/99designs/gqlgen v0.17.64 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible diff --git a/go.sum b/go.sum index bf0efcfec3..39243cb92e 100644 --- a/go.sum +++ b/go.sum @@ -59,6 +59,8 @@ github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7X github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= +github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= From dadfbf0350b2cb594c56060f37a532efa144ae10 Mon Sep 17 00:00:00 2001 From: ralikio <74771103+ralikio@users.noreply.github.com> Date: Sun, 2 Feb 2025 23:47:56 +0100 Subject: [PATCH 2/3] Test Validation --- common/hyperscaler/rules/grammar/listener.go | 20 ++- common/hyperscaler/rules/grammar/parser.go | 44 ++++++- .../hyperscaler/rules/grammar/parser_test.go | 5 +- common/hyperscaler/rules/parser.go | 2 +- common/hyperscaler/rules/parser_test_utils.go | 124 ++++++++++++++++-- common/hyperscaler/rules/simple_parser.go | 18 ++- .../hyperscaler/rules/simple_parser_test.go | 5 +- 7 files changed, 183 insertions(+), 35 deletions(-) diff --git a/common/hyperscaler/rules/grammar/listener.go b/common/hyperscaler/rules/grammar/listener.go index f2f7fe499e..be321955c7 100644 --- a/common/hyperscaler/rules/grammar/listener.go +++ b/common/hyperscaler/rules/grammar/listener.go @@ -12,21 +12,31 @@ type RuleListener struct { } func (r RuleListener) EnterEntry(c *parser.EntryContext) { - r.processed.Plan = c.PLAN().GetText() + if c.PLAN() != nil { + r.processed.Plan = c.PLAN().GetText() + } } func (r *RuleListener) EnterPrVal(c *parser.PrValContext) { - r.processed.PlatformRegion = c.Val().GetText() + if c.Val() != nil { + r.processed.PlatformRegion = c.Val().GetText() + } } func (r *RuleListener) EnterHrVal(c *parser.HrValContext) { - r.processed.HyperscalerRegion = c.Val().GetText() + if c.Val() != nil { + r.processed.HyperscalerRegion = c.Val().GetText() + } } func (s *RuleListener) EnterS(c *parser.SContext) { - s.processed.Shared = true + if c.S() != nil { + s.processed.Shared = true + } } func (s *RuleListener) EnterEu(c *parser.EuContext) { - s.processed.EuAccess = true + if c.EU() != nil { + s.processed.EuAccess = true + } } diff --git a/common/hyperscaler/rules/grammar/parser.go b/common/hyperscaler/rules/grammar/parser.go index 9a2f5aa3b3..6ff1c02cf8 100644 --- a/common/hyperscaler/rules/grammar/parser.go +++ b/common/hyperscaler/rules/grammar/parser.go @@ -7,24 +7,54 @@ import ( ) type GrammarParser struct{ - } -func (g* GrammarParser) Parse(ruleEntry string) *rules.Rule { - // Setup the input +func (g* GrammarParser) Parse(ruleEntry string) (*rules.Rule, error) { is := antlr.NewInputStream(ruleEntry) - // Create the Lexer + erorrsListener := &ErrorListener{} + lexer := parser.NewRuleLexer(is) + lexer.RemoveErrorListeners() + lexer.AddErrorListener(erorrsListener) + stream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel) - // Create the Parser p := parser.NewRuleParserParser(stream) + + p.RemoveErrorListeners() + p.AddErrorListener(erorrsListener) - // Finally parse the expression listener := &RuleListener{processed: &rules.Rule{}} antlr.ParseTreeWalkerDefault.Walk(listener, p.RuleEntry()) - return listener.processed + + if len(erorrsListener.Errors) > 0 { + return nil, erorrsListener.Errors[0] + } + + return listener.processed, nil +} + +type SyntaxError struct { + line, column int + msg string +} + +func (c *SyntaxError) Error() string { + return c.msg +} + +type ErrorListener struct { + *antlr.DefaultErrorListener + Errors []error +} + +func (c *ErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) { + c.Errors = append(c.Errors, &SyntaxError{ + line: line, + column: column, + msg: msg, + }) } diff --git a/common/hyperscaler/rules/grammar/parser_test.go b/common/hyperscaler/rules/grammar/parser_test.go index 0a4209b559..25dba32d58 100644 --- a/common/hyperscaler/rules/grammar/parser_test.go +++ b/common/hyperscaler/rules/grammar/parser_test.go @@ -5,7 +5,6 @@ import "testing" import "github.com/kyma-project/kyma-environment-broker/common/hyperscaler/rules" func TestParser(t *testing.T) { - - rules.ParserTest(t, &GrammarParser{}) - + rules.ParserHappyPathTest(t, &GrammarParser{}) + rules.ParserValidationTest(t, &GrammarParser{}) } \ No newline at end of file diff --git a/common/hyperscaler/rules/parser.go b/common/hyperscaler/rules/parser.go index 8780a9beb1..c4a44fbee8 100644 --- a/common/hyperscaler/rules/parser.go +++ b/common/hyperscaler/rules/parser.go @@ -1,5 +1,5 @@ package rules type Parser interface { - Parse(ruleEntry string) *Rule + Parse(ruleEntry string) (*Rule, error) } \ No newline at end of file diff --git a/common/hyperscaler/rules/parser_test_utils.go b/common/hyperscaler/rules/parser_test_utils.go index 18298a5766..414fb55850 100644 --- a/common/hyperscaler/rules/parser_test_utils.go +++ b/common/hyperscaler/rules/parser_test_utils.go @@ -6,10 +6,11 @@ import ( "github.com/stretchr/testify/require" ) -func ParserTest(t *testing.T, parser Parser) { +func ParserHappyPathTest(t *testing.T, parser Parser) { t.Run("with plan", func(t *testing.T) { - rule := parser.Parse("azure") + rule, err := parser.Parse("azure") + require.NoError(t, err) require.NotNil(t, rule) require.Equal(t, "azure", rule.Plan) @@ -20,8 +21,9 @@ func ParserTest(t *testing.T, parser Parser) { require.Equal(t, false, rule.Shared) }) - t.Run("with plan and platform region", func(t *testing.T) { - rule := parser.Parse("azure(PR=westeurope)") + t.Run("with plan and single input attribute", func(t *testing.T) { + rule, err := parser.Parse("azure(PR=westeurope)") + require.NoError(t, err) require.NotNil(t, rule) require.Equal(t, "azure", rule.Plan) @@ -30,10 +32,9 @@ func ParserTest(t *testing.T, parser Parser) { require.Equal(t, false, rule.EuAccess) require.Equal(t, false, rule.Shared) - }) - t.Run("with plan and hyperscaler region", func(t *testing.T) { - rule := parser.Parse("azure(HR=westeurope)") + rule, err = parser.Parse("azure(HR=westeurope)") + require.NoError(t, err) require.NotNil(t, rule) require.Equal(t, "azure", rule.Plan) @@ -44,8 +45,20 @@ func ParserTest(t *testing.T, parser Parser) { require.Equal(t, false, rule.Shared) }) - t.Run("with plan, platform and hyperscaler region", func(t *testing.T) { - rule := parser.Parse("azure(PR=easteurope, HR=westeurope)") + t.Run("with plan all output attributes - different positions", func(t *testing.T) { + rule, err := parser.Parse("azure(PR=easteurope,HR=westeurope)") + require.NoError(t, err) + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Equal(t, "westeurope", rule.HyperscalerRegion) + require.Equal(t, "easteurope", rule.PlatformRegion) + + require.False(t, rule.EuAccess) + require.False(t, rule.Shared) + + rule, err = parser.Parse("azure(HR=westeurope,PR=easteurope)") + require.NoError(t, err) require.NotNil(t, rule) require.Equal(t, "azure", rule.Plan) @@ -56,8 +69,9 @@ func ParserTest(t *testing.T, parser Parser) { require.False(t, rule.Shared) }) - t.Run("with plan and shared", func(t *testing.T) { - rule := parser.Parse("azure->S") + t.Run("with plan and single output attribute", func(t *testing.T) { + rule, err := parser.Parse("azure->S") + require.NoError(t, err) require.NotNil(t, rule) require.Equal(t, "azure", rule.Plan) @@ -66,11 +80,23 @@ func ParserTest(t *testing.T, parser Parser) { require.False(t, rule.EuAccess) require.True(t, rule.Shared) + + rule, err = parser.Parse("azure->EU") + require.NoError(t, err) + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Empty(t, rule.HyperscalerRegion) + require.Empty(t, rule.PlatformRegion) + + require.True(t, rule.EuAccess) + require.False(t, rule.Shared) }) - t.Run("with plan, shared and euAccess", func(t *testing.T) { - rule := parser.Parse("azure->S,EU") + t.Run("with plan and all output attributes - different positions", func(t *testing.T) { + rule, err := parser.Parse("azure->S,EU") + require.NoError(t, err) require.NotNil(t, rule) require.Equal(t, "azure", rule.Plan) @@ -79,6 +105,78 @@ func ParserTest(t *testing.T, parser Parser) { require.True(t, rule.EuAccess) require.True(t, rule.Shared) + + rule, err = parser.Parse("azure->EU,S") + require.NoError(t, err) + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Empty(t, rule.HyperscalerRegion) + require.Empty(t, rule.PlatformRegion) + + require.True(t, rule.EuAccess) + require.True(t, rule.Shared) + }) + + t.Run("with plan and single output/input attributes", func(t *testing.T) { + rule, err := parser.Parse("azure(PR=westeurope)->EU") + require.NoError(t, err) + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Empty(t, rule.HyperscalerRegion) + require.Equal(t, "westeurope", rule.PlatformRegion) + + require.True(t, rule.EuAccess) + require.False(t, rule.Shared) + }) + + t.Run("with plan and all input/output attributes", func(t *testing.T) { + rule, err := parser.Parse("azure(PR=westeurope, HR=easteurope)->EU,S") + require.NoError(t, err) + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Equal(t, "easteurope", rule.HyperscalerRegion) + require.Equal(t, "westeurope", rule.PlatformRegion) + + require.True(t, rule.EuAccess) + require.True(t, rule.Shared) + }) +} + + +func ParserValidationTest(t *testing.T, parser Parser) { + + t.Run("with paranthesis only", func(t *testing.T) { + rule, err := parser.Parse("()") + require.Nil(t, rule) + require.Error(t, err) + }) + + t.Run("with arrow only", func(t *testing.T) { + rule, err := parser.Parse("->") + require.Nil(t, rule) + require.Error(t, err) + }) + + t.Run("with incorrect attributes list", func(t *testing.T) { + rule, err := parser.Parse("test(,)->,") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("test(PR=west,HR=east)->,") + require.Nil(t, rule) + require.Error(t, err) }) +// t.Run("with duplicated input attribute", func(t *testing.T) { +// rule, err := parser.Parse("azure(PR=test,PR=test2)") +// require.Nil(t, rule) +// require.Error(t, err) + +// rule, err = parser.Parse("test(PR=west,HR=east)->EU,EU") +// require.Nil(t, rule) +// require.Error(t, err) +// }) } \ No newline at end of file diff --git a/common/hyperscaler/rules/simple_parser.go b/common/hyperscaler/rules/simple_parser.go index 170278019c..427b4d62f6 100644 --- a/common/hyperscaler/rules/simple_parser.go +++ b/common/hyperscaler/rules/simple_parser.go @@ -1,6 +1,7 @@ package rules import ( + "fmt" "strings" ) @@ -8,7 +9,7 @@ type SimpleParser struct{ } -func (g* SimpleParser) Parse(ruleEntry string) *Rule { +func (g* SimpleParser) Parse(ruleEntry string) (*Rule, error) { outputRule := &Rule{} outputInputPart := strings.Split(ruleEntry, "->") @@ -18,6 +19,9 @@ func (g* SimpleParser) Parse(ruleEntry string) *Rule { planAndInputAttr := strings.Split(inputPart, "(") outputRule.Plan = planAndInputAttr[0] + if outputRule.Plan == "" { + return nil, fmt.Errorf("plan is empty") + } if len(planAndInputAttr) > 1 { inputPart := strings.TrimSuffix(planAndInputAttr[1], ")") @@ -25,6 +29,11 @@ func (g* SimpleParser) Parse(ruleEntry string) *Rule { inputAttrs := strings.Split(inputPart, ",") for _, inputAttr := range inputAttrs { + + if inputAttr == "" { + return nil, fmt.Errorf("input attribute is empty") + } + if strings.Contains(inputAttr, "PR") { outputRule.PlatformRegion = strings.Split(inputAttr, "=")[1] } @@ -33,13 +42,16 @@ func (g* SimpleParser) Parse(ruleEntry string) *Rule { outputRule.HyperscalerRegion = strings.Split(inputAttr, "=")[1] } } - } if len(outputInputPart) > 1 { outputAttrs := strings.Split(outputInputPart[1], ",") for _, outputAttr := range outputAttrs { + if outputAttr == "" { + return nil, fmt.Errorf("output attribute is empty") + } + if outputAttr == "S" { outputRule.Shared = true } else if outputAttr == "EU" { @@ -48,5 +60,5 @@ func (g* SimpleParser) Parse(ruleEntry string) *Rule { } } - return outputRule + return outputRule, nil } diff --git a/common/hyperscaler/rules/simple_parser_test.go b/common/hyperscaler/rules/simple_parser_test.go index 821f72d3a7..6dcfa85940 100644 --- a/common/hyperscaler/rules/simple_parser_test.go +++ b/common/hyperscaler/rules/simple_parser_test.go @@ -3,7 +3,6 @@ package rules import "testing" func TestParser(t *testing.T) { - - ParserTest(t, &SimpleParser{}) - + ParserHappyPathTest(t, &SimpleParser{}) + ParserValidationTest(t, &SimpleParser{}) } \ No newline at end of file From 0fa6a10ee6ba825306deb3154e33cf8ce4efff56 Mon Sep 17 00:00:00 2001 From: ralikio <74771103+ralikio@users.noreply.github.com> Date: Tue, 4 Feb 2025 16:22:54 +0100 Subject: [PATCH 3/3] Added Tests from https://github.com/PK85/hap-parser --- .../grammar/{parser.go => antlr_parser.go} | 0 .../{parser_test.go => antlr_parser_test.go} | 2 +- common/hyperscaler/rules/grammar/listener.go | 39 ++- common/hyperscaler/rules/parser_test_utils.go | 234 +++++++++++++++++- common/hyperscaler/rules/rule.go | 58 +++++ common/hyperscaler/rules/simple_parser.go | 55 +++- 6 files changed, 359 insertions(+), 29 deletions(-) rename common/hyperscaler/rules/grammar/{parser.go => antlr_parser.go} (100%) rename common/hyperscaler/rules/grammar/{parser_test.go => antlr_parser_test.go} (85%) diff --git a/common/hyperscaler/rules/grammar/parser.go b/common/hyperscaler/rules/grammar/antlr_parser.go similarity index 100% rename from common/hyperscaler/rules/grammar/parser.go rename to common/hyperscaler/rules/grammar/antlr_parser.go diff --git a/common/hyperscaler/rules/grammar/parser_test.go b/common/hyperscaler/rules/grammar/antlr_parser_test.go similarity index 85% rename from common/hyperscaler/rules/grammar/parser_test.go rename to common/hyperscaler/rules/grammar/antlr_parser_test.go index 25dba32d58..7a99115a30 100644 --- a/common/hyperscaler/rules/grammar/parser_test.go +++ b/common/hyperscaler/rules/grammar/antlr_parser_test.go @@ -4,7 +4,7 @@ import "testing" import "github.com/kyma-project/kyma-environment-broker/common/hyperscaler/rules" -func TestParser(t *testing.T) { +func TestAntlrParser(t *testing.T) { rules.ParserHappyPathTest(t, &GrammarParser{}) rules.ParserValidationTest(t, &GrammarParser{}) } \ No newline at end of file diff --git a/common/hyperscaler/rules/grammar/listener.go b/common/hyperscaler/rules/grammar/listener.go index be321955c7..6443690192 100644 --- a/common/hyperscaler/rules/grammar/listener.go +++ b/common/hyperscaler/rules/grammar/listener.go @@ -1,6 +1,7 @@ package grammar import ( + "github.com/antlr4-go/antlr/v4" "github.com/kyma-project/kyma-environment-broker/common/hyperscaler/rules" parser "github.com/kyma-project/kyma-environment-broker/common/hyperscaler/rules/grammar/antlr" ) @@ -13,30 +14,54 @@ type RuleListener struct { func (r RuleListener) EnterEntry(c *parser.EntryContext) { if c.PLAN() != nil { - r.processed.Plan = c.PLAN().GetText() + _, err := r.processed.SetPlan(c.PLAN().GetText()) + if err != nil { + reportError(err.Error(), c.BaseParserRuleContext, c.GetParser()) + } } } func (r *RuleListener) EnterPrVal(c *parser.PrValContext) { if c.Val() != nil { - r.processed.PlatformRegion = c.Val().GetText() + _, err := r.processed.SetAttributeValue("PR", c.Val().GetText()) + if err != nil { + reportError(err.Error(), c.BaseParserRuleContext, c.GetParser()) + } } } func (r *RuleListener) EnterHrVal(c *parser.HrValContext) { if c.Val() != nil { - r.processed.HyperscalerRegion = c.Val().GetText() + _, err := r.processed.SetAttributeValue("HR", c.Val().GetText()) + if err != nil { + reportError(err.Error(), c.BaseParserRuleContext, c.GetParser()) + } } } -func (s *RuleListener) EnterS(c *parser.SContext) { + + +func (r *RuleListener) EnterS(c *parser.SContext) { if c.S() != nil { - s.processed.Shared = true + _, err := r.processed.SetAttributeValue("S", "true") + if err != nil { + reportError(err.Error(), c.BaseParserRuleContext, c.GetParser()) + } } } -func (s *RuleListener) EnterEu(c *parser.EuContext) { +func (r *RuleListener) EnterEu(c *parser.EuContext) { if c.EU() != nil { - s.processed.EuAccess = true + _, err := r.processed.SetAttributeValue("EU", "true") + if err != nil { + reportError(err.Error(), c.BaseParserRuleContext, c.GetParser()) + } } } + +func reportError(msg string, ruleCtx antlr.BaseParserRuleContext, parser antlr.Parser) { + excp := antlr.NewBaseRecognitionException(msg, parser, nil, &ruleCtx) + ruleCtx.SetException(excp) + parser.GetErrorHandler().ReportError(parser, excp) + parser.SetError(excp) +} \ No newline at end of file diff --git a/common/hyperscaler/rules/parser_test_utils.go b/common/hyperscaler/rules/parser_test_utils.go index 414fb55850..6114d5c069 100644 --- a/common/hyperscaler/rules/parser_test_utils.go +++ b/common/hyperscaler/rules/parser_test_utils.go @@ -148,12 +148,118 @@ func ParserHappyPathTest(t *testing.T, parser Parser) { func ParserValidationTest(t *testing.T, parser Parser) { - t.Run("with paranthesis only", func(t *testing.T) { + t.Run("with paranthesis only, no attributes", func(t *testing.T) { rule, err := parser.Parse("()") require.Nil(t, rule) require.Error(t, err) }) + t.Run("with duplicated arrow", func(t *testing.T) { + rule, err := parser.Parse("->->") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("plan(PR=test, HR=test2) ->-> S, EU") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("plan(PR=test, HR=test2)-> S -> EU") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("plan->(PR=test, HR=test2)-> S, EU") + require.Nil(t, rule) + require.Error(t, err) + + }) + + + t.Run("with invalid equal sign", func(t *testing.T) { + rule, err := parser.Parse("=") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("==") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("===") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("=azure=") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure==") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure=(PR=westeu, HR=easteu)=") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure=(PR=westeu, HR=easteu=wsteu)") + require.Nil(t, rule) + require.Error(t, err) + }) + + t.Run("with duplicated or unclosed parantheses", func(t *testing.T) { + rule, err := parser.Parse("(())") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("(") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("((") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse(")") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("))") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("())") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("aws(())") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("aws(") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("aws((") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("aws)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("aws))") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("aws())") + require.Nil(t, rule) + require.Error(t, err) + + + rule, err = parser.Parse("aws(PR=westeu, HR=easteu") + require.Nil(t, rule) + require.Error(t, err) + + }) + t.Run("with arrow only", func(t *testing.T) { rule, err := parser.Parse("->") require.Nil(t, rule) @@ -170,13 +276,121 @@ func ParserValidationTest(t *testing.T, parser Parser) { require.Error(t, err) }) -// t.Run("with duplicated input attribute", func(t *testing.T) { -// rule, err := parser.Parse("azure(PR=test,PR=test2)") -// require.Nil(t, rule) -// require.Error(t, err) + t.Run("with duplicated input, output attribute - PR", func(t *testing.T) { + rule, err := parser.Parse("azure(PR=test,PR=test2)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure(PR=test,PR)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure(HR=test,HR=test2)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure(HR=test,HR)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("test(PR=west,HR=east)->EU,EU") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("test(PR=west,HR=east)->S,S") + require.Nil(t, rule) + require.Error(t, err) + + }) + + t.Run("with whitespace which should be ignored", func(t *testing.T) { + rule, err := parser.Parse("azure ( PR = TEST, HR = TEST2 ) -> EU , S") + require.NoError(t, err) + + require.NotNil(t, rule) + require.Equal(t, "azure", rule.Plan) + require.Equal(t, "TEST", rule.PlatformRegion) + require.Equal(t, "TEST2", rule.HyperscalerRegion) + + require.True(t, rule.EuAccess) + require.True(t, rule.Shared) + }) + + t.Run("with invalid comma", func(t *testing.T) { + rule, err := parser.Parse("azure(PR=test,,PR=test2)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure(,,)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("test(PR=west,HR=east)->,,") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("test(PR=west,HR=east)->,S") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("test(PR=west,,)->S,EU") + require.Nil(t, rule) + require.Error(t, err) -// rule, err = parser.Parse("test(PR=west,HR=east)->EU,EU") -// require.Nil(t, rule) -// require.Error(t, err) -// }) -} \ No newline at end of file + rule, err = parser.Parse("test(PR=west,HR=east)->S,,") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("test(PR=west.HR=east)->S") + require.Nil(t, rule) + require.Error(t, err) + + }) + + t.Run("with unsupported attributes", func(t *testing.T) { + rule, err := parser.Parse("azure(DR=invalid-key)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure(PR=valid-key)->S,AA") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure(PR=valid-key)->AA") + require.Nil(t, rule) + require.Error(t, err) + }) + + t.Run("with unsupported plan", func(t *testing.T) { + rule, err := parser.Parse("azuree") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azurrre(PR=valid-key)->S") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("not-existing-plan(PR=valid-key)->EU") + require.Nil(t, rule) + require.Error(t, err) + }) + + + t.Run("without input attirbute value", func(t *testing.T) { + rule, err := parser.Parse("azure(PR)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure(PR=)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure(PR, HR)") + require.Nil(t, rule) + require.Error(t, err) + + rule, err = parser.Parse("azure(HR)") + require.Nil(t, rule) + require.Error(t, err) + }) +} diff --git a/common/hyperscaler/rules/rule.go b/common/hyperscaler/rules/rule.go index 7e82486d4f..0c35aa27f2 100644 --- a/common/hyperscaler/rules/rule.go +++ b/common/hyperscaler/rules/rule.go @@ -1,5 +1,11 @@ package rules +import ( + "fmt" + + "github.com/kyma-project/kyma-environment-broker/internal/broker" +) + type Rule struct { Plan string PlatformRegion string @@ -21,4 +27,56 @@ func (r *Rule) Matched() bool { } return false +} + + +func (r* Rule) SetAttributeValue(attribute, value string) (*Rule, error) { + switch attribute { + case "PR": + if r.PlatformRegion != "" { + return nil, fmt.Errorf("PlatformRegion already set"); + } else if value == "" { + return nil, fmt.Errorf("PlatformRegion is empty") + } + + r.PlatformRegion = value + case "HR": + if r.HyperscalerRegion != "" { + return nil, fmt.Errorf("HyperscalerRegion already set"); + } else if value == "" { + return nil, fmt.Errorf("HyperscalerRegion is empty") + } + + r.HyperscalerRegion = value + case "EU": + if r.EuAccess { + return nil, fmt.Errorf("EuAccess already set"); + } + r.EuAccess = true + case "S": + if r.Shared { + return nil, fmt.Errorf("Shared already set"); + } + + r.Shared = true + default: + return nil, fmt.Errorf("unknown attribute %s", attribute) + } + + return r, nil +} + +func (r* Rule) SetPlan(value string) (*Rule, error) { + if value == "" { + return nil, fmt.Errorf("plan is empty") + } + + // validate that the plan is supported + _, ok := broker.PlanIDsMapping[value] + if !ok { + return nil, fmt.Errorf("plan %s is not supported", value) + } + + r.Plan = value + return r, nil } \ No newline at end of file diff --git a/common/hyperscaler/rules/simple_parser.go b/common/hyperscaler/rules/simple_parser.go index 427b4d62f6..d76b58fd63 100644 --- a/common/hyperscaler/rules/simple_parser.go +++ b/common/hyperscaler/rules/simple_parser.go @@ -3,6 +3,7 @@ package rules import ( "fmt" "strings" + ) type SimpleParser struct{ @@ -12,15 +13,43 @@ type SimpleParser struct{ func (g* SimpleParser) Parse(ruleEntry string) (*Rule, error) { outputRule := &Rule{} + ruleEntry = strings.ReplaceAll(ruleEntry, " ", "") + ruleEntry = strings.ReplaceAll(ruleEntry, "\t", "") + ruleEntry = strings.ReplaceAll(ruleEntry, "\n", "") + ruleEntry = strings.ReplaceAll(ruleEntry, "\r", "") + ruleEntry = strings.ReplaceAll(ruleEntry, "\f", "") + outputInputPart := strings.Split(ruleEntry, "->") + if len(outputInputPart) > 2 { + return nil, fmt.Errorf("rule has more than one arrows") + } + inputPart := outputInputPart[0] planAndInputAttr := strings.Split(inputPart, "(") - outputRule.Plan = planAndInputAttr[0] - if outputRule.Plan == "" { - return nil, fmt.Errorf("plan is empty") + if len(planAndInputAttr) > 2 { + return nil, fmt.Errorf("rule has more than one '('") + } + + forValidationOnly := strings.Split(inputPart, ")") + + if len(forValidationOnly) > 2 { + return nil, fmt.Errorf("rule has more than one ')'") + } + + if strings.Contains(inputPart, "(") && !strings.Contains(inputPart, ")") { + return nil, fmt.Errorf("rule has unclosed parantheses") + } + + if !strings.Contains(inputPart, "(") && strings.Contains(inputPart, ")") { + return nil, fmt.Errorf("rule has unclosed parantheses") + } + + _, err := outputRule.SetPlan(planAndInputAttr[0]) + if err != nil { + return nil, err } if len(planAndInputAttr) > 1 { @@ -34,12 +63,15 @@ func (g* SimpleParser) Parse(ruleEntry string) (*Rule, error) { return nil, fmt.Errorf("input attribute is empty") } - if strings.Contains(inputAttr, "PR") { - outputRule.PlatformRegion = strings.Split(inputAttr, "=")[1] + attribute := strings.Split(inputAttr, "=") + + if len(attribute) != 2 { + return nil, fmt.Errorf("input attribute has no value") } - if strings.Contains(inputAttr, "HR") { - outputRule.HyperscalerRegion = strings.Split(inputAttr, "=")[1] + _, err := outputRule.SetAttributeValue(attribute[0], attribute[1]) + if err != nil { + return nil, err } } } @@ -52,13 +84,14 @@ func (g* SimpleParser) Parse(ruleEntry string) (*Rule, error) { return nil, fmt.Errorf("output attribute is empty") } - if outputAttr == "S" { - outputRule.Shared = true - } else if outputAttr == "EU" { - outputRule.EuAccess = true + _, err := outputRule.SetAttributeValue(outputAttr, "true") + if err != nil { + return nil, err } } } return outputRule, nil } + +