From 74ac2f668680d24eef9790af0219bd69ac64314b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20H=C3=B6rstrup?= Date: Fri, 23 Aug 2024 15:22:20 +0200 Subject: [PATCH] Refactor PFDL code (#60) - Make code more modular to enable the reuse of the code (e.g.. make more functions and methods single purpose) - Fix various bugs in the petri net generation - Renaming - Format code and add docstrings - Allow a PFDL program to be passed over to the scheduler as a string (currently, only a file path was allowed) - Add various quality of live features/fixes - Allow the free configuration of the "start task" (former productionTask) - Allow integers as loop limits and negative numbers --------- Co-authored-by: Oliver Stolz --- pfdl_grammar/PFDLLexer.g4 | 40 +- pfdl_grammar/PFDLParser.g4 | 33 +- pfdl_scheduler/model/process.py | 10 +- pfdl_scheduler/parser/PFDLLexer.py | 450 +++---- pfdl_scheduler/parser/PFDLParser.py | 1097 +++++++++-------- pfdl_scheduler/parser/PFDLParserVisitor.py | 7 +- pfdl_scheduler/parser/pfdl_tree_visitor.py | 52 +- pfdl_scheduler/petri_net/drawer.py | 5 +- pfdl_scheduler/petri_net/generator.py | 565 +++++---- pfdl_scheduler/petri_net/logic.py | 43 +- pfdl_scheduler/scheduler.py | 152 ++- pfdl_scheduler/scheduling/event.py | 2 +- pfdl_scheduler/utils/dashboard_observer.py | 16 +- pfdl_scheduler/utils/helpers.py | 40 +- pfdl_scheduler/utils/log_entry_observer.py | 4 +- pfdl_scheduler/utils/parsing_utils.py | 32 +- pfdl_scheduler/validation/error_handler.py | 4 +- .../validation/semantic_error_checker.py | 56 +- scheduler_demo.py | 20 +- .../test_scheduling_callbacks.py | 54 +- .../test_scheduling_marking.py | 84 +- .../scheduling/task_synchronisation.pfdl | 10 +- tests/unit_test/test_pfdl_tree_visitor.py | 115 +- .../unit_test/test_semantic_error_checker.py | 44 +- validate_pfdl_file.py | 6 +- 25 files changed, 1532 insertions(+), 1409 deletions(-) diff --git a/pfdl_grammar/PFDLLexer.g4 b/pfdl_grammar/PFDLLexer.g4 index 949ce49..086328c 100644 --- a/pfdl_grammar/PFDLLexer.g4 +++ b/pfdl_grammar/PFDLLexer.g4 @@ -1,11 +1,14 @@ lexer grammar PFDLLexer; -// DenterHelper for generating INDENT AND DEDENT tokens to realize -// a python-like grammar with Indentations +// DenterHelper for generating INDENT AND DEDENT tokens to realize a python-like grammar with +// Indentations -tokens { INDENT, DEDENT } +tokens { + INDENT, + DEDENT +} -@lexer::header{ +@lexer::header { from antlr_denter.DenterHelper import DenterHelper from PFDLParser import PFDLParser } @@ -56,7 +59,7 @@ QUOTE: '"'; ARRAY_LEFT: '['; ARRAY_RIGHT: ']'; -COMMENT : '#' ~[\n]+ -> skip; +COMMENT: '#' ~[\n]* -> skip; WHITESPACE: [ \t]+ -> skip; NL: ('\r'? '\n' ' '*); @@ -76,48 +79,39 @@ SLASH: '/'; MINUS: '-'; PLUS: '+'; - INTEGER: [0-9]+; -FLOAT: INTEGER '.'INTEGER; +FLOAT: INTEGER '.' INTEGER; -STRING: '"' ('\\"'|.)*? '"'; +STRING: '"' ('\\"' | .)*? '"'; STARTS_WITH_LOWER_C_STR: [a-z][a-zA-Z0-9_]*; STARTS_WITH_UPPER_C_STR: [A-Z][a-zA-Z0-9_]*; // JSON Grammar mode JSON; -JSON_STRING: '"' ('\\"'|.)*? '"'; +JSON_STRING: '"' ('\\"' | .)*? '"'; JSON_TRUE: 'true'; JSON_FALSE: 'false'; JSON_COLON: ':'; JSON_QUOTE: '"'; -JSON_COMMENT : '#' ~[\n]+ -> skip; +JSON_COMMENT: '#' ~[\n]+ -> skip; JSON_ARRAY_LEFT: '['; JSON_ARRAY_RIGHT: ']'; JSON_COMMA: ','; -NUMBER - : '-'? INT ('.' [0-9] +)? EXP? - ; +NUMBER: '-'? INT ('.' [0-9]+)? EXP?; -fragment INT - : '0' | [1-9] [0-9]* - ; +fragment INT: '0' | [1-9] [0-9]*; // no leading zeros -fragment EXP - : [Ee] [+\-]? INT - ; +fragment EXP: [Ee] [+\-]? INT; -WS - : [ \t\n\r] + -> skip - ; +WS: [ \t\n\r]+ -> skip; JSON_OPEN_2: '{' -> pushMode(JSON); -JSON_CLOSE: '}' -> popMode; \ No newline at end of file +JSON_CLOSE: '}' -> popMode; diff --git a/pfdl_grammar/PFDLParser.g4 b/pfdl_grammar/PFDLParser.g4 index 6e4f942..a8c5dac 100644 --- a/pfdl_grammar/PFDLParser.g4 +++ b/pfdl_grammar/PFDLParser.g4 @@ -48,7 +48,7 @@ while_loop: LOOP WHILE expression INDENT statement+ DEDENT; counting_loop: - PARALLEL? LOOP STARTS_WITH_LOWER_C_STR TO attribute_access INDENT statement+ DEDENT; + PARALLEL? LOOP STARTS_WITH_LOWER_C_STR TO (attribute_access | INTEGER) INDENT statement+ DEDENT; condition: CONDITION INDENT expression NL+ DEDENT condition_passed condition_failed?; @@ -60,15 +60,16 @@ condition_failed: FAILED INDENT statement+ DEDENT; parameter: - STARTS_WITH_LOWER_C_STR - | attribute_access; + STARTS_WITH_LOWER_C_STR | attribute_access; struct_initialization: STARTS_WITH_UPPER_C_STR INDENT json_object NL+ DEDENT | STARTS_WITH_UPPER_C_STR NL* json_object NL*; variable_definition: - STARTS_WITH_LOWER_C_STR COLON primitive array?; + STARTS_WITH_LOWER_C_STR COLON variable_type; + +variable_type: primitive array?; primitive: NUMBER_P @@ -82,9 +83,7 @@ attribute_access: array: ARRAY_LEFT (INTEGER | STARTS_WITH_LOWER_C_STR)? ARRAY_RIGHT; -number: - INTEGER - | FLOAT; +number: MINUS? (INTEGER | FLOAT); value: TRUE @@ -128,13 +127,13 @@ json_open_bracket: JSON_OPEN | JSON_OPEN_2; json_value: - JSON_STRING - | JSON_TRUE - | JSON_FALSE - | NUMBER - | json_object - | json_array; - -json_array - : JSON_ARRAY_LEFT json_value (JSON_COMMA json_value)* JSON_ARRAY_RIGHT - | JSON_ARRAY_LEFT JSON_ARRAY_RIGHT; \ No newline at end of file + JSON_STRING + | JSON_TRUE + | JSON_FALSE + | NUMBER + | json_object + | json_array; + +json_array: + JSON_ARRAY_LEFT json_value (JSON_COMMA json_value)* JSON_ARRAY_RIGHT + | JSON_ARRAY_LEFT JSON_ARRAY_RIGHT; diff --git a/pfdl_scheduler/model/process.py b/pfdl_scheduler/model/process.py index 09d61bc..c9038fc 100644 --- a/pfdl_scheduler/model/process.py +++ b/pfdl_scheduler/model/process.py @@ -25,14 +25,21 @@ class Process: Attributes: structs: A dict for mapping the Struct names to the Struct objects. task: A dict for mapping the Task names to the Task objects. + start_task_name: the name of the start task of the PFDL program (typically "productionTask"). """ - def __init__(self, structs: Dict[str, Struct] = None, tasks: Dict[str, Task] = None) -> None: + def __init__( + self, + structs: Dict[str, Struct] = None, + tasks: Dict[str, Task] = None, + start_task_name: str = "productionTask", + ) -> None: """Initialize the object. Args: structs: A dict for mapping the Struct names to the Struct objects. tasks: A dict for mapping the Task names to the Task objects. + start_task_name: the name of the start task of the PFDL program (typically "productionTask"). """ if structs: self.structs: Dict[str, Struct] = structs @@ -42,3 +49,4 @@ def __init__(self, structs: Dict[str, Struct] = None, tasks: Dict[str, Task] = N self.tasks: Dict[str, Task] = tasks else: self.tasks: Dict[str, Task] = {} + self.start_task_name = start_task_name diff --git a/pfdl_scheduler/parser/PFDLLexer.py b/pfdl_scheduler/parser/PFDLLexer.py index 391e5bf..896d888 100644 --- a/pfdl_scheduler/parser/PFDLLexer.py +++ b/pfdl_scheduler/parser/PFDLLexer.py @@ -1,8 +1,7 @@ -# Generated from PFDLLexer.g4 by ANTLR 4.9.2 +# Generated from PFDLLexer.g4 by ANTLR 4.9.3 from antlr4 import * from io import StringIO import sys - if sys.version_info[1] > 5: from typing import TextIO else: @@ -13,16 +12,17 @@ from pfdl_scheduler.parser.PFDLParser import PFDLParser + def serializedATN(): with StringIO() as buf: buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2A") - buf.write("\u01b6\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6") + buf.write("\u01b7\b\1\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6") buf.write("\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r") buf.write("\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22") buf.write("\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30") buf.write("\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35") - buf.write('\4\36\t\36\4\37\t\37\4 \t \4!\t!\4"\t"\4#\t#\4$\t$\4') - buf.write("%\t%\4&\t&\4'\t'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t") + buf.write("\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$\t$\4") + buf.write("%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t,\4-\t") buf.write("-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63") buf.write("\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4") buf.write(":\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\3\2\3\2\3\2\3") @@ -36,34 +36,34 @@ def serializedATN(): buf.write("\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\22\3\22\3\22") buf.write("\3\22\3\22\3\23\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3\25") buf.write("\3\25\3\26\3\26\3\27\3\27\3\27\3\27\3\30\3\30\3\31\3\31") - buf.write("\3\32\3\32\3\33\3\33\6\33\u0103\n\33\r\33\16\33\u0104") - buf.write("\3\33\3\33\3\34\6\34\u010a\n\34\r\34\16\34\u010b\3\34") - buf.write("\3\34\3\35\5\35\u0111\n\35\3\35\3\35\7\35\u0115\n\35\f") - buf.write("\35\16\35\u0118\13\35\3\36\3\36\3\37\3\37\3 \3 \3!\3!") - buf.write('\3!\3"\3"\3#\3#\3#\3$\3$\3$\3%\3%\3%\3&\3&\3&\3&\3\'') - buf.write("\3'\3'\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-\6-\u0140\n-") - buf.write("\r-\16-\u0141\3.\3.\3.\3.\3/\3/\3/\3/\7/\u014c\n/\f/\16") - buf.write("/\u014f\13/\3/\3/\3\60\3\60\7\60\u0155\n\60\f\60\16\60") - buf.write("\u0158\13\60\3\61\3\61\7\61\u015c\n\61\f\61\16\61\u015f") - buf.write("\13\61\3\62\3\62\3\62\3\62\7\62\u0165\n\62\f\62\16\62") - buf.write("\u0168\13\62\3\62\3\62\3\63\3\63\3\63\3\63\3\63\3\64\3") + buf.write("\3\32\3\32\3\33\3\33\7\33\u0103\n\33\f\33\16\33\u0106") + buf.write("\13\33\3\33\3\33\3\34\6\34\u010b\n\34\r\34\16\34\u010c") + buf.write("\3\34\3\34\3\35\5\35\u0112\n\35\3\35\3\35\7\35\u0116\n") + buf.write("\35\f\35\16\35\u0119\13\35\3\36\3\36\3\37\3\37\3 \3 \3") + buf.write("!\3!\3!\3\"\3\"\3#\3#\3#\3$\3$\3$\3%\3%\3%\3&\3&\3&\3") + buf.write("&\3\'\3\'\3\'\3(\3(\3)\3)\3*\3*\3+\3+\3,\3,\3-\6-\u0141") + buf.write("\n-\r-\16-\u0142\3.\3.\3.\3.\3/\3/\3/\3/\7/\u014d\n/\f") + buf.write("/\16/\u0150\13/\3/\3/\3\60\3\60\7\60\u0156\n\60\f\60\16") + buf.write("\60\u0159\13\60\3\61\3\61\7\61\u015d\n\61\f\61\16\61\u0160") + buf.write("\13\61\3\62\3\62\3\62\3\62\7\62\u0166\n\62\f\62\16\62") + buf.write("\u0169\13\62\3\62\3\62\3\63\3\63\3\63\3\63\3\63\3\64\3") buf.write("\64\3\64\3\64\3\64\3\64\3\65\3\65\3\66\3\66\3\67\3\67") - buf.write("\6\67\u017d\n\67\r\67\16\67\u017e\3\67\3\67\38\38\39\3") - buf.write("9\3:\3:\3;\5;\u018a\n;\3;\3;\3;\6;\u018f\n;\r;\16;\u0190") - buf.write("\5;\u0193\n;\3;\5;\u0196\n;\3<\3<\3<\7<\u019b\n<\f<\16") - buf.write("<\u019e\13<\5<\u01a0\n<\3=\3=\5=\u01a4\n=\3=\3=\3>\6>") - buf.write("\u01a9\n>\r>\16>\u01aa\3>\3>\3?\3?\3?\3?\3@\3@\3@\3@\4") - buf.write("\u014d\u0166\2A\4\5\6\6\b\7\n\b\f\t\16\n\20\13\22\f\24") - buf.write('\r\26\16\30\17\32\20\34\21\36\22 \23"\24$\25&\26(\27') - buf.write('*\30,\31.\32\60\33\62\34\64\35\66\368\37: "@#B$D%') - buf.write("F&H'J(L)N*P+R,T-V.X/Z\60\\\61^\62`\63b\64d\65f\66h\67") + buf.write("\6\67\u017e\n\67\r\67\16\67\u017f\3\67\3\67\38\38\39\3") + buf.write("9\3:\3:\3;\5;\u018b\n;\3;\3;\3;\6;\u0190\n;\r;\16;\u0191") + buf.write("\5;\u0194\n;\3;\5;\u0197\n;\3<\3<\3<\7<\u019c\n<\f<\16") + buf.write("<\u019f\13<\5<\u01a1\n<\3=\3=\5=\u01a5\n=\3=\3=\3>\6>") + buf.write("\u01aa\n>\r>\16>\u01ab\3>\3>\3?\3?\3?\3?\3@\3@\3@\3@\4") + buf.write("\u014e\u0167\2A\4\5\6\6\b\7\n\b\f\t\16\n\20\13\22\f\24") + buf.write("\r\26\16\30\17\32\20\34\21\36\22 \23\"\24$\25&\26(\27") + buf.write("*\30,\31.\32\60\33\62\34\64\35\66\368\37: \"@#B$D%") + buf.write("F&H\'J(L)N*P+R,T-V.X/Z\60\\\61^\62`\63b\64d\65f\66h\67") buf.write("j8l9n:p;rx\2z\2|?~@\u0080A\4\2\3\f\3\2\f\f\4\2\13") - buf.write('\13""\3\2\62;\3\2c|\6\2\62;C\\aac|\3\2C\\\3\2\63;\4') - buf.write('\2GGgg\4\2--//\5\2\13\f\17\17""\2\u01c6\2\4\3\2\2\2') + buf.write("\13\"\"\3\2\62;\3\2c|\6\2\62;C\\aac|\3\2C\\\3\2\63;\4") + buf.write("\2GGgg\4\2--//\5\2\13\f\17\17\"\"\2\u01c7\2\4\3\2\2\2") buf.write("\2\6\3\2\2\2\2\b\3\2\2\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16") buf.write("\3\2\2\2\2\20\3\2\2\2\2\22\3\2\2\2\2\24\3\2\2\2\2\26\3") buf.write("\2\2\2\2\30\3\2\2\2\2\32\3\2\2\2\2\34\3\2\2\2\2\36\3\2") - buf.write('\2\2\2 \3\2\2\2\2"\3\2\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3') + buf.write("\2\2\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2\2\2&\3\2\2\2\2(\3") buf.write("\2\2\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2") buf.write("\62\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\28\3\2\2\2\2:\3") buf.write("\2\2\2\2<\3\2\2\2\2>\3\2\2\2\2@\3\2\2\2\2B\3\2\2\2\2D") @@ -77,20 +77,20 @@ def serializedATN(): buf.write("\3\2\2\2\f\u0095\3\2\2\2\16\u009a\3\2\2\2\20\u00a0\3\2") buf.write("\2\2\22\u00a3\3\2\2\2\24\u00ac\3\2\2\2\26\u00b6\3\2\2") buf.write("\2\30\u00bd\3\2\2\2\32\u00c4\3\2\2\2\34\u00cb\3\2\2\2") - buf.write('\36\u00cf\3\2\2\2 \u00d6\3\2\2\2"\u00dd\3\2\2\2$\u00e5') + buf.write("\36\u00cf\3\2\2\2 \u00d6\3\2\2\2\"\u00dd\3\2\2\2$\u00e5") buf.write("\3\2\2\2&\u00ea\3\2\2\2(\u00f0\3\2\2\2*\u00f2\3\2\2\2") buf.write(",\u00f4\3\2\2\2.\u00f6\3\2\2\2\60\u00fa\3\2\2\2\62\u00fc") - buf.write("\3\2\2\2\64\u00fe\3\2\2\2\66\u0100\3\2\2\28\u0109\3\2") - buf.write("\2\2:\u0110\3\2\2\2<\u0119\3\2\2\2>\u011b\3\2\2\2@\u011d") - buf.write("\3\2\2\2B\u011f\3\2\2\2D\u0122\3\2\2\2F\u0124\3\2\2\2") - buf.write("H\u0127\3\2\2\2J\u012a\3\2\2\2L\u012d\3\2\2\2N\u0131\3") - buf.write("\2\2\2P\u0134\3\2\2\2R\u0136\3\2\2\2T\u0138\3\2\2\2V\u013a") - buf.write("\3\2\2\2X\u013c\3\2\2\2Z\u013f\3\2\2\2\\\u0143\3\2\2\2") - buf.write("^\u0147\3\2\2\2`\u0152\3\2\2\2b\u0159\3\2\2\2d\u0160\3") - buf.write("\2\2\2f\u016b\3\2\2\2h\u0170\3\2\2\2j\u0176\3\2\2\2l\u0178") - buf.write("\3\2\2\2n\u017a\3\2\2\2p\u0182\3\2\2\2r\u0184\3\2\2\2") - buf.write("t\u0186\3\2\2\2v\u0189\3\2\2\2x\u019f\3\2\2\2z\u01a1\3") - buf.write("\2\2\2|\u01a8\3\2\2\2~\u01ae\3\2\2\2\u0080\u01b2\3\2\2") + buf.write("\3\2\2\2\64\u00fe\3\2\2\2\66\u0100\3\2\2\28\u010a\3\2") + buf.write("\2\2:\u0111\3\2\2\2<\u011a\3\2\2\2>\u011c\3\2\2\2@\u011e") + buf.write("\3\2\2\2B\u0120\3\2\2\2D\u0123\3\2\2\2F\u0125\3\2\2\2") + buf.write("H\u0128\3\2\2\2J\u012b\3\2\2\2L\u012e\3\2\2\2N\u0132\3") + buf.write("\2\2\2P\u0135\3\2\2\2R\u0137\3\2\2\2T\u0139\3\2\2\2V\u013b") + buf.write("\3\2\2\2X\u013d\3\2\2\2Z\u0140\3\2\2\2\\\u0144\3\2\2\2") + buf.write("^\u0148\3\2\2\2`\u0153\3\2\2\2b\u015a\3\2\2\2d\u0161\3") + buf.write("\2\2\2f\u016c\3\2\2\2h\u0171\3\2\2\2j\u0177\3\2\2\2l\u0179") + buf.write("\3\2\2\2n\u017b\3\2\2\2p\u0183\3\2\2\2r\u0185\3\2\2\2") + buf.write("t\u0187\3\2\2\2v\u018a\3\2\2\2x\u01a0\3\2\2\2z\u01a2\3") + buf.write("\2\2\2|\u01a9\3\2\2\2~\u01af\3\2\2\2\u0080\u01b3\3\2\2") buf.write("\2\u0082\u0083\7U\2\2\u0083\u0084\7v\2\2\u0084\u0085\7") buf.write("t\2\2\u0085\u0086\7w\2\2\u0086\u0087\7e\2\2\u0087\u0088") buf.write("\7v\2\2\u0088\5\3\2\2\2\u0089\u008a\7V\2\2\u008a\u008b") @@ -127,86 +127,86 @@ def serializedATN(): buf.write("\2\2\2\u00e5\u00e6\7v\2\2\u00e6\u00e7\7t\2\2\u00e7\u00e8") buf.write("\7w\2\2\u00e8\u00e9\7g\2\2\u00e9%\3\2\2\2\u00ea\u00eb") buf.write("\7h\2\2\u00eb\u00ec\7c\2\2\u00ec\u00ed\7n\2\2\u00ed\u00ee") - buf.write("\7u\2\2\u00ee\u00ef\7g\2\2\u00ef'\3\2\2\2\u00f0\u00f1") + buf.write("\7u\2\2\u00ee\u00ef\7g\2\2\u00ef\'\3\2\2\2\u00f0\u00f1") buf.write("\7<\2\2\u00f1)\3\2\2\2\u00f2\u00f3\7\60\2\2\u00f3+\3\2") buf.write("\2\2\u00f4\u00f5\7.\2\2\u00f5-\3\2\2\2\u00f6\u00f7\7}") buf.write("\2\2\u00f7\u00f8\3\2\2\2\u00f8\u00f9\b\27\2\2\u00f9/\3") buf.write("\2\2\2\u00fa\u00fb\7$\2\2\u00fb\61\3\2\2\2\u00fc\u00fd") buf.write("\7]\2\2\u00fd\63\3\2\2\2\u00fe\u00ff\7_\2\2\u00ff\65\3") - buf.write("\2\2\2\u0100\u0102\7%\2\2\u0101\u0103\n\2\2\2\u0102\u0101") - buf.write("\3\2\2\2\u0103\u0104\3\2\2\2\u0104\u0102\3\2\2\2\u0104") - buf.write("\u0105\3\2\2\2\u0105\u0106\3\2\2\2\u0106\u0107\b\33\3") - buf.write("\2\u0107\67\3\2\2\2\u0108\u010a\t\3\2\2\u0109\u0108\3") - buf.write("\2\2\2\u010a\u010b\3\2\2\2\u010b\u0109\3\2\2\2\u010b\u010c") - buf.write("\3\2\2\2\u010c\u010d\3\2\2\2\u010d\u010e\b\34\3\2\u010e") - buf.write("9\3\2\2\2\u010f\u0111\7\17\2\2\u0110\u010f\3\2\2\2\u0110") - buf.write("\u0111\3\2\2\2\u0111\u0112\3\2\2\2\u0112\u0116\7\f\2\2") - buf.write('\u0113\u0115\7"\2\2\u0114\u0113\3\2\2\2\u0115\u0118\3') - buf.write("\2\2\2\u0116\u0114\3\2\2\2\u0116\u0117\3\2\2\2\u0117;") - buf.write("\3\2\2\2\u0118\u0116\3\2\2\2\u0119\u011a\7*\2\2\u011a") - buf.write("=\3\2\2\2\u011b\u011c\7+\2\2\u011c?\3\2\2\2\u011d\u011e") - buf.write("\7>\2\2\u011eA\3\2\2\2\u011f\u0120\7>\2\2\u0120\u0121") - buf.write("\7?\2\2\u0121C\3\2\2\2\u0122\u0123\7@\2\2\u0123E\3\2\2") - buf.write("\2\u0124\u0125\7@\2\2\u0125\u0126\7?\2\2\u0126G\3\2\2") - buf.write("\2\u0127\u0128\7?\2\2\u0128\u0129\7?\2\2\u0129I\3\2\2") - buf.write("\2\u012a\u012b\7#\2\2\u012b\u012c\7?\2\2\u012cK\3\2\2") - buf.write("\2\u012d\u012e\7C\2\2\u012e\u012f\7p\2\2\u012f\u0130\7") - buf.write("f\2\2\u0130M\3\2\2\2\u0131\u0132\7Q\2\2\u0132\u0133\7") - buf.write("t\2\2\u0133O\3\2\2\2\u0134\u0135\7#\2\2\u0135Q\3\2\2\2") - buf.write("\u0136\u0137\7,\2\2\u0137S\3\2\2\2\u0138\u0139\7\61\2") - buf.write("\2\u0139U\3\2\2\2\u013a\u013b\7/\2\2\u013bW\3\2\2\2\u013c") - buf.write("\u013d\7-\2\2\u013dY\3\2\2\2\u013e\u0140\t\4\2\2\u013f") - buf.write("\u013e\3\2\2\2\u0140\u0141\3\2\2\2\u0141\u013f\3\2\2\2") - buf.write("\u0141\u0142\3\2\2\2\u0142[\3\2\2\2\u0143\u0144\5Z-\2") - buf.write("\u0144\u0145\7\60\2\2\u0145\u0146\5Z-\2\u0146]\3\2\2\2") - buf.write("\u0147\u014d\7$\2\2\u0148\u0149\7^\2\2\u0149\u014c\7$") - buf.write("\2\2\u014a\u014c\13\2\2\2\u014b\u0148\3\2\2\2\u014b\u014a") - buf.write("\3\2\2\2\u014c\u014f\3\2\2\2\u014d\u014e\3\2\2\2\u014d") - buf.write("\u014b\3\2\2\2\u014e\u0150\3\2\2\2\u014f\u014d\3\2\2\2") - buf.write("\u0150\u0151\7$\2\2\u0151_\3\2\2\2\u0152\u0156\t\5\2\2") - buf.write("\u0153\u0155\t\6\2\2\u0154\u0153\3\2\2\2\u0155\u0158\3") - buf.write("\2\2\2\u0156\u0154\3\2\2\2\u0156\u0157\3\2\2\2\u0157a") - buf.write("\3\2\2\2\u0158\u0156\3\2\2\2\u0159\u015d\t\7\2\2\u015a") - buf.write("\u015c\t\6\2\2\u015b\u015a\3\2\2\2\u015c\u015f\3\2\2\2") - buf.write("\u015d\u015b\3\2\2\2\u015d\u015e\3\2\2\2\u015ec\3\2\2") - buf.write("\2\u015f\u015d\3\2\2\2\u0160\u0166\7$\2\2\u0161\u0162") - buf.write("\7^\2\2\u0162\u0165\7$\2\2\u0163\u0165\13\2\2\2\u0164") - buf.write("\u0161\3\2\2\2\u0164\u0163\3\2\2\2\u0165\u0168\3\2\2\2") - buf.write("\u0166\u0167\3\2\2\2\u0166\u0164\3\2\2\2\u0167\u0169\3") - buf.write("\2\2\2\u0168\u0166\3\2\2\2\u0169\u016a\7$\2\2\u016ae\3") - buf.write("\2\2\2\u016b\u016c\7v\2\2\u016c\u016d\7t\2\2\u016d\u016e") - buf.write("\7w\2\2\u016e\u016f\7g\2\2\u016fg\3\2\2\2\u0170\u0171") - buf.write("\7h\2\2\u0171\u0172\7c\2\2\u0172\u0173\7n\2\2\u0173\u0174") - buf.write("\7u\2\2\u0174\u0175\7g\2\2\u0175i\3\2\2\2\u0176\u0177") - buf.write("\7<\2\2\u0177k\3\2\2\2\u0178\u0179\7$\2\2\u0179m\3\2\2") - buf.write("\2\u017a\u017c\7%\2\2\u017b\u017d\n\2\2\2\u017c\u017b") - buf.write("\3\2\2\2\u017d\u017e\3\2\2\2\u017e\u017c\3\2\2\2\u017e") - buf.write("\u017f\3\2\2\2\u017f\u0180\3\2\2\2\u0180\u0181\b\67\3") - buf.write("\2\u0181o\3\2\2\2\u0182\u0183\7]\2\2\u0183q\3\2\2\2\u0184") - buf.write("\u0185\7_\2\2\u0185s\3\2\2\2\u0186\u0187\7.\2\2\u0187") - buf.write("u\3\2\2\2\u0188\u018a\7/\2\2\u0189\u0188\3\2\2\2\u0189") - buf.write("\u018a\3\2\2\2\u018a\u018b\3\2\2\2\u018b\u0192\5x<\2\u018c") - buf.write("\u018e\7\60\2\2\u018d\u018f\t\4\2\2\u018e\u018d\3\2\2") - buf.write("\2\u018f\u0190\3\2\2\2\u0190\u018e\3\2\2\2\u0190\u0191") - buf.write("\3\2\2\2\u0191\u0193\3\2\2\2\u0192\u018c\3\2\2\2\u0192") - buf.write("\u0193\3\2\2\2\u0193\u0195\3\2\2\2\u0194\u0196\5z=\2\u0195") - buf.write("\u0194\3\2\2\2\u0195\u0196\3\2\2\2\u0196w\3\2\2\2\u0197") - buf.write("\u01a0\7\62\2\2\u0198\u019c\t\b\2\2\u0199\u019b\t\4\2") - buf.write("\2\u019a\u0199\3\2\2\2\u019b\u019e\3\2\2\2\u019c\u019a") - buf.write("\3\2\2\2\u019c\u019d\3\2\2\2\u019d\u01a0\3\2\2\2\u019e") - buf.write("\u019c\3\2\2\2\u019f\u0197\3\2\2\2\u019f\u0198\3\2\2\2") - buf.write("\u01a0y\3\2\2\2\u01a1\u01a3\t\t\2\2\u01a2\u01a4\t\n\2") - buf.write("\2\u01a3\u01a2\3\2\2\2\u01a3\u01a4\3\2\2\2\u01a4\u01a5") - buf.write("\3\2\2\2\u01a5\u01a6\5x<\2\u01a6{\3\2\2\2\u01a7\u01a9") - buf.write("\t\13\2\2\u01a8\u01a7\3\2\2\2\u01a9\u01aa\3\2\2\2\u01aa") - buf.write("\u01a8\3\2\2\2\u01aa\u01ab\3\2\2\2\u01ab\u01ac\3\2\2\2") - buf.write("\u01ac\u01ad\b>\3\2\u01ad}\3\2\2\2\u01ae\u01af\7}\2\2") - buf.write("\u01af\u01b0\3\2\2\2\u01b0\u01b1\b?\2\2\u01b1\177\3\2") - buf.write("\2\2\u01b2\u01b3\7\177\2\2\u01b3\u01b4\3\2\2\2\u01b4\u01b5") - buf.write("\b@\4\2\u01b5\u0081\3\2\2\2\30\2\3\u0104\u010b\u0110\u0116") - buf.write("\u0141\u014b\u014d\u0156\u015d\u0164\u0166\u017e\u0189") - buf.write("\u0190\u0192\u0195\u019c\u019f\u01a3\u01aa\5\7\3\2\b\2") - buf.write("\2\6\2\2") + buf.write("\2\2\2\u0100\u0104\7%\2\2\u0101\u0103\n\2\2\2\u0102\u0101") + buf.write("\3\2\2\2\u0103\u0106\3\2\2\2\u0104\u0102\3\2\2\2\u0104") + buf.write("\u0105\3\2\2\2\u0105\u0107\3\2\2\2\u0106\u0104\3\2\2\2") + buf.write("\u0107\u0108\b\33\3\2\u0108\67\3\2\2\2\u0109\u010b\t\3") + buf.write("\2\2\u010a\u0109\3\2\2\2\u010b\u010c\3\2\2\2\u010c\u010a") + buf.write("\3\2\2\2\u010c\u010d\3\2\2\2\u010d\u010e\3\2\2\2\u010e") + buf.write("\u010f\b\34\3\2\u010f9\3\2\2\2\u0110\u0112\7\17\2\2\u0111") + buf.write("\u0110\3\2\2\2\u0111\u0112\3\2\2\2\u0112\u0113\3\2\2\2") + buf.write("\u0113\u0117\7\f\2\2\u0114\u0116\7\"\2\2\u0115\u0114\3") + buf.write("\2\2\2\u0116\u0119\3\2\2\2\u0117\u0115\3\2\2\2\u0117\u0118") + buf.write("\3\2\2\2\u0118;\3\2\2\2\u0119\u0117\3\2\2\2\u011a\u011b") + buf.write("\7*\2\2\u011b=\3\2\2\2\u011c\u011d\7+\2\2\u011d?\3\2\2") + buf.write("\2\u011e\u011f\7>\2\2\u011fA\3\2\2\2\u0120\u0121\7>\2") + buf.write("\2\u0121\u0122\7?\2\2\u0122C\3\2\2\2\u0123\u0124\7@\2") + buf.write("\2\u0124E\3\2\2\2\u0125\u0126\7@\2\2\u0126\u0127\7?\2") + buf.write("\2\u0127G\3\2\2\2\u0128\u0129\7?\2\2\u0129\u012a\7?\2") + buf.write("\2\u012aI\3\2\2\2\u012b\u012c\7#\2\2\u012c\u012d\7?\2") + buf.write("\2\u012dK\3\2\2\2\u012e\u012f\7C\2\2\u012f\u0130\7p\2") + buf.write("\2\u0130\u0131\7f\2\2\u0131M\3\2\2\2\u0132\u0133\7Q\2") + buf.write("\2\u0133\u0134\7t\2\2\u0134O\3\2\2\2\u0135\u0136\7#\2") + buf.write("\2\u0136Q\3\2\2\2\u0137\u0138\7,\2\2\u0138S\3\2\2\2\u0139") + buf.write("\u013a\7\61\2\2\u013aU\3\2\2\2\u013b\u013c\7/\2\2\u013c") + buf.write("W\3\2\2\2\u013d\u013e\7-\2\2\u013eY\3\2\2\2\u013f\u0141") + buf.write("\t\4\2\2\u0140\u013f\3\2\2\2\u0141\u0142\3\2\2\2\u0142") + buf.write("\u0140\3\2\2\2\u0142\u0143\3\2\2\2\u0143[\3\2\2\2\u0144") + buf.write("\u0145\5Z-\2\u0145\u0146\7\60\2\2\u0146\u0147\5Z-\2\u0147") + buf.write("]\3\2\2\2\u0148\u014e\7$\2\2\u0149\u014a\7^\2\2\u014a") + buf.write("\u014d\7$\2\2\u014b\u014d\13\2\2\2\u014c\u0149\3\2\2\2") + buf.write("\u014c\u014b\3\2\2\2\u014d\u0150\3\2\2\2\u014e\u014f\3") + buf.write("\2\2\2\u014e\u014c\3\2\2\2\u014f\u0151\3\2\2\2\u0150\u014e") + buf.write("\3\2\2\2\u0151\u0152\7$\2\2\u0152_\3\2\2\2\u0153\u0157") + buf.write("\t\5\2\2\u0154\u0156\t\6\2\2\u0155\u0154\3\2\2\2\u0156") + buf.write("\u0159\3\2\2\2\u0157\u0155\3\2\2\2\u0157\u0158\3\2\2\2") + buf.write("\u0158a\3\2\2\2\u0159\u0157\3\2\2\2\u015a\u015e\t\7\2") + buf.write("\2\u015b\u015d\t\6\2\2\u015c\u015b\3\2\2\2\u015d\u0160") + buf.write("\3\2\2\2\u015e\u015c\3\2\2\2\u015e\u015f\3\2\2\2\u015f") + buf.write("c\3\2\2\2\u0160\u015e\3\2\2\2\u0161\u0167\7$\2\2\u0162") + buf.write("\u0163\7^\2\2\u0163\u0166\7$\2\2\u0164\u0166\13\2\2\2") + buf.write("\u0165\u0162\3\2\2\2\u0165\u0164\3\2\2\2\u0166\u0169\3") + buf.write("\2\2\2\u0167\u0168\3\2\2\2\u0167\u0165\3\2\2\2\u0168\u016a") + buf.write("\3\2\2\2\u0169\u0167\3\2\2\2\u016a\u016b\7$\2\2\u016b") + buf.write("e\3\2\2\2\u016c\u016d\7v\2\2\u016d\u016e\7t\2\2\u016e") + buf.write("\u016f\7w\2\2\u016f\u0170\7g\2\2\u0170g\3\2\2\2\u0171") + buf.write("\u0172\7h\2\2\u0172\u0173\7c\2\2\u0173\u0174\7n\2\2\u0174") + buf.write("\u0175\7u\2\2\u0175\u0176\7g\2\2\u0176i\3\2\2\2\u0177") + buf.write("\u0178\7<\2\2\u0178k\3\2\2\2\u0179\u017a\7$\2\2\u017a") + buf.write("m\3\2\2\2\u017b\u017d\7%\2\2\u017c\u017e\n\2\2\2\u017d") + buf.write("\u017c\3\2\2\2\u017e\u017f\3\2\2\2\u017f\u017d\3\2\2\2") + buf.write("\u017f\u0180\3\2\2\2\u0180\u0181\3\2\2\2\u0181\u0182\b") + buf.write("\67\3\2\u0182o\3\2\2\2\u0183\u0184\7]\2\2\u0184q\3\2\2") + buf.write("\2\u0185\u0186\7_\2\2\u0186s\3\2\2\2\u0187\u0188\7.\2") + buf.write("\2\u0188u\3\2\2\2\u0189\u018b\7/\2\2\u018a\u0189\3\2\2") + buf.write("\2\u018a\u018b\3\2\2\2\u018b\u018c\3\2\2\2\u018c\u0193") + buf.write("\5x<\2\u018d\u018f\7\60\2\2\u018e\u0190\t\4\2\2\u018f") + buf.write("\u018e\3\2\2\2\u0190\u0191\3\2\2\2\u0191\u018f\3\2\2\2") + buf.write("\u0191\u0192\3\2\2\2\u0192\u0194\3\2\2\2\u0193\u018d\3") + buf.write("\2\2\2\u0193\u0194\3\2\2\2\u0194\u0196\3\2\2\2\u0195\u0197") + buf.write("\5z=\2\u0196\u0195\3\2\2\2\u0196\u0197\3\2\2\2\u0197w") + buf.write("\3\2\2\2\u0198\u01a1\7\62\2\2\u0199\u019d\t\b\2\2\u019a") + buf.write("\u019c\t\4\2\2\u019b\u019a\3\2\2\2\u019c\u019f\3\2\2\2") + buf.write("\u019d\u019b\3\2\2\2\u019d\u019e\3\2\2\2\u019e\u01a1\3") + buf.write("\2\2\2\u019f\u019d\3\2\2\2\u01a0\u0198\3\2\2\2\u01a0\u0199") + buf.write("\3\2\2\2\u01a1y\3\2\2\2\u01a2\u01a4\t\t\2\2\u01a3\u01a5") + buf.write("\t\n\2\2\u01a4\u01a3\3\2\2\2\u01a4\u01a5\3\2\2\2\u01a5") + buf.write("\u01a6\3\2\2\2\u01a6\u01a7\5x<\2\u01a7{\3\2\2\2\u01a8") + buf.write("\u01aa\t\13\2\2\u01a9\u01a8\3\2\2\2\u01aa\u01ab\3\2\2") + buf.write("\2\u01ab\u01a9\3\2\2\2\u01ab\u01ac\3\2\2\2\u01ac\u01ad") + buf.write("\3\2\2\2\u01ad\u01ae\b>\3\2\u01ae}\3\2\2\2\u01af\u01b0") + buf.write("\7}\2\2\u01b0\u01b1\3\2\2\2\u01b1\u01b2\b?\2\2\u01b2\177") + buf.write("\3\2\2\2\u01b3\u01b4\7\177\2\2\u01b4\u01b5\3\2\2\2\u01b5") + buf.write("\u01b6\b@\4\2\u01b6\u0081\3\2\2\2\30\2\3\u0104\u010c\u0111") + buf.write("\u0117\u0142\u014c\u014e\u0157\u015e\u0165\u0167\u017f") + buf.write("\u018a\u0191\u0193\u0196\u019d\u01a0\u01a4\u01ab\5\7\3") + buf.write("\2\b\2\2\6\2\2") return buf.getvalue() @@ -214,7 +214,7 @@ class PFDLLexer(Lexer): atn = ATNDeserializer().deserialize(serializedATN()) - decisionsToDFA = [DFA(ds, i) for i, ds in enumerate(atn.decisionToState)] + decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] JSON = 1 @@ -282,191 +282,55 @@ class PFDLLexer(Lexer): JSON_OPEN_2 = 62 JSON_CLOSE = 63 - channelNames = ["DEFAULT_TOKEN_CHANNEL", "HIDDEN"] + channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] - modeNames = ["DEFAULT_MODE", "JSON"] + modeNames = [ "DEFAULT_MODE", "JSON" ] - literalNames = [ - "", - "'Struct'", - "'Task'", - "'In'", - "'Out'", - "'Loop'", - "'While'", - "'To'", - "'Parallel'", - "'Condition'", - "'Passed'", - "'Failed'", - "'OnDone'", - "'End'", - "'number'", - "'string'", - "'boolean'", - "'.'", - "'('", - "')'", - "'<'", - "'<='", - "'>'", - "'>='", - "'=='", - "'!='", - "'And'", - "'Or'", - "'!'", - "'*'", - "'/'", - "'-'", - "'+'", - "'}'", - ] + literalNames = [ "", + "'Struct'", "'Task'", "'In'", "'Out'", "'Loop'", "'While'", + "'To'", "'Parallel'", "'Condition'", "'Passed'", "'Failed'", + "'OnDone'", "'End'", "'number'", "'string'", "'boolean'", "'.'", + "'('", "')'", "'<'", "'<='", "'>'", "'>='", "'=='", "'!='", + "'And'", "'Or'", "'!'", "'*'", "'/'", "'-'", "'+'", "'}'" ] - symbolicNames = [ - "", - "INDENT", - "DEDENT", - "STRUCT", - "TASK", - "IN", - "OUT", - "LOOP", - "WHILE", - "TO", - "PARALLEL", - "CONDITION", - "PASSED", - "FAILED", - "ON_DONE", - "END", - "NUMBER_P", - "STRING_P", - "BOOLEAN_P", - "TRUE", - "FALSE", - "COLON", - "DOT", - "COMMA", - "JSON_OPEN", - "QUOTE", - "ARRAY_LEFT", - "ARRAY_RIGHT", - "COMMENT", - "WHITESPACE", - "NL", - "LEFT_PARENTHESIS", - "RIGHT_PARENTHESIS", - "LESS_THAN", - "LESS_THAN_OR_EQUAL", - "GREATER_THAN", - "GREATER_THAN_OR_EQUAL", - "EQUAL", - "NOT_EQUAL", - "BOOLEAN_AND", - "BOOLEAN_OR", - "BOOLEAN_NOT", - "STAR", - "SLASH", - "MINUS", - "PLUS", - "INTEGER", - "FLOAT", - "STRING", - "STARTS_WITH_LOWER_C_STR", - "STARTS_WITH_UPPER_C_STR", - "JSON_STRING", - "JSON_TRUE", - "JSON_FALSE", - "JSON_COLON", - "JSON_QUOTE", - "JSON_COMMENT", - "JSON_ARRAY_LEFT", - "JSON_ARRAY_RIGHT", - "JSON_COMMA", - "NUMBER", - "WS", - "JSON_OPEN_2", - "JSON_CLOSE", - ] + symbolicNames = [ "", + "INDENT", "DEDENT", "STRUCT", "TASK", "IN", "OUT", "LOOP", "WHILE", + "TO", "PARALLEL", "CONDITION", "PASSED", "FAILED", "ON_DONE", + "END", "NUMBER_P", "STRING_P", "BOOLEAN_P", "TRUE", "FALSE", + "COLON", "DOT", "COMMA", "JSON_OPEN", "QUOTE", "ARRAY_LEFT", + "ARRAY_RIGHT", "COMMENT", "WHITESPACE", "NL", "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", "LESS_THAN", "LESS_THAN_OR_EQUAL", "GREATER_THAN", + "GREATER_THAN_OR_EQUAL", "EQUAL", "NOT_EQUAL", "BOOLEAN_AND", + "BOOLEAN_OR", "BOOLEAN_NOT", "STAR", "SLASH", "MINUS", "PLUS", + "INTEGER", "FLOAT", "STRING", "STARTS_WITH_LOWER_C_STR", "STARTS_WITH_UPPER_C_STR", + "JSON_STRING", "JSON_TRUE", "JSON_FALSE", "JSON_COLON", "JSON_QUOTE", + "JSON_COMMENT", "JSON_ARRAY_LEFT", "JSON_ARRAY_RIGHT", "JSON_COMMA", + "NUMBER", "WS", "JSON_OPEN_2", "JSON_CLOSE" ] - ruleNames = [ - "STRUCT", - "TASK", - "IN", - "OUT", - "LOOP", - "WHILE", - "TO", - "PARALLEL", - "CONDITION", - "PASSED", - "FAILED", - "ON_DONE", - "END", - "NUMBER_P", - "STRING_P", - "BOOLEAN_P", - "TRUE", - "FALSE", - "COLON", - "DOT", - "COMMA", - "JSON_OPEN", - "QUOTE", - "ARRAY_LEFT", - "ARRAY_RIGHT", - "COMMENT", - "WHITESPACE", - "NL", - "LEFT_PARENTHESIS", - "RIGHT_PARENTHESIS", - "LESS_THAN", - "LESS_THAN_OR_EQUAL", - "GREATER_THAN", - "GREATER_THAN_OR_EQUAL", - "EQUAL", - "NOT_EQUAL", - "BOOLEAN_AND", - "BOOLEAN_OR", - "BOOLEAN_NOT", - "STAR", - "SLASH", - "MINUS", - "PLUS", - "INTEGER", - "FLOAT", - "STRING", - "STARTS_WITH_LOWER_C_STR", - "STARTS_WITH_UPPER_C_STR", - "JSON_STRING", - "JSON_TRUE", - "JSON_FALSE", - "JSON_COLON", - "JSON_QUOTE", - "JSON_COMMENT", - "JSON_ARRAY_LEFT", - "JSON_ARRAY_RIGHT", - "JSON_COMMA", - "NUMBER", - "INT", - "EXP", - "WS", - "JSON_OPEN_2", - "JSON_CLOSE", - ] + ruleNames = [ "STRUCT", "TASK", "IN", "OUT", "LOOP", "WHILE", "TO", + "PARALLEL", "CONDITION", "PASSED", "FAILED", "ON_DONE", + "END", "NUMBER_P", "STRING_P", "BOOLEAN_P", "TRUE", "FALSE", + "COLON", "DOT", "COMMA", "JSON_OPEN", "QUOTE", "ARRAY_LEFT", + "ARRAY_RIGHT", "COMMENT", "WHITESPACE", "NL", "LEFT_PARENTHESIS", + "RIGHT_PARENTHESIS", "LESS_THAN", "LESS_THAN_OR_EQUAL", + "GREATER_THAN", "GREATER_THAN_OR_EQUAL", "EQUAL", "NOT_EQUAL", + "BOOLEAN_AND", "BOOLEAN_OR", "BOOLEAN_NOT", "STAR", "SLASH", + "MINUS", "PLUS", "INTEGER", "FLOAT", "STRING", "STARTS_WITH_LOWER_C_STR", + "STARTS_WITH_UPPER_C_STR", "JSON_STRING", "JSON_TRUE", + "JSON_FALSE", "JSON_COLON", "JSON_QUOTE", "JSON_COMMENT", + "JSON_ARRAY_LEFT", "JSON_ARRAY_RIGHT", "JSON_COMMA", "NUMBER", + "INT", "EXP", "WS", "JSON_OPEN_2", "JSON_CLOSE" ] grammarFileName = "PFDLLexer.g4" - def __init__(self, input=None, output: TextIO = sys.stdout): + def __init__(self, input=None, output:TextIO = sys.stdout): super().__init__(input, output) - self.checkVersion("4.9.2") - self._interp = LexerATNSimulator( - self, self.atn, self.decisionsToDFA, PredictionContextCache() - ) + self.checkVersion("4.9.3") + self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) self._actions = None self._predicates = None + class PFDLDenter(DenterHelper): def __init__(self, lexer, nl_token, indent_token, dedent_token, ignore_eof): super().__init__(nl_token, indent_token, dedent_token, ignore_eof) @@ -479,7 +343,7 @@ def pull_token(self): def nextToken(self): if not self.denter: - self.denter = self.PFDLDenter( - self, self.NL, PFDLLexer.INDENT, PFDLLexer.DEDENT, ignore_eof=False - ) + self.denter = self.PFDLDenter(self, self.NL, PFDLLexer.INDENT, PFDLLexer.DEDENT, ignore_eof=False) return self.denter.next_token() + + diff --git a/pfdl_scheduler/parser/PFDLParser.py b/pfdl_scheduler/parser/PFDLParser.py index 99bdcf9..dae5f8d 100644 --- a/pfdl_scheduler/parser/PFDLParser.py +++ b/pfdl_scheduler/parser/PFDLParser.py @@ -1,4 +1,4 @@ -# Generated from PFDLParser.g4 by ANTLR 4.9.2 +# Generated from PFDLParser.g4 by ANTLR 4.9.3 # encoding: utf-8 from antlr4 import * from io import StringIO @@ -12,208 +12,214 @@ def serializedATN(): with StringIO() as buf: buf.write("\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3A") - buf.write("\u01a9\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") + buf.write("\u01b3\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7") buf.write("\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r\4\16") buf.write("\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4\23\t\23") buf.write("\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31") buf.write("\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t\35\4\36\t\36") - buf.write("\4\37\t\37\4 \t \4!\t!\3\2\3\2\3\2\7\2F\n\2\f\2\16\2I") - buf.write("\13\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\6\3R\n\3\r\3\16\3S\6") - buf.write("\3V\n\3\r\3\16\3W\3\3\3\3\3\3\3\4\3\4\3\4\3\4\5\4a\n\4") - buf.write("\3\4\6\4d\n\4\r\4\16\4e\3\4\5\4i\n\4\3\4\3\4\3\4\3\5\3") - buf.write("\5\3\5\3\5\6\5r\n\5\r\5\16\5s\6\5v\n\5\r\5\16\5w\3\5\3") - buf.write("\5\3\6\3\6\3\6\3\6\6\6\u0080\n\6\r\6\16\6\u0081\6\6\u0084") - buf.write("\n\6\r\6\16\6\u0085\3\6\3\6\3\7\3\7\3\7\3\7\3\7\3\7\5") - buf.write("\7\u0090\n\7\3\b\3\b\6\b\u0094\n\b\r\b\16\b\u0095\3\b") - buf.write("\3\b\3\b\5\b\u009b\n\b\3\b\5\b\u009e\n\b\3\b\5\b\u00a1") - buf.write("\n\b\3\t\3\t\6\t\u00a5\n\t\r\t\16\t\u00a6\3\t\3\t\3\t") - buf.write("\5\t\u00ac\n\t\3\t\5\t\u00af\n\t\3\t\5\t\u00b2\n\t\3\n") - buf.write("\3\n\3\n\3\n\6\n\u00b8\n\n\r\n\16\n\u00b9\3\n\6\n\u00bd") - buf.write("\n\n\r\n\16\n\u00be\3\n\3\n\3\13\3\13\3\13\3\13\6\13\u00c7") - buf.write("\n\13\r\13\16\13\u00c8\6\13\u00cb\n\13\r\13\16\13\u00cc") - buf.write("\3\13\3\13\3\f\3\f\3\f\6\f\u00d4\n\f\r\f\16\f\u00d5\3") - buf.write("\f\3\f\3\r\3\r\3\r\3\r\3\r\6\r\u00df\n\r\r\r\16\r\u00e0") - buf.write("\3\r\3\r\3\16\5\16\u00e6\n\16\3\16\3\16\3\16\3\16\3\16") - buf.write("\3\16\6\16\u00ee\n\16\r\16\16\16\u00ef\3\16\3\16\3\17") - buf.write("\3\17\3\17\3\17\6\17\u00f8\n\17\r\17\16\17\u00f9\3\17") - buf.write("\3\17\3\17\5\17\u00ff\n\17\3\20\3\20\3\20\6\20\u0104\n") - buf.write("\20\r\20\16\20\u0105\3\20\3\20\3\21\3\21\3\21\6\21\u010d") - buf.write("\n\21\r\21\16\21\u010e\3\21\3\21\3\22\3\22\5\22\u0115") - buf.write("\n\22\3\23\3\23\3\23\3\23\6\23\u011b\n\23\r\23\16\23\u011c") - buf.write("\3\23\3\23\3\23\3\23\7\23\u0123\n\23\f\23\16\23\u0126") - buf.write("\13\23\3\23\3\23\7\23\u012a\n\23\f\23\16\23\u012d\13\23") - buf.write("\5\23\u012f\n\23\3\24\3\24\3\24\3\24\5\24\u0135\n\24\3") - buf.write("\25\3\25\3\26\3\26\3\26\3\26\5\26\u013d\n\26\6\26\u013f") - buf.write("\n\26\r\26\16\26\u0140\3\27\3\27\5\27\u0145\n\27\3\27") - buf.write("\3\27\3\30\3\30\3\31\3\31\3\31\3\31\3\31\5\31\u0150\n") - buf.write("\31\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32\5\32") - buf.write("\u015b\n\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3") - buf.write("\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32\3\32") - buf.write("\3\32\3\32\3\32\7\32\u0173\n\32\f\32\16\32\u0176\13\32") - buf.write("\3\33\3\33\3\34\3\34\3\35\3\35\3\35\3\35\7\35\u0180\n") - buf.write("\35\f\35\16\35\u0183\13\35\3\35\3\35\3\35\3\35\3\35\5") - buf.write("\35\u018a\n\35\3\36\3\36\3\36\3\36\3\37\3\37\3 \3 \3 ") - buf.write("\3 \3 \3 \5 \u0198\n \3!\3!\3!\3!\7!\u019e\n!\f!\16!\u01a1") - buf.write("\13!\3!\3!\3!\3!\5!\u01a7\n!\3!\2\3\62\"\2\4\6\b\n\f\16") - buf.write("\20\22\24\26\30\32\34\36 \"$&(*,.\60\62\64\668:<>@\2\7") - buf.write("\4\2\22\24\64\64\4\2\60\60\63\63\3\2\60\61\3\2#(\4\2\32") - buf.write("\32@@\2\u01cd\2G\3\2\2\2\4L\3\2\2\2\6\\\3\2\2\2\bm\3\2") - buf.write("\2\2\n{\3\2\2\2\f\u008f\3\2\2\2\16\u00a0\3\2\2\2\20\u00b1") - buf.write("\3\2\2\2\22\u00b3\3\2\2\2\24\u00c2\3\2\2\2\26\u00d0\3") - buf.write("\2\2\2\30\u00d9\3\2\2\2\32\u00e5\3\2\2\2\34\u00f3\3\2") - buf.write("\2\2\36\u0100\3\2\2\2 \u0109\3\2\2\2\"\u0114\3\2\2\2$") - buf.write("\u012e\3\2\2\2&\u0130\3\2\2\2(\u0136\3\2\2\2*\u0138\3") - buf.write("\2\2\2,\u0142\3\2\2\2.\u0148\3\2\2\2\60\u014f\3\2\2\2") - buf.write("\62\u015a\3\2\2\2\64\u0177\3\2\2\2\66\u0179\3\2\2\28\u0189") - buf.write("\3\2\2\2:\u018b\3\2\2\2<\u018f\3\2\2\2>\u0197\3\2\2\2") - buf.write("@\u01a6\3\2\2\2BF\7 \2\2CF\5\4\3\2DF\5\6\4\2EB\3\2\2\2") - buf.write("EC\3\2\2\2ED\3\2\2\2FI\3\2\2\2GE\3\2\2\2GH\3\2\2\2HJ\3") - buf.write("\2\2\2IG\3\2\2\2JK\7\2\2\3K\3\3\2\2\2LM\7\5\2\2MN\7\64") - buf.write("\2\2NU\7\3\2\2OQ\5&\24\2PR\7 \2\2QP\3\2\2\2RS\3\2\2\2") - buf.write("SQ\3\2\2\2ST\3\2\2\2TV\3\2\2\2UO\3\2\2\2VW\3\2\2\2WU\3") - buf.write("\2\2\2WX\3\2\2\2XY\3\2\2\2YZ\7\4\2\2Z[\7\21\2\2[\5\3\2") - buf.write("\2\2\\]\7\6\2\2]^\7\63\2\2^`\7\3\2\2_a\5\b\5\2`_\3\2\2") - buf.write("\2`a\3\2\2\2ac\3\2\2\2bd\5\f\7\2cb\3\2\2\2de\3\2\2\2e") - buf.write("c\3\2\2\2ef\3\2\2\2fh\3\2\2\2gi\5\n\6\2hg\3\2\2\2hi\3") - buf.write("\2\2\2ij\3\2\2\2jk\7\4\2\2kl\7\21\2\2l\7\3\2\2\2mn\7\7") - buf.write("\2\2nu\7\3\2\2oq\5&\24\2pr\7 \2\2qp\3\2\2\2rs\3\2\2\2") - buf.write("sq\3\2\2\2st\3\2\2\2tv\3\2\2\2uo\3\2\2\2vw\3\2\2\2wu\3") - buf.write("\2\2\2wx\3\2\2\2xy\3\2\2\2yz\7\4\2\2z\t\3\2\2\2{|\7\b") - buf.write("\2\2|\u0083\7\3\2\2}\177\7\63\2\2~\u0080\7 \2\2\177~\3") - buf.write("\2\2\2\u0080\u0081\3\2\2\2\u0081\177\3\2\2\2\u0081\u0082") - buf.write("\3\2\2\2\u0082\u0084\3\2\2\2\u0083}\3\2\2\2\u0084\u0085") - buf.write("\3\2\2\2\u0085\u0083\3\2\2\2\u0085\u0086\3\2\2\2\u0086") - buf.write("\u0087\3\2\2\2\u0087\u0088\7\4\2\2\u0088\13\3\2\2\2\u0089") - buf.write("\u0090\5\16\b\2\u008a\u0090\5\20\t\2\u008b\u0090\5\26") - buf.write("\f\2\u008c\u0090\5\30\r\2\u008d\u0090\5\32\16\2\u008e") - buf.write("\u0090\5\34\17\2\u008f\u0089\3\2\2\2\u008f\u008a\3\2\2") - buf.write("\2\u008f\u008b\3\2\2\2\u008f\u008c\3\2\2\2\u008f\u008d") - buf.write("\3\2\2\2\u008f\u008e\3\2\2\2\u0090\r\3\2\2\2\u0091\u0093") - buf.write("\7\64\2\2\u0092\u0094\7 \2\2\u0093\u0092\3\2\2\2\u0094") - buf.write("\u0095\3\2\2\2\u0095\u0093\3\2\2\2\u0095\u0096\3\2\2\2") - buf.write("\u0096\u00a1\3\2\2\2\u0097\u0098\7\64\2\2\u0098\u009a") - buf.write("\7\3\2\2\u0099\u009b\5\22\n\2\u009a\u0099\3\2\2\2\u009a") - buf.write("\u009b\3\2\2\2\u009b\u009d\3\2\2\2\u009c\u009e\5\24\13") - buf.write("\2\u009d\u009c\3\2\2\2\u009d\u009e\3\2\2\2\u009e\u009f") - buf.write("\3\2\2\2\u009f\u00a1\7\4\2\2\u00a0\u0091\3\2\2\2\u00a0") - buf.write("\u0097\3\2\2\2\u00a1\17\3\2\2\2\u00a2\u00a4\7\63\2\2\u00a3") - buf.write("\u00a5\7 \2\2\u00a4\u00a3\3\2\2\2\u00a5\u00a6\3\2\2\2") - buf.write("\u00a6\u00a4\3\2\2\2\u00a6\u00a7\3\2\2\2\u00a7\u00b2\3") - buf.write("\2\2\2\u00a8\u00a9\7\63\2\2\u00a9\u00ab\7\3\2\2\u00aa") - buf.write("\u00ac\5\22\n\2\u00ab\u00aa\3\2\2\2\u00ab\u00ac\3\2\2") - buf.write("\2\u00ac\u00ae\3\2\2\2\u00ad\u00af\5\24\13\2\u00ae\u00ad") - buf.write("\3\2\2\2\u00ae\u00af\3\2\2\2\u00af\u00b0\3\2\2\2\u00b0") - buf.write("\u00b2\7\4\2\2\u00b1\u00a2\3\2\2\2\u00b1\u00a8\3\2\2\2") - buf.write("\u00b2\21\3\2\2\2\u00b3\u00b4\7\7\2\2\u00b4\u00bc\7\3") - buf.write("\2\2\u00b5\u00b7\5\"\22\2\u00b6\u00b8\7 \2\2\u00b7\u00b6") - buf.write("\3\2\2\2\u00b8\u00b9\3\2\2\2\u00b9\u00b7\3\2\2\2\u00b9") - buf.write("\u00ba\3\2\2\2\u00ba\u00bd\3\2\2\2\u00bb\u00bd\5$\23\2") - buf.write("\u00bc\u00b5\3\2\2\2\u00bc\u00bb\3\2\2\2\u00bd\u00be\3") - buf.write("\2\2\2\u00be\u00bc\3\2\2\2\u00be\u00bf\3\2\2\2\u00bf\u00c0") - buf.write("\3\2\2\2\u00c0\u00c1\7\4\2\2\u00c1\23\3\2\2\2\u00c2\u00c3") - buf.write("\7\b\2\2\u00c3\u00ca\7\3\2\2\u00c4\u00c6\5&\24\2\u00c5") - buf.write("\u00c7\7 \2\2\u00c6\u00c5\3\2\2\2\u00c7\u00c8\3\2\2\2") - buf.write("\u00c8\u00c6\3\2\2\2\u00c8\u00c9\3\2\2\2\u00c9\u00cb\3") - buf.write("\2\2\2\u00ca\u00c4\3\2\2\2\u00cb\u00cc\3\2\2\2\u00cc\u00ca") - buf.write("\3\2\2\2\u00cc\u00cd\3\2\2\2\u00cd\u00ce\3\2\2\2\u00ce") - buf.write("\u00cf\7\4\2\2\u00cf\25\3\2\2\2\u00d0\u00d1\7\f\2\2\u00d1") - buf.write("\u00d3\7\3\2\2\u00d2\u00d4\5\20\t\2\u00d3\u00d2\3\2\2") - buf.write("\2\u00d4\u00d5\3\2\2\2\u00d5\u00d3\3\2\2\2\u00d5\u00d6") - buf.write("\3\2\2\2\u00d6\u00d7\3\2\2\2\u00d7\u00d8\7\4\2\2\u00d8") - buf.write("\27\3\2\2\2\u00d9\u00da\7\t\2\2\u00da\u00db\7\n\2\2\u00db") - buf.write("\u00dc\5\62\32\2\u00dc\u00de\7\3\2\2\u00dd\u00df\5\f\7") - buf.write("\2\u00de\u00dd\3\2\2\2\u00df\u00e0\3\2\2\2\u00e0\u00de") - buf.write("\3\2\2\2\u00e0\u00e1\3\2\2\2\u00e1\u00e2\3\2\2\2\u00e2") - buf.write("\u00e3\7\4\2\2\u00e3\31\3\2\2\2\u00e4\u00e6\7\f\2\2\u00e5") - buf.write("\u00e4\3\2\2\2\u00e5\u00e6\3\2\2\2\u00e6\u00e7\3\2\2\2") - buf.write("\u00e7\u00e8\7\t\2\2\u00e8\u00e9\7\63\2\2\u00e9\u00ea") - buf.write("\7\13\2\2\u00ea\u00eb\5*\26\2\u00eb\u00ed\7\3\2\2\u00ec") - buf.write("\u00ee\5\f\7\2\u00ed\u00ec\3\2\2\2\u00ee\u00ef\3\2\2\2") - buf.write("\u00ef\u00ed\3\2\2\2\u00ef\u00f0\3\2\2\2\u00f0\u00f1\3") - buf.write("\2\2\2\u00f1\u00f2\7\4\2\2\u00f2\33\3\2\2\2\u00f3\u00f4") - buf.write("\7\r\2\2\u00f4\u00f5\7\3\2\2\u00f5\u00f7\5\62\32\2\u00f6") - buf.write("\u00f8\7 \2\2\u00f7\u00f6\3\2\2\2\u00f8\u00f9\3\2\2\2") - buf.write("\u00f9\u00f7\3\2\2\2\u00f9\u00fa\3\2\2\2\u00fa\u00fb\3") - buf.write("\2\2\2\u00fb\u00fc\7\4\2\2\u00fc\u00fe\5\36\20\2\u00fd") - buf.write("\u00ff\5 \21\2\u00fe\u00fd\3\2\2\2\u00fe\u00ff\3\2\2\2") - buf.write("\u00ff\35\3\2\2\2\u0100\u0101\7\16\2\2\u0101\u0103\7\3") - buf.write("\2\2\u0102\u0104\5\f\7\2\u0103\u0102\3\2\2\2\u0104\u0105") - buf.write("\3\2\2\2\u0105\u0103\3\2\2\2\u0105\u0106\3\2\2\2\u0106") - buf.write("\u0107\3\2\2\2\u0107\u0108\7\4\2\2\u0108\37\3\2\2\2\u0109") - buf.write("\u010a\7\17\2\2\u010a\u010c\7\3\2\2\u010b\u010d\5\f\7") - buf.write("\2\u010c\u010b\3\2\2\2\u010d\u010e\3\2\2\2\u010e\u010c") - buf.write("\3\2\2\2\u010e\u010f\3\2\2\2\u010f\u0110\3\2\2\2\u0110") - buf.write("\u0111\7\4\2\2\u0111!\3\2\2\2\u0112\u0115\7\63\2\2\u0113") - buf.write("\u0115\5*\26\2\u0114\u0112\3\2\2\2\u0114\u0113\3\2\2\2") - buf.write("\u0115#\3\2\2\2\u0116\u0117\7\64\2\2\u0117\u0118\7\3\2") - buf.write("\2\u0118\u011a\58\35\2\u0119\u011b\7 \2\2\u011a\u0119") - buf.write("\3\2\2\2\u011b\u011c\3\2\2\2\u011c\u011a\3\2\2\2\u011c") - buf.write("\u011d\3\2\2\2\u011d\u011e\3\2\2\2\u011e\u011f\7\4\2\2") - buf.write("\u011f\u012f\3\2\2\2\u0120\u0124\7\64\2\2\u0121\u0123") - buf.write("\7 \2\2\u0122\u0121\3\2\2\2\u0123\u0126\3\2\2\2\u0124") - buf.write("\u0122\3\2\2\2\u0124\u0125\3\2\2\2\u0125\u0127\3\2\2\2") - buf.write("\u0126\u0124\3\2\2\2\u0127\u012b\58\35\2\u0128\u012a\7") - buf.write(" \2\2\u0129\u0128\3\2\2\2\u012a\u012d\3\2\2\2\u012b\u0129") - buf.write("\3\2\2\2\u012b\u012c\3\2\2\2\u012c\u012f\3\2\2\2\u012d") - buf.write("\u012b\3\2\2\2\u012e\u0116\3\2\2\2\u012e\u0120\3\2\2\2") - buf.write("\u012f%\3\2\2\2\u0130\u0131\7\63\2\2\u0131\u0132\7\27") - buf.write("\2\2\u0132\u0134\5(\25\2\u0133\u0135\5,\27\2\u0134\u0133") - buf.write("\3\2\2\2\u0134\u0135\3\2\2\2\u0135\'\3\2\2\2\u0136\u0137") - buf.write("\t\2\2\2\u0137)\3\2\2\2\u0138\u013e\7\63\2\2\u0139\u013a") - buf.write("\7\30\2\2\u013a\u013c\7\63\2\2\u013b\u013d\5,\27\2\u013c") - buf.write("\u013b\3\2\2\2\u013c\u013d\3\2\2\2\u013d\u013f\3\2\2\2") - buf.write("\u013e\u0139\3\2\2\2\u013f\u0140\3\2\2\2\u0140\u013e\3") - buf.write("\2\2\2\u0140\u0141\3\2\2\2\u0141+\3\2\2\2\u0142\u0144") - buf.write("\7\34\2\2\u0143\u0145\t\3\2\2\u0144\u0143\3\2\2\2\u0144") - buf.write("\u0145\3\2\2\2\u0145\u0146\3\2\2\2\u0146\u0147\7\35\2") - buf.write("\2\u0147-\3\2\2\2\u0148\u0149\t\4\2\2\u0149/\3\2\2\2\u014a") - buf.write("\u0150\7\25\2\2\u014b\u0150\7\26\2\2\u014c\u0150\5.\30") - buf.write("\2\u014d\u0150\7\62\2\2\u014e\u0150\5*\26\2\u014f\u014a") - buf.write("\3\2\2\2\u014f\u014b\3\2\2\2\u014f\u014c\3\2\2\2\u014f") - buf.write("\u014d\3\2\2\2\u014f\u014e\3\2\2\2\u0150\61\3\2\2\2\u0151") - buf.write("\u0152\b\32\1\2\u0152\u0153\7!\2\2\u0153\u0154\5\62\32") - buf.write("\2\u0154\u0155\7\"\2\2\u0155\u015b\3\2\2\2\u0156\u0157") - buf.write("\5\66\34\2\u0157\u0158\5\62\32\6\u0158\u015b\3\2\2\2\u0159") - buf.write("\u015b\5\60\31\2\u015a\u0151\3\2\2\2\u015a\u0156\3\2\2") - buf.write("\2\u015a\u0159\3\2\2\2\u015b\u0174\3\2\2\2\u015c\u015d") - buf.write("\f\13\2\2\u015d\u015e\7,\2\2\u015e\u0173\5\62\32\f\u015f") - buf.write("\u0160\f\n\2\2\u0160\u0161\7-\2\2\u0161\u0173\5\62\32") - buf.write("\13\u0162\u0163\f\t\2\2\u0163\u0164\7.\2\2\u0164\u0173") - buf.write("\5\62\32\n\u0165\u0166\f\b\2\2\u0166\u0167\7/\2\2\u0167") - buf.write("\u0173\5\62\32\t\u0168\u0169\f\7\2\2\u0169\u016a\5\64") - buf.write("\33\2\u016a\u016b\5\62\32\b\u016b\u0173\3\2\2\2\u016c") - buf.write("\u016d\f\5\2\2\u016d\u016e\7)\2\2\u016e\u0173\5\62\32") - buf.write("\6\u016f\u0170\f\4\2\2\u0170\u0171\7*\2\2\u0171\u0173") - buf.write("\5\62\32\5\u0172\u015c\3\2\2\2\u0172\u015f\3\2\2\2\u0172") - buf.write("\u0162\3\2\2\2\u0172\u0165\3\2\2\2\u0172\u0168\3\2\2\2") - buf.write("\u0172\u016c\3\2\2\2\u0172\u016f\3\2\2\2\u0173\u0176\3") - buf.write("\2\2\2\u0174\u0172\3\2\2\2\u0174\u0175\3\2\2\2\u0175\63") - buf.write("\3\2\2\2\u0176\u0174\3\2\2\2\u0177\u0178\t\5\2\2\u0178") - buf.write("\65\3\2\2\2\u0179\u017a\7+\2\2\u017a\67\3\2\2\2\u017b") - buf.write("\u017c\5<\37\2\u017c\u0181\5:\36\2\u017d\u017e\7=\2\2") - buf.write("\u017e\u0180\5:\36\2\u017f\u017d\3\2\2\2\u0180\u0183\3") - buf.write("\2\2\2\u0181\u017f\3\2\2\2\u0181\u0182\3\2\2\2\u0182\u0184") - buf.write("\3\2\2\2\u0183\u0181\3\2\2\2\u0184\u0185\7A\2\2\u0185") - buf.write("\u018a\3\2\2\2\u0186\u0187\5<\37\2\u0187\u0188\7A\2\2") - buf.write("\u0188\u018a\3\2\2\2\u0189\u017b\3\2\2\2\u0189\u0186\3") - buf.write("\2\2\2\u018a9\3\2\2\2\u018b\u018c\7\65\2\2\u018c\u018d") - buf.write("\78\2\2\u018d\u018e\5> \2\u018e;\3\2\2\2\u018f\u0190\t") - buf.write("\6\2\2\u0190=\3\2\2\2\u0191\u0198\7\65\2\2\u0192\u0198") - buf.write("\7\66\2\2\u0193\u0198\7\67\2\2\u0194\u0198\7>\2\2\u0195") - buf.write("\u0198\58\35\2\u0196\u0198\5@!\2\u0197\u0191\3\2\2\2\u0197") - buf.write("\u0192\3\2\2\2\u0197\u0193\3\2\2\2\u0197\u0194\3\2\2\2") - buf.write("\u0197\u0195\3\2\2\2\u0197\u0196\3\2\2\2\u0198?\3\2\2") - buf.write("\2\u0199\u019a\7;\2\2\u019a\u019f\5> \2\u019b\u019c\7") - buf.write("=\2\2\u019c\u019e\5> \2\u019d\u019b\3\2\2\2\u019e\u01a1") - buf.write("\3\2\2\2\u019f\u019d\3\2\2\2\u019f\u01a0\3\2\2\2\u01a0") - buf.write("\u01a2\3\2\2\2\u01a1\u019f\3\2\2\2\u01a2\u01a3\7<\2\2") - buf.write("\u01a3\u01a7\3\2\2\2\u01a4\u01a5\7;\2\2\u01a5\u01a7\7") - buf.write("<\2\2\u01a6\u0199\3\2\2\2\u01a6\u01a4\3\2\2\2\u01a7A\3") - buf.write("\2\2\2\65EGSW`ehsw\u0081\u0085\u008f\u0095\u009a\u009d") - buf.write("\u00a0\u00a6\u00ab\u00ae\u00b1\u00b9\u00bc\u00be\u00c8") - buf.write("\u00cc\u00d5\u00e0\u00e5\u00ef\u00f9\u00fe\u0105\u010e") - buf.write("\u0114\u011c\u0124\u012b\u012e\u0134\u013c\u0140\u0144") - buf.write("\u014f\u015a\u0172\u0174\u0181\u0189\u0197\u019f\u01a6") + buf.write("\4\37\t\37\4 \t \4!\t!\4\"\t\"\3\2\3\2\3\2\7\2H\n\2\f") + buf.write("\2\16\2K\13\2\3\2\3\2\3\3\3\3\3\3\3\3\3\3\6\3T\n\3\r\3") + buf.write("\16\3U\6\3X\n\3\r\3\16\3Y\3\3\3\3\3\3\3\4\3\4\3\4\3\4") + buf.write("\5\4c\n\4\3\4\6\4f\n\4\r\4\16\4g\3\4\5\4k\n\4\3\4\3\4") + buf.write("\3\4\3\5\3\5\3\5\3\5\6\5t\n\5\r\5\16\5u\6\5x\n\5\r\5\16") + buf.write("\5y\3\5\3\5\3\6\3\6\3\6\3\6\6\6\u0082\n\6\r\6\16\6\u0083") + buf.write("\6\6\u0086\n\6\r\6\16\6\u0087\3\6\3\6\3\7\3\7\3\7\3\7") + buf.write("\3\7\3\7\5\7\u0092\n\7\3\b\3\b\6\b\u0096\n\b\r\b\16\b") + buf.write("\u0097\3\b\3\b\3\b\5\b\u009d\n\b\3\b\5\b\u00a0\n\b\3\b") + buf.write("\5\b\u00a3\n\b\3\t\3\t\6\t\u00a7\n\t\r\t\16\t\u00a8\3") + buf.write("\t\3\t\3\t\5\t\u00ae\n\t\3\t\5\t\u00b1\n\t\3\t\5\t\u00b4") + buf.write("\n\t\3\n\3\n\3\n\3\n\6\n\u00ba\n\n\r\n\16\n\u00bb\3\n") + buf.write("\6\n\u00bf\n\n\r\n\16\n\u00c0\3\n\3\n\3\13\3\13\3\13\3") + buf.write("\13\6\13\u00c9\n\13\r\13\16\13\u00ca\6\13\u00cd\n\13\r") + buf.write("\13\16\13\u00ce\3\13\3\13\3\f\3\f\3\f\6\f\u00d6\n\f\r") + buf.write("\f\16\f\u00d7\3\f\3\f\3\r\3\r\3\r\3\r\3\r\6\r\u00e1\n") + buf.write("\r\r\r\16\r\u00e2\3\r\3\r\3\16\5\16\u00e8\n\16\3\16\3") + buf.write("\16\3\16\3\16\3\16\5\16\u00ef\n\16\3\16\3\16\6\16\u00f3") + buf.write("\n\16\r\16\16\16\u00f4\3\16\3\16\3\17\3\17\3\17\3\17\6") + buf.write("\17\u00fd\n\17\r\17\16\17\u00fe\3\17\3\17\3\17\5\17\u0104") + buf.write("\n\17\3\20\3\20\3\20\6\20\u0109\n\20\r\20\16\20\u010a") + buf.write("\3\20\3\20\3\21\3\21\3\21\6\21\u0112\n\21\r\21\16\21\u0113") + buf.write("\3\21\3\21\3\22\3\22\5\22\u011a\n\22\3\23\3\23\3\23\3") + buf.write("\23\6\23\u0120\n\23\r\23\16\23\u0121\3\23\3\23\3\23\3") + buf.write("\23\7\23\u0128\n\23\f\23\16\23\u012b\13\23\3\23\3\23\7") + buf.write("\23\u012f\n\23\f\23\16\23\u0132\13\23\5\23\u0134\n\23") + buf.write("\3\24\3\24\3\24\3\24\3\25\3\25\5\25\u013c\n\25\3\26\3") + buf.write("\26\3\27\3\27\3\27\3\27\5\27\u0144\n\27\6\27\u0146\n\27") + buf.write("\r\27\16\27\u0147\3\30\3\30\5\30\u014c\n\30\3\30\3\30") + buf.write("\3\31\5\31\u0151\n\31\3\31\3\31\3\32\3\32\3\32\3\32\3") + buf.write("\32\5\32\u015a\n\32\3\33\3\33\3\33\3\33\3\33\3\33\3\33") + buf.write("\3\33\3\33\5\33\u0165\n\33\3\33\3\33\3\33\3\33\3\33\3") + buf.write("\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33") + buf.write("\3\33\3\33\3\33\3\33\3\33\3\33\7\33\u017d\n\33\f\33\16") + buf.write("\33\u0180\13\33\3\34\3\34\3\35\3\35\3\36\3\36\3\36\3\36") + buf.write("\7\36\u018a\n\36\f\36\16\36\u018d\13\36\3\36\3\36\3\36") + buf.write("\3\36\3\36\5\36\u0194\n\36\3\37\3\37\3\37\3\37\3 \3 \3") + buf.write("!\3!\3!\3!\3!\3!\5!\u01a2\n!\3\"\3\"\3\"\3\"\7\"\u01a8") + buf.write("\n\"\f\"\16\"\u01ab\13\"\3\"\3\"\3\"\3\"\5\"\u01b1\n\"") + buf.write("\3\"\2\3\64#\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"") + buf.write("$&(*,.\60\62\64\668:<>@B\2\7\4\2\22\24\64\64\4\2\60\60") + buf.write("\63\63\3\2\60\61\3\2#(\4\2\32\32@@\2\u01d8\2I\3\2\2\2") + buf.write("\4N\3\2\2\2\6^\3\2\2\2\bo\3\2\2\2\n}\3\2\2\2\f\u0091\3") + buf.write("\2\2\2\16\u00a2\3\2\2\2\20\u00b3\3\2\2\2\22\u00b5\3\2") + buf.write("\2\2\24\u00c4\3\2\2\2\26\u00d2\3\2\2\2\30\u00db\3\2\2") + buf.write("\2\32\u00e7\3\2\2\2\34\u00f8\3\2\2\2\36\u0105\3\2\2\2") + buf.write(" \u010e\3\2\2\2\"\u0119\3\2\2\2$\u0133\3\2\2\2&\u0135") + buf.write("\3\2\2\2(\u0139\3\2\2\2*\u013d\3\2\2\2,\u013f\3\2\2\2") + buf.write(".\u0149\3\2\2\2\60\u0150\3\2\2\2\62\u0159\3\2\2\2\64\u0164") + buf.write("\3\2\2\2\66\u0181\3\2\2\28\u0183\3\2\2\2:\u0193\3\2\2") + buf.write("\2<\u0195\3\2\2\2>\u0199\3\2\2\2@\u01a1\3\2\2\2B\u01b0") + buf.write("\3\2\2\2DH\7 \2\2EH\5\4\3\2FH\5\6\4\2GD\3\2\2\2GE\3\2") + buf.write("\2\2GF\3\2\2\2HK\3\2\2\2IG\3\2\2\2IJ\3\2\2\2JL\3\2\2\2") + buf.write("KI\3\2\2\2LM\7\2\2\3M\3\3\2\2\2NO\7\5\2\2OP\7\64\2\2P") + buf.write("W\7\3\2\2QS\5&\24\2RT\7 \2\2SR\3\2\2\2TU\3\2\2\2US\3\2") + buf.write("\2\2UV\3\2\2\2VX\3\2\2\2WQ\3\2\2\2XY\3\2\2\2YW\3\2\2\2") + buf.write("YZ\3\2\2\2Z[\3\2\2\2[\\\7\4\2\2\\]\7\21\2\2]\5\3\2\2\2") + buf.write("^_\7\6\2\2_`\7\63\2\2`b\7\3\2\2ac\5\b\5\2ba\3\2\2\2bc") + buf.write("\3\2\2\2ce\3\2\2\2df\5\f\7\2ed\3\2\2\2fg\3\2\2\2ge\3\2") + buf.write("\2\2gh\3\2\2\2hj\3\2\2\2ik\5\n\6\2ji\3\2\2\2jk\3\2\2\2") + buf.write("kl\3\2\2\2lm\7\4\2\2mn\7\21\2\2n\7\3\2\2\2op\7\7\2\2p") + buf.write("w\7\3\2\2qs\5&\24\2rt\7 \2\2sr\3\2\2\2tu\3\2\2\2us\3\2") + buf.write("\2\2uv\3\2\2\2vx\3\2\2\2wq\3\2\2\2xy\3\2\2\2yw\3\2\2\2") + buf.write("yz\3\2\2\2z{\3\2\2\2{|\7\4\2\2|\t\3\2\2\2}~\7\b\2\2~\u0085") + buf.write("\7\3\2\2\177\u0081\7\63\2\2\u0080\u0082\7 \2\2\u0081\u0080") + buf.write("\3\2\2\2\u0082\u0083\3\2\2\2\u0083\u0081\3\2\2\2\u0083") + buf.write("\u0084\3\2\2\2\u0084\u0086\3\2\2\2\u0085\177\3\2\2\2\u0086") + buf.write("\u0087\3\2\2\2\u0087\u0085\3\2\2\2\u0087\u0088\3\2\2\2") + buf.write("\u0088\u0089\3\2\2\2\u0089\u008a\7\4\2\2\u008a\13\3\2") + buf.write("\2\2\u008b\u0092\5\16\b\2\u008c\u0092\5\20\t\2\u008d\u0092") + buf.write("\5\26\f\2\u008e\u0092\5\30\r\2\u008f\u0092\5\32\16\2\u0090") + buf.write("\u0092\5\34\17\2\u0091\u008b\3\2\2\2\u0091\u008c\3\2\2") + buf.write("\2\u0091\u008d\3\2\2\2\u0091\u008e\3\2\2\2\u0091\u008f") + buf.write("\3\2\2\2\u0091\u0090\3\2\2\2\u0092\r\3\2\2\2\u0093\u0095") + buf.write("\7\64\2\2\u0094\u0096\7 \2\2\u0095\u0094\3\2\2\2\u0096") + buf.write("\u0097\3\2\2\2\u0097\u0095\3\2\2\2\u0097\u0098\3\2\2\2") + buf.write("\u0098\u00a3\3\2\2\2\u0099\u009a\7\64\2\2\u009a\u009c") + buf.write("\7\3\2\2\u009b\u009d\5\22\n\2\u009c\u009b\3\2\2\2\u009c") + buf.write("\u009d\3\2\2\2\u009d\u009f\3\2\2\2\u009e\u00a0\5\24\13") + buf.write("\2\u009f\u009e\3\2\2\2\u009f\u00a0\3\2\2\2\u00a0\u00a1") + buf.write("\3\2\2\2\u00a1\u00a3\7\4\2\2\u00a2\u0093\3\2\2\2\u00a2") + buf.write("\u0099\3\2\2\2\u00a3\17\3\2\2\2\u00a4\u00a6\7\63\2\2\u00a5") + buf.write("\u00a7\7 \2\2\u00a6\u00a5\3\2\2\2\u00a7\u00a8\3\2\2\2") + buf.write("\u00a8\u00a6\3\2\2\2\u00a8\u00a9\3\2\2\2\u00a9\u00b4\3") + buf.write("\2\2\2\u00aa\u00ab\7\63\2\2\u00ab\u00ad\7\3\2\2\u00ac") + buf.write("\u00ae\5\22\n\2\u00ad\u00ac\3\2\2\2\u00ad\u00ae\3\2\2") + buf.write("\2\u00ae\u00b0\3\2\2\2\u00af\u00b1\5\24\13\2\u00b0\u00af") + buf.write("\3\2\2\2\u00b0\u00b1\3\2\2\2\u00b1\u00b2\3\2\2\2\u00b2") + buf.write("\u00b4\7\4\2\2\u00b3\u00a4\3\2\2\2\u00b3\u00aa\3\2\2\2") + buf.write("\u00b4\21\3\2\2\2\u00b5\u00b6\7\7\2\2\u00b6\u00be\7\3") + buf.write("\2\2\u00b7\u00b9\5\"\22\2\u00b8\u00ba\7 \2\2\u00b9\u00b8") + buf.write("\3\2\2\2\u00ba\u00bb\3\2\2\2\u00bb\u00b9\3\2\2\2\u00bb") + buf.write("\u00bc\3\2\2\2\u00bc\u00bf\3\2\2\2\u00bd\u00bf\5$\23\2") + buf.write("\u00be\u00b7\3\2\2\2\u00be\u00bd\3\2\2\2\u00bf\u00c0\3") + buf.write("\2\2\2\u00c0\u00be\3\2\2\2\u00c0\u00c1\3\2\2\2\u00c1\u00c2") + buf.write("\3\2\2\2\u00c2\u00c3\7\4\2\2\u00c3\23\3\2\2\2\u00c4\u00c5") + buf.write("\7\b\2\2\u00c5\u00cc\7\3\2\2\u00c6\u00c8\5&\24\2\u00c7") + buf.write("\u00c9\7 \2\2\u00c8\u00c7\3\2\2\2\u00c9\u00ca\3\2\2\2") + buf.write("\u00ca\u00c8\3\2\2\2\u00ca\u00cb\3\2\2\2\u00cb\u00cd\3") + buf.write("\2\2\2\u00cc\u00c6\3\2\2\2\u00cd\u00ce\3\2\2\2\u00ce\u00cc") + buf.write("\3\2\2\2\u00ce\u00cf\3\2\2\2\u00cf\u00d0\3\2\2\2\u00d0") + buf.write("\u00d1\7\4\2\2\u00d1\25\3\2\2\2\u00d2\u00d3\7\f\2\2\u00d3") + buf.write("\u00d5\7\3\2\2\u00d4\u00d6\5\20\t\2\u00d5\u00d4\3\2\2") + buf.write("\2\u00d6\u00d7\3\2\2\2\u00d7\u00d5\3\2\2\2\u00d7\u00d8") + buf.write("\3\2\2\2\u00d8\u00d9\3\2\2\2\u00d9\u00da\7\4\2\2\u00da") + buf.write("\27\3\2\2\2\u00db\u00dc\7\t\2\2\u00dc\u00dd\7\n\2\2\u00dd") + buf.write("\u00de\5\64\33\2\u00de\u00e0\7\3\2\2\u00df\u00e1\5\f\7") + buf.write("\2\u00e0\u00df\3\2\2\2\u00e1\u00e2\3\2\2\2\u00e2\u00e0") + buf.write("\3\2\2\2\u00e2\u00e3\3\2\2\2\u00e3\u00e4\3\2\2\2\u00e4") + buf.write("\u00e5\7\4\2\2\u00e5\31\3\2\2\2\u00e6\u00e8\7\f\2\2\u00e7") + buf.write("\u00e6\3\2\2\2\u00e7\u00e8\3\2\2\2\u00e8\u00e9\3\2\2\2") + buf.write("\u00e9\u00ea\7\t\2\2\u00ea\u00eb\7\63\2\2\u00eb\u00ee") + buf.write("\7\13\2\2\u00ec\u00ef\5,\27\2\u00ed\u00ef\7\60\2\2\u00ee") + buf.write("\u00ec\3\2\2\2\u00ee\u00ed\3\2\2\2\u00ef\u00f0\3\2\2\2") + buf.write("\u00f0\u00f2\7\3\2\2\u00f1\u00f3\5\f\7\2\u00f2\u00f1\3") + buf.write("\2\2\2\u00f3\u00f4\3\2\2\2\u00f4\u00f2\3\2\2\2\u00f4\u00f5") + buf.write("\3\2\2\2\u00f5\u00f6\3\2\2\2\u00f6\u00f7\7\4\2\2\u00f7") + buf.write("\33\3\2\2\2\u00f8\u00f9\7\r\2\2\u00f9\u00fa\7\3\2\2\u00fa") + buf.write("\u00fc\5\64\33\2\u00fb\u00fd\7 \2\2\u00fc\u00fb\3\2\2") + buf.write("\2\u00fd\u00fe\3\2\2\2\u00fe\u00fc\3\2\2\2\u00fe\u00ff") + buf.write("\3\2\2\2\u00ff\u0100\3\2\2\2\u0100\u0101\7\4\2\2\u0101") + buf.write("\u0103\5\36\20\2\u0102\u0104\5 \21\2\u0103\u0102\3\2\2") + buf.write("\2\u0103\u0104\3\2\2\2\u0104\35\3\2\2\2\u0105\u0106\7") + buf.write("\16\2\2\u0106\u0108\7\3\2\2\u0107\u0109\5\f\7\2\u0108") + buf.write("\u0107\3\2\2\2\u0109\u010a\3\2\2\2\u010a\u0108\3\2\2\2") + buf.write("\u010a\u010b\3\2\2\2\u010b\u010c\3\2\2\2\u010c\u010d\7") + buf.write("\4\2\2\u010d\37\3\2\2\2\u010e\u010f\7\17\2\2\u010f\u0111") + buf.write("\7\3\2\2\u0110\u0112\5\f\7\2\u0111\u0110\3\2\2\2\u0112") + buf.write("\u0113\3\2\2\2\u0113\u0111\3\2\2\2\u0113\u0114\3\2\2\2") + buf.write("\u0114\u0115\3\2\2\2\u0115\u0116\7\4\2\2\u0116!\3\2\2") + buf.write("\2\u0117\u011a\7\63\2\2\u0118\u011a\5,\27\2\u0119\u0117") + buf.write("\3\2\2\2\u0119\u0118\3\2\2\2\u011a#\3\2\2\2\u011b\u011c") + buf.write("\7\64\2\2\u011c\u011d\7\3\2\2\u011d\u011f\5:\36\2\u011e") + buf.write("\u0120\7 \2\2\u011f\u011e\3\2\2\2\u0120\u0121\3\2\2\2") + buf.write("\u0121\u011f\3\2\2\2\u0121\u0122\3\2\2\2\u0122\u0123\3") + buf.write("\2\2\2\u0123\u0124\7\4\2\2\u0124\u0134\3\2\2\2\u0125\u0129") + buf.write("\7\64\2\2\u0126\u0128\7 \2\2\u0127\u0126\3\2\2\2\u0128") + buf.write("\u012b\3\2\2\2\u0129\u0127\3\2\2\2\u0129\u012a\3\2\2\2") + buf.write("\u012a\u012c\3\2\2\2\u012b\u0129\3\2\2\2\u012c\u0130\5") + buf.write(":\36\2\u012d\u012f\7 \2\2\u012e\u012d\3\2\2\2\u012f\u0132") + buf.write("\3\2\2\2\u0130\u012e\3\2\2\2\u0130\u0131\3\2\2\2\u0131") + buf.write("\u0134\3\2\2\2\u0132\u0130\3\2\2\2\u0133\u011b\3\2\2\2") + buf.write("\u0133\u0125\3\2\2\2\u0134%\3\2\2\2\u0135\u0136\7\63\2") + buf.write("\2\u0136\u0137\7\27\2\2\u0137\u0138\5(\25\2\u0138\'\3") + buf.write("\2\2\2\u0139\u013b\5*\26\2\u013a\u013c\5.\30\2\u013b\u013a") + buf.write("\3\2\2\2\u013b\u013c\3\2\2\2\u013c)\3\2\2\2\u013d\u013e") + buf.write("\t\2\2\2\u013e+\3\2\2\2\u013f\u0145\7\63\2\2\u0140\u0141") + buf.write("\7\30\2\2\u0141\u0143\7\63\2\2\u0142\u0144\5.\30\2\u0143") + buf.write("\u0142\3\2\2\2\u0143\u0144\3\2\2\2\u0144\u0146\3\2\2\2") + buf.write("\u0145\u0140\3\2\2\2\u0146\u0147\3\2\2\2\u0147\u0145\3") + buf.write("\2\2\2\u0147\u0148\3\2\2\2\u0148-\3\2\2\2\u0149\u014b") + buf.write("\7\34\2\2\u014a\u014c\t\3\2\2\u014b\u014a\3\2\2\2\u014b") + buf.write("\u014c\3\2\2\2\u014c\u014d\3\2\2\2\u014d\u014e\7\35\2") + buf.write("\2\u014e/\3\2\2\2\u014f\u0151\7.\2\2\u0150\u014f\3\2\2") + buf.write("\2\u0150\u0151\3\2\2\2\u0151\u0152\3\2\2\2\u0152\u0153") + buf.write("\t\4\2\2\u0153\61\3\2\2\2\u0154\u015a\7\25\2\2\u0155\u015a") + buf.write("\7\26\2\2\u0156\u015a\5\60\31\2\u0157\u015a\7\62\2\2\u0158") + buf.write("\u015a\5,\27\2\u0159\u0154\3\2\2\2\u0159\u0155\3\2\2\2") + buf.write("\u0159\u0156\3\2\2\2\u0159\u0157\3\2\2\2\u0159\u0158\3") + buf.write("\2\2\2\u015a\63\3\2\2\2\u015b\u015c\b\33\1\2\u015c\u015d") + buf.write("\7!\2\2\u015d\u015e\5\64\33\2\u015e\u015f\7\"\2\2\u015f") + buf.write("\u0165\3\2\2\2\u0160\u0161\58\35\2\u0161\u0162\5\64\33") + buf.write("\6\u0162\u0165\3\2\2\2\u0163\u0165\5\62\32\2\u0164\u015b") + buf.write("\3\2\2\2\u0164\u0160\3\2\2\2\u0164\u0163\3\2\2\2\u0165") + buf.write("\u017e\3\2\2\2\u0166\u0167\f\13\2\2\u0167\u0168\7,\2\2") + buf.write("\u0168\u017d\5\64\33\f\u0169\u016a\f\n\2\2\u016a\u016b") + buf.write("\7-\2\2\u016b\u017d\5\64\33\13\u016c\u016d\f\t\2\2\u016d") + buf.write("\u016e\7.\2\2\u016e\u017d\5\64\33\n\u016f\u0170\f\b\2") + buf.write("\2\u0170\u0171\7/\2\2\u0171\u017d\5\64\33\t\u0172\u0173") + buf.write("\f\7\2\2\u0173\u0174\5\66\34\2\u0174\u0175\5\64\33\b\u0175") + buf.write("\u017d\3\2\2\2\u0176\u0177\f\5\2\2\u0177\u0178\7)\2\2") + buf.write("\u0178\u017d\5\64\33\6\u0179\u017a\f\4\2\2\u017a\u017b") + buf.write("\7*\2\2\u017b\u017d\5\64\33\5\u017c\u0166\3\2\2\2\u017c") + buf.write("\u0169\3\2\2\2\u017c\u016c\3\2\2\2\u017c\u016f\3\2\2\2") + buf.write("\u017c\u0172\3\2\2\2\u017c\u0176\3\2\2\2\u017c\u0179\3") + buf.write("\2\2\2\u017d\u0180\3\2\2\2\u017e\u017c\3\2\2\2\u017e\u017f") + buf.write("\3\2\2\2\u017f\65\3\2\2\2\u0180\u017e\3\2\2\2\u0181\u0182") + buf.write("\t\5\2\2\u0182\67\3\2\2\2\u0183\u0184\7+\2\2\u01849\3") + buf.write("\2\2\2\u0185\u0186\5> \2\u0186\u018b\5<\37\2\u0187\u0188") + buf.write("\7=\2\2\u0188\u018a\5<\37\2\u0189\u0187\3\2\2\2\u018a") + buf.write("\u018d\3\2\2\2\u018b\u0189\3\2\2\2\u018b\u018c\3\2\2\2") + buf.write("\u018c\u018e\3\2\2\2\u018d\u018b\3\2\2\2\u018e\u018f\7") + buf.write("A\2\2\u018f\u0194\3\2\2\2\u0190\u0191\5> \2\u0191\u0192") + buf.write("\7A\2\2\u0192\u0194\3\2\2\2\u0193\u0185\3\2\2\2\u0193") + buf.write("\u0190\3\2\2\2\u0194;\3\2\2\2\u0195\u0196\7\65\2\2\u0196") + buf.write("\u0197\78\2\2\u0197\u0198\5@!\2\u0198=\3\2\2\2\u0199\u019a") + buf.write("\t\6\2\2\u019a?\3\2\2\2\u019b\u01a2\7\65\2\2\u019c\u01a2") + buf.write("\7\66\2\2\u019d\u01a2\7\67\2\2\u019e\u01a2\7>\2\2\u019f") + buf.write("\u01a2\5:\36\2\u01a0\u01a2\5B\"\2\u01a1\u019b\3\2\2\2") + buf.write("\u01a1\u019c\3\2\2\2\u01a1\u019d\3\2\2\2\u01a1\u019e\3") + buf.write("\2\2\2\u01a1\u019f\3\2\2\2\u01a1\u01a0\3\2\2\2\u01a2A") + buf.write("\3\2\2\2\u01a3\u01a4\7;\2\2\u01a4\u01a9\5@!\2\u01a5\u01a6") + buf.write("\7=\2\2\u01a6\u01a8\5@!\2\u01a7\u01a5\3\2\2\2\u01a8\u01ab") + buf.write("\3\2\2\2\u01a9\u01a7\3\2\2\2\u01a9\u01aa\3\2\2\2\u01aa") + buf.write("\u01ac\3\2\2\2\u01ab\u01a9\3\2\2\2\u01ac\u01ad\7<\2\2") + buf.write("\u01ad\u01b1\3\2\2\2\u01ae\u01af\7;\2\2\u01af\u01b1\7") + buf.write("<\2\2\u01b0\u01a3\3\2\2\2\u01b0\u01ae\3\2\2\2\u01b1C\3") + buf.write("\2\2\2\67GIUYbgjuy\u0083\u0087\u0091\u0097\u009c\u009f") + buf.write("\u00a2\u00a8\u00ad\u00b0\u00b3\u00bb\u00be\u00c0\u00ca") + buf.write("\u00ce\u00d7\u00e2\u00e7\u00ee\u00f4\u00fe\u0103\u010a") + buf.write("\u0113\u0119\u0121\u0129\u0130\u0133\u013b\u0143\u0147") + buf.write("\u014b\u0150\u0159\u0164\u017c\u017e\u018b\u0193\u01a1") + buf.write("\u01a9\u01b0") return buf.getvalue() @@ -276,28 +282,29 @@ class PFDLParser ( Parser ): RULE_parameter = 16 RULE_struct_initialization = 17 RULE_variable_definition = 18 - RULE_primitive = 19 - RULE_attribute_access = 20 - RULE_array = 21 - RULE_number = 22 - RULE_value = 23 - RULE_expression = 24 - RULE_binOperation = 25 - RULE_unOperation = 26 - RULE_json_object = 27 - RULE_pair = 28 - RULE_json_open_bracket = 29 - RULE_json_value = 30 - RULE_json_array = 31 + RULE_variable_type = 19 + RULE_primitive = 20 + RULE_attribute_access = 21 + RULE_array = 22 + RULE_number = 23 + RULE_value = 24 + RULE_expression = 25 + RULE_binOperation = 26 + RULE_unOperation = 27 + RULE_json_object = 28 + RULE_pair = 29 + RULE_json_open_bracket = 30 + RULE_json_value = 31 + RULE_json_array = 32 ruleNames = [ "program", "struct", "task", "task_in", "task_out", "statement", "service_call", "task_call", "call_input", "call_output", "parallel", "while_loop", "counting_loop", "condition", "condition_passed", "condition_failed", "parameter", - "struct_initialization", "variable_definition", "primitive", - "attribute_access", "array", "number", "value", "expression", - "binOperation", "unOperation", "json_object", "pair", - "json_open_bracket", "json_value", "json_array" ] + "struct_initialization", "variable_definition", "variable_type", + "primitive", "attribute_access", "array", "number", "value", + "expression", "binOperation", "unOperation", "json_object", + "pair", "json_open_bracket", "json_value", "json_array" ] EOF = Token.EOF INDENT=1 @@ -366,7 +373,7 @@ class PFDLParser ( Parser ): def __init__(self, input:TokenStream, output:TextIO = sys.stdout): super().__init__(input, output) - self.checkVersion("4.9.2") + self.checkVersion("4.9.3") self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache) self._predicates = None @@ -430,33 +437,33 @@ def program(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 69 + self.state = 71 self._errHandler.sync(self) _la = self._input.LA(1) while (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << PFDLParser.STRUCT) | (1 << PFDLParser.TASK) | (1 << PFDLParser.NL))) != 0): - self.state = 67 + self.state = 69 self._errHandler.sync(self) token = self._input.LA(1) if token in [PFDLParser.NL]: - self.state = 64 + self.state = 66 self.match(PFDLParser.NL) pass elif token in [PFDLParser.STRUCT]: - self.state = 65 + self.state = 67 self.struct() pass elif token in [PFDLParser.TASK]: - self.state = 66 + self.state = 68 self.task() pass else: raise NoViableAltException(self) - self.state = 71 + self.state = 73 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 72 + self.state = 74 self.match(PFDLParser.EOF) except RecognitionException as re: localctx.exception = re @@ -529,39 +536,39 @@ def struct(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 74 + self.state = 76 self.match(PFDLParser.STRUCT) - self.state = 75 + self.state = 77 self.match(PFDLParser.STARTS_WITH_UPPER_C_STR) - self.state = 76 + self.state = 78 self.match(PFDLParser.INDENT) - self.state = 83 + self.state = 85 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 77 + self.state = 79 self.variable_definition() - self.state = 79 + self.state = 81 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 78 + self.state = 80 self.match(PFDLParser.NL) - self.state = 81 + self.state = 83 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.NL): break - self.state = 85 + self.state = 87 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.STARTS_WITH_LOWER_C_STR): break - self.state = 87 + self.state = 89 self.match(PFDLParser.DEDENT) - self.state = 88 + self.state = 90 self.match(PFDLParser.END) except RecognitionException as re: localctx.exception = re @@ -636,43 +643,43 @@ def task(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 90 + self.state = 92 self.match(PFDLParser.TASK) - self.state = 91 + self.state = 93 self.match(PFDLParser.STARTS_WITH_LOWER_C_STR) - self.state = 92 - self.match(PFDLParser.INDENT) self.state = 94 + self.match(PFDLParser.INDENT) + self.state = 96 self._errHandler.sync(self) _la = self._input.LA(1) if _la==PFDLParser.IN: - self.state = 93 + self.state = 95 self.task_in() - self.state = 97 + self.state = 99 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 96 + self.state = 98 self.statement() - self.state = 99 + self.state = 101 self._errHandler.sync(self) _la = self._input.LA(1) if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << PFDLParser.LOOP) | (1 << PFDLParser.PARALLEL) | (1 << PFDLParser.CONDITION) | (1 << PFDLParser.STARTS_WITH_LOWER_C_STR) | (1 << PFDLParser.STARTS_WITH_UPPER_C_STR))) != 0)): break - self.state = 102 + self.state = 104 self._errHandler.sync(self) _la = self._input.LA(1) if _la==PFDLParser.OUT: - self.state = 101 + self.state = 103 self.task_out() - self.state = 104 + self.state = 106 self.match(PFDLParser.DEDENT) - self.state = 105 + self.state = 107 self.match(PFDLParser.END) except RecognitionException as re: localctx.exception = re @@ -739,35 +746,35 @@ def task_in(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 107 + self.state = 109 self.match(PFDLParser.IN) - self.state = 108 + self.state = 110 self.match(PFDLParser.INDENT) - self.state = 115 + self.state = 117 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 109 + self.state = 111 self.variable_definition() - self.state = 111 + self.state = 113 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 110 + self.state = 112 self.match(PFDLParser.NL) - self.state = 113 + self.state = 115 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.NL): break - self.state = 117 + self.state = 119 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.STARTS_WITH_LOWER_C_STR): break - self.state = 119 + self.state = 121 self.match(PFDLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -833,35 +840,35 @@ def task_out(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 121 + self.state = 123 self.match(PFDLParser.OUT) - self.state = 122 + self.state = 124 self.match(PFDLParser.INDENT) - self.state = 129 + self.state = 131 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 123 + self.state = 125 self.match(PFDLParser.STARTS_WITH_LOWER_C_STR) - self.state = 125 + self.state = 127 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 124 + self.state = 126 self.match(PFDLParser.NL) - self.state = 127 + self.state = 129 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.NL): break - self.state = 131 + self.state = 133 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.STARTS_WITH_LOWER_C_STR): break - self.state = 133 + self.state = 135 self.match(PFDLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -928,42 +935,42 @@ def statement(self): localctx = PFDLParser.StatementContext(self, self._ctx, self.state) self.enterRule(localctx, 10, self.RULE_statement) try: - self.state = 141 + self.state = 143 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,11,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 135 + self.state = 137 self.service_call() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 136 + self.state = 138 self.task_call() pass elif la_ == 3: self.enterOuterAlt(localctx, 3) - self.state = 137 + self.state = 139 self.parallel() pass elif la_ == 4: self.enterOuterAlt(localctx, 4) - self.state = 138 + self.state = 140 self.while_loop() pass elif la_ == 5: self.enterOuterAlt(localctx, 5) - self.state = 139 + self.state = 141 self.counting_loop() pass elif la_ == 6: self.enterOuterAlt(localctx, 6) - self.state = 140 + self.state = 142 self.condition() pass @@ -1033,20 +1040,20 @@ def service_call(self): self.enterRule(localctx, 12, self.RULE_service_call) self._la = 0 # Token type try: - self.state = 158 + self.state = 160 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,15,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 143 + self.state = 145 self.match(PFDLParser.STARTS_WITH_UPPER_C_STR) - self.state = 145 + self.state = 147 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 144 + self.state = 146 self.match(PFDLParser.NL) - self.state = 147 + self.state = 149 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.NL): @@ -1056,27 +1063,27 @@ def service_call(self): elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 149 + self.state = 151 self.match(PFDLParser.STARTS_WITH_UPPER_C_STR) - self.state = 150 - self.match(PFDLParser.INDENT) self.state = 152 + self.match(PFDLParser.INDENT) + self.state = 154 self._errHandler.sync(self) _la = self._input.LA(1) if _la==PFDLParser.IN: - self.state = 151 + self.state = 153 self.call_input() - self.state = 155 + self.state = 157 self._errHandler.sync(self) _la = self._input.LA(1) if _la==PFDLParser.OUT: - self.state = 154 + self.state = 156 self.call_output() - self.state = 157 + self.state = 159 self.match(PFDLParser.DEDENT) pass @@ -1146,20 +1153,20 @@ def task_call(self): self.enterRule(localctx, 14, self.RULE_task_call) self._la = 0 # Token type try: - self.state = 175 + self.state = 177 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,19,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 160 + self.state = 162 self.match(PFDLParser.STARTS_WITH_LOWER_C_STR) - self.state = 162 + self.state = 164 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 161 + self.state = 163 self.match(PFDLParser.NL) - self.state = 164 + self.state = 166 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.NL): @@ -1169,27 +1176,27 @@ def task_call(self): elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 166 + self.state = 168 self.match(PFDLParser.STARTS_WITH_LOWER_C_STR) - self.state = 167 - self.match(PFDLParser.INDENT) self.state = 169 + self.match(PFDLParser.INDENT) + self.state = 171 self._errHandler.sync(self) _la = self._input.LA(1) if _la==PFDLParser.IN: - self.state = 168 + self.state = 170 self.call_input() - self.state = 172 + self.state = 174 self._errHandler.sync(self) _la = self._input.LA(1) if _la==PFDLParser.OUT: - self.state = 171 + self.state = 173 self.call_output() - self.state = 174 + self.state = 176 self.match(PFDLParser.DEDENT) pass @@ -1266,27 +1273,27 @@ def call_input(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 177 + self.state = 179 self.match(PFDLParser.IN) - self.state = 178 + self.state = 180 self.match(PFDLParser.INDENT) - self.state = 186 + self.state = 188 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 186 + self.state = 188 self._errHandler.sync(self) token = self._input.LA(1) if token in [PFDLParser.STARTS_WITH_LOWER_C_STR]: - self.state = 179 + self.state = 181 self.parameter() - self.state = 181 + self.state = 183 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 180 + self.state = 182 self.match(PFDLParser.NL) - self.state = 183 + self.state = 185 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.NL): @@ -1294,19 +1301,19 @@ def call_input(self): pass elif token in [PFDLParser.STARTS_WITH_UPPER_C_STR]: - self.state = 185 + self.state = 187 self.struct_initialization() pass else: raise NoViableAltException(self) - self.state = 188 + self.state = 190 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.STARTS_WITH_LOWER_C_STR or _la==PFDLParser.STARTS_WITH_UPPER_C_STR): break - self.state = 190 + self.state = 192 self.match(PFDLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -1373,35 +1380,35 @@ def call_output(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 192 + self.state = 194 self.match(PFDLParser.OUT) - self.state = 193 + self.state = 195 self.match(PFDLParser.INDENT) - self.state = 200 + self.state = 202 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 194 + self.state = 196 self.variable_definition() - self.state = 196 + self.state = 198 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 195 + self.state = 197 self.match(PFDLParser.NL) - self.state = 198 + self.state = 200 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.NL): break - self.state = 202 + self.state = 204 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.STARTS_WITH_LOWER_C_STR): break - self.state = 204 + self.state = 206 self.match(PFDLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -1462,23 +1469,23 @@ def parallel(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 206 + self.state = 208 self.match(PFDLParser.PARALLEL) - self.state = 207 + self.state = 209 self.match(PFDLParser.INDENT) - self.state = 209 + self.state = 211 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 208 + self.state = 210 self.task_call() - self.state = 211 + self.state = 213 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.STARTS_WITH_LOWER_C_STR): break - self.state = 213 + self.state = 215 self.match(PFDLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -1546,27 +1553,27 @@ def while_loop(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 215 + self.state = 217 self.match(PFDLParser.LOOP) - self.state = 216 + self.state = 218 self.match(PFDLParser.WHILE) - self.state = 217 + self.state = 219 self.expression(0) - self.state = 218 + self.state = 220 self.match(PFDLParser.INDENT) - self.state = 220 + self.state = 222 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 219 + self.state = 221 self.statement() - self.state = 222 + self.state = 224 self._errHandler.sync(self) _la = self._input.LA(1) if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << PFDLParser.LOOP) | (1 << PFDLParser.PARALLEL) | (1 << PFDLParser.CONDITION) | (1 << PFDLParser.STARTS_WITH_LOWER_C_STR) | (1 << PFDLParser.STARTS_WITH_UPPER_C_STR))) != 0)): break - self.state = 224 + self.state = 226 self.match(PFDLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -1593,16 +1600,19 @@ def STARTS_WITH_LOWER_C_STR(self): def TO(self): return self.getToken(PFDLParser.TO, 0) - def attribute_access(self): - return self.getTypedRuleContext(PFDLParser.Attribute_accessContext,0) - - def INDENT(self): return self.getToken(PFDLParser.INDENT, 0) def DEDENT(self): return self.getToken(PFDLParser.DEDENT, 0) + def attribute_access(self): + return self.getTypedRuleContext(PFDLParser.Attribute_accessContext,0) + + + def INTEGER(self): + return self.getToken(PFDLParser.INTEGER, 0) + def PARALLEL(self): return self.getToken(PFDLParser.PARALLEL, 0) @@ -1640,37 +1650,49 @@ def counting_loop(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 227 + self.state = 229 self._errHandler.sync(self) _la = self._input.LA(1) if _la==PFDLParser.PARALLEL: - self.state = 226 + self.state = 228 self.match(PFDLParser.PARALLEL) - self.state = 229 - self.match(PFDLParser.LOOP) - self.state = 230 - self.match(PFDLParser.STARTS_WITH_LOWER_C_STR) self.state = 231 - self.match(PFDLParser.TO) + self.match(PFDLParser.LOOP) self.state = 232 - self.attribute_access() + self.match(PFDLParser.STARTS_WITH_LOWER_C_STR) self.state = 233 + self.match(PFDLParser.TO) + self.state = 236 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [PFDLParser.STARTS_WITH_LOWER_C_STR]: + self.state = 234 + self.attribute_access() + pass + elif token in [PFDLParser.INTEGER]: + self.state = 235 + self.match(PFDLParser.INTEGER) + pass + else: + raise NoViableAltException(self) + + self.state = 238 self.match(PFDLParser.INDENT) - self.state = 235 + self.state = 240 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 234 + self.state = 239 self.statement() - self.state = 237 + self.state = 242 self._errHandler.sync(self) _la = self._input.LA(1) if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << PFDLParser.LOOP) | (1 << PFDLParser.PARALLEL) | (1 << PFDLParser.CONDITION) | (1 << PFDLParser.STARTS_WITH_LOWER_C_STR) | (1 << PFDLParser.STARTS_WITH_UPPER_C_STR))) != 0)): break - self.state = 239 + self.state = 244 self.match(PFDLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -1742,33 +1764,33 @@ def condition(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 241 + self.state = 246 self.match(PFDLParser.CONDITION) - self.state = 242 + self.state = 247 self.match(PFDLParser.INDENT) - self.state = 243 + self.state = 248 self.expression(0) - self.state = 245 + self.state = 250 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 244 + self.state = 249 self.match(PFDLParser.NL) - self.state = 247 + self.state = 252 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.NL): break - self.state = 249 + self.state = 254 self.match(PFDLParser.DEDENT) - self.state = 250 + self.state = 255 self.condition_passed() - self.state = 252 + self.state = 257 self._errHandler.sync(self) _la = self._input.LA(1) if _la==PFDLParser.FAILED: - self.state = 251 + self.state = 256 self.condition_failed() @@ -1831,23 +1853,23 @@ def condition_passed(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 254 + self.state = 259 self.match(PFDLParser.PASSED) - self.state = 255 + self.state = 260 self.match(PFDLParser.INDENT) - self.state = 257 + self.state = 262 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 256 + self.state = 261 self.statement() - self.state = 259 + self.state = 264 self._errHandler.sync(self) _la = self._input.LA(1) if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << PFDLParser.LOOP) | (1 << PFDLParser.PARALLEL) | (1 << PFDLParser.CONDITION) | (1 << PFDLParser.STARTS_WITH_LOWER_C_STR) | (1 << PFDLParser.STARTS_WITH_UPPER_C_STR))) != 0)): break - self.state = 261 + self.state = 266 self.match(PFDLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -1908,23 +1930,23 @@ def condition_failed(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 263 + self.state = 268 self.match(PFDLParser.FAILED) - self.state = 264 + self.state = 269 self.match(PFDLParser.INDENT) - self.state = 266 + self.state = 271 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 265 + self.state = 270 self.statement() - self.state = 268 + self.state = 273 self._errHandler.sync(self) _la = self._input.LA(1) if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << PFDLParser.LOOP) | (1 << PFDLParser.PARALLEL) | (1 << PFDLParser.CONDITION) | (1 << PFDLParser.STARTS_WITH_LOWER_C_STR) | (1 << PFDLParser.STARTS_WITH_UPPER_C_STR))) != 0)): break - self.state = 270 + self.state = 275 self.match(PFDLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -1974,18 +1996,18 @@ def parameter(self): localctx = PFDLParser.ParameterContext(self, self._ctx, self.state) self.enterRule(localctx, 32, self.RULE_parameter) try: - self.state = 274 + self.state = 279 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,33,self._ctx) + la_ = self._interp.adaptivePredict(self._input,34,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 272 + self.state = 277 self.match(PFDLParser.STARTS_WITH_LOWER_C_STR) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 273 + self.state = 278 self.attribute_access() pass @@ -2051,56 +2073,56 @@ def struct_initialization(self): self.enterRule(localctx, 34, self.RULE_struct_initialization) self._la = 0 # Token type try: - self.state = 300 + self.state = 305 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,37,self._ctx) + la_ = self._interp.adaptivePredict(self._input,38,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 276 + self.state = 281 self.match(PFDLParser.STARTS_WITH_UPPER_C_STR) - self.state = 277 + self.state = 282 self.match(PFDLParser.INDENT) - self.state = 278 + self.state = 283 self.json_object() - self.state = 280 + self.state = 285 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 279 + self.state = 284 self.match(PFDLParser.NL) - self.state = 282 + self.state = 287 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==PFDLParser.NL): break - self.state = 284 + self.state = 289 self.match(PFDLParser.DEDENT) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 286 + self.state = 291 self.match(PFDLParser.STARTS_WITH_UPPER_C_STR) - self.state = 290 + self.state = 295 self._errHandler.sync(self) _la = self._input.LA(1) while _la==PFDLParser.NL: - self.state = 287 - self.match(PFDLParser.NL) self.state = 292 + self.match(PFDLParser.NL) + self.state = 297 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 293 + self.state = 298 self.json_object() - self.state = 297 + self.state = 302 self._errHandler.sync(self) _la = self._input.LA(1) while _la==PFDLParser.NL: - self.state = 294 - self.match(PFDLParser.NL) self.state = 299 + self.match(PFDLParser.NL) + self.state = 304 self._errHandler.sync(self) _la = self._input.LA(1) @@ -2129,12 +2151,8 @@ def STARTS_WITH_LOWER_C_STR(self): def COLON(self): return self.getToken(PFDLParser.COLON, 0) - def primitive(self): - return self.getTypedRuleContext(PFDLParser.PrimitiveContext,0) - - - def array(self): - return self.getTypedRuleContext(PFDLParser.ArrayContext,0) + def variable_type(self): + return self.getTypedRuleContext(PFDLParser.Variable_typeContext,0) def getRuleIndex(self): @@ -2161,20 +2179,72 @@ def variable_definition(self): localctx = PFDLParser.Variable_definitionContext(self, self._ctx, self.state) self.enterRule(localctx, 36, self.RULE_variable_definition) - self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 302 + self.state = 307 self.match(PFDLParser.STARTS_WITH_LOWER_C_STR) - self.state = 303 + self.state = 308 self.match(PFDLParser.COLON) - self.state = 304 + self.state = 309 + self.variable_type() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + + class Variable_typeContext(ParserRuleContext): + __slots__ = 'parser' + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def primitive(self): + return self.getTypedRuleContext(PFDLParser.PrimitiveContext,0) + + + def array(self): + return self.getTypedRuleContext(PFDLParser.ArrayContext,0) + + + def getRuleIndex(self): + return PFDLParser.RULE_variable_type + + def enterRule(self, listener:ParseTreeListener): + if hasattr( listener, "enterVariable_type" ): + listener.enterVariable_type(self) + + def exitRule(self, listener:ParseTreeListener): + if hasattr( listener, "exitVariable_type" ): + listener.exitVariable_type(self) + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitVariable_type" ): + return visitor.visitVariable_type(self) + else: + return visitor.visitChildren(self) + + + + + def variable_type(self): + + localctx = PFDLParser.Variable_typeContext(self, self._ctx, self.state) + self.enterRule(localctx, 38, self.RULE_variable_type) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 311 self.primitive() - self.state = 306 + self.state = 313 self._errHandler.sync(self) _la = self._input.LA(1) if _la==PFDLParser.ARRAY_LEFT: - self.state = 305 + self.state = 312 self.array() @@ -2229,11 +2299,11 @@ def accept(self, visitor:ParseTreeVisitor): def primitive(self): localctx = PFDLParser.PrimitiveContext(self, self._ctx, self.state) - self.enterRule(localctx, 38, self.RULE_primitive) + self.enterRule(localctx, 40, self.RULE_primitive) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 308 + self.state = 315 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << PFDLParser.NUMBER_P) | (1 << PFDLParser.STRING_P) | (1 << PFDLParser.BOOLEAN_P) | (1 << PFDLParser.STARTS_WITH_UPPER_C_STR))) != 0)): self._errHandler.recoverInline(self) @@ -2298,34 +2368,34 @@ def accept(self, visitor:ParseTreeVisitor): def attribute_access(self): localctx = PFDLParser.Attribute_accessContext(self, self._ctx, self.state) - self.enterRule(localctx, 40, self.RULE_attribute_access) + self.enterRule(localctx, 42, self.RULE_attribute_access) try: self.enterOuterAlt(localctx, 1) - self.state = 310 + self.state = 317 self.match(PFDLParser.STARTS_WITH_LOWER_C_STR) - self.state = 316 + self.state = 323 self._errHandler.sync(self) _alt = 1 while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt == 1: - self.state = 311 + self.state = 318 self.match(PFDLParser.DOT) - self.state = 312 + self.state = 319 self.match(PFDLParser.STARTS_WITH_LOWER_C_STR) - self.state = 314 + self.state = 321 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,39,self._ctx) + la_ = self._interp.adaptivePredict(self._input,40,self._ctx) if la_ == 1: - self.state = 313 + self.state = 320 self.array() else: raise NoViableAltException(self) - self.state = 318 + self.state = 325 self._errHandler.sync(self) - _alt = self._interp.adaptivePredict(self._input,40,self._ctx) + _alt = self._interp.adaptivePredict(self._input,41,self._ctx) except RecognitionException as re: localctx.exception = re @@ -2378,17 +2448,17 @@ def accept(self, visitor:ParseTreeVisitor): def array(self): localctx = PFDLParser.ArrayContext(self, self._ctx, self.state) - self.enterRule(localctx, 42, self.RULE_array) + self.enterRule(localctx, 44, self.RULE_array) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 320 + self.state = 327 self.match(PFDLParser.ARRAY_LEFT) - self.state = 322 + self.state = 329 self._errHandler.sync(self) _la = self._input.LA(1) if _la==PFDLParser.INTEGER or _la==PFDLParser.STARTS_WITH_LOWER_C_STR: - self.state = 321 + self.state = 328 _la = self._input.LA(1) if not(_la==PFDLParser.INTEGER or _la==PFDLParser.STARTS_WITH_LOWER_C_STR): self._errHandler.recoverInline(self) @@ -2397,7 +2467,7 @@ def array(self): self.consume() - self.state = 324 + self.state = 331 self.match(PFDLParser.ARRAY_RIGHT) except RecognitionException as re: localctx.exception = re @@ -2421,6 +2491,9 @@ def INTEGER(self): def FLOAT(self): return self.getToken(PFDLParser.FLOAT, 0) + def MINUS(self): + return self.getToken(PFDLParser.MINUS, 0) + def getRuleIndex(self): return PFDLParser.RULE_number @@ -2444,11 +2517,19 @@ def accept(self, visitor:ParseTreeVisitor): def number(self): localctx = PFDLParser.NumberContext(self, self._ctx, self.state) - self.enterRule(localctx, 44, self.RULE_number) + self.enterRule(localctx, 46, self.RULE_number) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 326 + self.state = 334 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==PFDLParser.MINUS: + self.state = 333 + self.match(PFDLParser.MINUS) + + + self.state = 336 _la = self._input.LA(1) if not(_la==PFDLParser.INTEGER or _la==PFDLParser.FLOAT): self._errHandler.recoverInline(self) @@ -2511,34 +2592,34 @@ def accept(self, visitor:ParseTreeVisitor): def value(self): localctx = PFDLParser.ValueContext(self, self._ctx, self.state) - self.enterRule(localctx, 46, self.RULE_value) + self.enterRule(localctx, 48, self.RULE_value) try: - self.state = 333 + self.state = 343 self._errHandler.sync(self) token = self._input.LA(1) if token in [PFDLParser.TRUE]: self.enterOuterAlt(localctx, 1) - self.state = 328 + self.state = 338 self.match(PFDLParser.TRUE) pass elif token in [PFDLParser.FALSE]: self.enterOuterAlt(localctx, 2) - self.state = 329 + self.state = 339 self.match(PFDLParser.FALSE) pass - elif token in [PFDLParser.INTEGER, PFDLParser.FLOAT]: + elif token in [PFDLParser.MINUS, PFDLParser.INTEGER, PFDLParser.FLOAT]: self.enterOuterAlt(localctx, 3) - self.state = 330 + self.state = 340 self.number() pass elif token in [PFDLParser.STRING]: self.enterOuterAlt(localctx, 4) - self.state = 331 + self.state = 341 self.match(PFDLParser.STRING) pass elif token in [PFDLParser.STARTS_WITH_LOWER_C_STR]: self.enterOuterAlt(localctx, 5) - self.state = 332 + self.state = 342 self.attribute_access() pass else: @@ -2627,141 +2708,141 @@ def expression(self, _p:int=0): _parentState = self.state localctx = PFDLParser.ExpressionContext(self, self._ctx, _parentState) _prevctx = localctx - _startState = 48 - self.enterRecursionRule(localctx, 48, self.RULE_expression, _p) + _startState = 50 + self.enterRecursionRule(localctx, 50, self.RULE_expression, _p) try: self.enterOuterAlt(localctx, 1) - self.state = 344 + self.state = 354 self._errHandler.sync(self) token = self._input.LA(1) if token in [PFDLParser.LEFT_PARENTHESIS]: - self.state = 336 + self.state = 346 self.match(PFDLParser.LEFT_PARENTHESIS) - self.state = 337 + self.state = 347 self.expression(0) - self.state = 338 + self.state = 348 self.match(PFDLParser.RIGHT_PARENTHESIS) pass elif token in [PFDLParser.BOOLEAN_NOT]: - self.state = 340 + self.state = 350 self.unOperation() - self.state = 341 + self.state = 351 self.expression(4) pass - elif token in [PFDLParser.TRUE, PFDLParser.FALSE, PFDLParser.INTEGER, PFDLParser.FLOAT, PFDLParser.STRING, PFDLParser.STARTS_WITH_LOWER_C_STR]: - self.state = 343 + elif token in [PFDLParser.TRUE, PFDLParser.FALSE, PFDLParser.MINUS, PFDLParser.INTEGER, PFDLParser.FLOAT, PFDLParser.STRING, PFDLParser.STARTS_WITH_LOWER_C_STR]: + self.state = 353 self.value() pass else: raise NoViableAltException(self) self._ctx.stop = self._input.LT(-1) - self.state = 370 + self.state = 380 self._errHandler.sync(self) - _alt = self._interp.adaptivePredict(self._input,45,self._ctx) + _alt = self._interp.adaptivePredict(self._input,47,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx - self.state = 368 + self.state = 378 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,44,self._ctx) + la_ = self._interp.adaptivePredict(self._input,46,self._ctx) if la_ == 1: localctx = PFDLParser.ExpressionContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 346 + self.state = 356 if not self.precpred(self._ctx, 9): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 9)") - self.state = 347 + self.state = 357 self.match(PFDLParser.STAR) - self.state = 348 + self.state = 358 self.expression(10) pass elif la_ == 2: localctx = PFDLParser.ExpressionContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 349 + self.state = 359 if not self.precpred(self._ctx, 8): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 8)") - self.state = 350 + self.state = 360 self.match(PFDLParser.SLASH) - self.state = 351 + self.state = 361 self.expression(9) pass elif la_ == 3: localctx = PFDLParser.ExpressionContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 352 + self.state = 362 if not self.precpred(self._ctx, 7): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 7)") - self.state = 353 + self.state = 363 self.match(PFDLParser.MINUS) - self.state = 354 + self.state = 364 self.expression(8) pass elif la_ == 4: localctx = PFDLParser.ExpressionContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 355 + self.state = 365 if not self.precpred(self._ctx, 6): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 6)") - self.state = 356 + self.state = 366 self.match(PFDLParser.PLUS) - self.state = 357 + self.state = 367 self.expression(7) pass elif la_ == 5: localctx = PFDLParser.ExpressionContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 358 + self.state = 368 if not self.precpred(self._ctx, 5): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 5)") - self.state = 359 + self.state = 369 self.binOperation() - self.state = 360 + self.state = 370 self.expression(6) pass elif la_ == 6: localctx = PFDLParser.ExpressionContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 362 + self.state = 372 if not self.precpred(self._ctx, 3): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 3)") - self.state = 363 + self.state = 373 self.match(PFDLParser.BOOLEAN_AND) - self.state = 364 + self.state = 374 self.expression(4) pass elif la_ == 7: localctx = PFDLParser.ExpressionContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_expression) - self.state = 365 + self.state = 375 if not self.precpred(self._ctx, 2): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 2)") - self.state = 366 + self.state = 376 self.match(PFDLParser.BOOLEAN_OR) - self.state = 367 + self.state = 377 self.expression(3) pass - self.state = 372 + self.state = 382 self._errHandler.sync(self) - _alt = self._interp.adaptivePredict(self._input,45,self._ctx) + _alt = self._interp.adaptivePredict(self._input,47,self._ctx) except RecognitionException as re: localctx.exception = re @@ -2820,11 +2901,11 @@ def accept(self, visitor:ParseTreeVisitor): def binOperation(self): localctx = PFDLParser.BinOperationContext(self, self._ctx, self.state) - self.enterRule(localctx, 50, self.RULE_binOperation) + self.enterRule(localctx, 52, self.RULE_binOperation) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 373 + self.state = 383 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << PFDLParser.LESS_THAN) | (1 << PFDLParser.LESS_THAN_OR_EQUAL) | (1 << PFDLParser.GREATER_THAN) | (1 << PFDLParser.GREATER_THAN_OR_EQUAL) | (1 << PFDLParser.EQUAL) | (1 << PFDLParser.NOT_EQUAL))) != 0)): self._errHandler.recoverInline(self) @@ -2873,10 +2954,10 @@ def accept(self, visitor:ParseTreeVisitor): def unOperation(self): localctx = PFDLParser.UnOperationContext(self, self._ctx, self.state) - self.enterRule(localctx, 52, self.RULE_unOperation) + self.enterRule(localctx, 54, self.RULE_unOperation) try: self.enterOuterAlt(localctx, 1) - self.state = 375 + self.state = 385 self.match(PFDLParser.BOOLEAN_NOT) except RecognitionException as re: localctx.exception = re @@ -2937,39 +3018,39 @@ def accept(self, visitor:ParseTreeVisitor): def json_object(self): localctx = PFDLParser.Json_objectContext(self, self._ctx, self.state) - self.enterRule(localctx, 54, self.RULE_json_object) + self.enterRule(localctx, 56, self.RULE_json_object) self._la = 0 # Token type try: - self.state = 391 + self.state = 401 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,47,self._ctx) + la_ = self._interp.adaptivePredict(self._input,49,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 377 + self.state = 387 self.json_open_bracket() - self.state = 378 + self.state = 388 self.pair() - self.state = 383 + self.state = 393 self._errHandler.sync(self) _la = self._input.LA(1) while _la==PFDLParser.JSON_COMMA: - self.state = 379 + self.state = 389 self.match(PFDLParser.JSON_COMMA) - self.state = 380 + self.state = 390 self.pair() - self.state = 385 + self.state = 395 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 386 + self.state = 396 self.match(PFDLParser.JSON_CLOSE) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 388 + self.state = 398 self.json_open_bracket() - self.state = 389 + self.state = 399 self.match(PFDLParser.JSON_CLOSE) pass @@ -3023,14 +3104,14 @@ def accept(self, visitor:ParseTreeVisitor): def pair(self): localctx = PFDLParser.PairContext(self, self._ctx, self.state) - self.enterRule(localctx, 56, self.RULE_pair) + self.enterRule(localctx, 58, self.RULE_pair) try: self.enterOuterAlt(localctx, 1) - self.state = 393 + self.state = 403 self.match(PFDLParser.JSON_STRING) - self.state = 394 + self.state = 404 self.match(PFDLParser.JSON_COLON) - self.state = 395 + self.state = 405 self.json_value() except RecognitionException as re: localctx.exception = re @@ -3077,11 +3158,11 @@ def accept(self, visitor:ParseTreeVisitor): def json_open_bracket(self): localctx = PFDLParser.Json_open_bracketContext(self, self._ctx, self.state) - self.enterRule(localctx, 58, self.RULE_json_open_bracket) + self.enterRule(localctx, 60, self.RULE_json_open_bracket) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 397 + self.state = 407 _la = self._input.LA(1) if not(_la==PFDLParser.JSON_OPEN or _la==PFDLParser.JSON_OPEN_2): self._errHandler.recoverInline(self) @@ -3147,39 +3228,39 @@ def accept(self, visitor:ParseTreeVisitor): def json_value(self): localctx = PFDLParser.Json_valueContext(self, self._ctx, self.state) - self.enterRule(localctx, 60, self.RULE_json_value) + self.enterRule(localctx, 62, self.RULE_json_value) try: - self.state = 405 + self.state = 415 self._errHandler.sync(self) token = self._input.LA(1) if token in [PFDLParser.JSON_STRING]: self.enterOuterAlt(localctx, 1) - self.state = 399 + self.state = 409 self.match(PFDLParser.JSON_STRING) pass elif token in [PFDLParser.JSON_TRUE]: self.enterOuterAlt(localctx, 2) - self.state = 400 + self.state = 410 self.match(PFDLParser.JSON_TRUE) pass elif token in [PFDLParser.JSON_FALSE]: self.enterOuterAlt(localctx, 3) - self.state = 401 + self.state = 411 self.match(PFDLParser.JSON_FALSE) pass elif token in [PFDLParser.NUMBER]: self.enterOuterAlt(localctx, 4) - self.state = 402 + self.state = 412 self.match(PFDLParser.NUMBER) pass elif token in [PFDLParser.JSON_OPEN, PFDLParser.JSON_OPEN_2]: self.enterOuterAlt(localctx, 5) - self.state = 403 + self.state = 413 self.json_object() pass elif token in [PFDLParser.JSON_ARRAY_LEFT]: self.enterOuterAlt(localctx, 6) - self.state = 404 + self.state = 414 self.json_array() pass else: @@ -3243,39 +3324,39 @@ def accept(self, visitor:ParseTreeVisitor): def json_array(self): localctx = PFDLParser.Json_arrayContext(self, self._ctx, self.state) - self.enterRule(localctx, 62, self.RULE_json_array) + self.enterRule(localctx, 64, self.RULE_json_array) self._la = 0 # Token type try: - self.state = 420 + self.state = 430 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,50,self._ctx) + la_ = self._interp.adaptivePredict(self._input,52,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) - self.state = 407 + self.state = 417 self.match(PFDLParser.JSON_ARRAY_LEFT) - self.state = 408 + self.state = 418 self.json_value() - self.state = 413 + self.state = 423 self._errHandler.sync(self) _la = self._input.LA(1) while _la==PFDLParser.JSON_COMMA: - self.state = 409 + self.state = 419 self.match(PFDLParser.JSON_COMMA) - self.state = 410 + self.state = 420 self.json_value() - self.state = 415 + self.state = 425 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 416 + self.state = 426 self.match(PFDLParser.JSON_ARRAY_RIGHT) pass elif la_ == 2: self.enterOuterAlt(localctx, 2) - self.state = 418 + self.state = 428 self.match(PFDLParser.JSON_ARRAY_LEFT) - self.state = 419 + self.state = 429 self.match(PFDLParser.JSON_ARRAY_RIGHT) pass @@ -3293,7 +3374,7 @@ def json_array(self): def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): if self._predicates == None: self._predicates = dict() - self._predicates[24] = self.expression_sempred + self._predicates[25] = self.expression_sempred pred = self._predicates.get(ruleIndex, None) if pred is None: raise Exception("No predicate with index:" + str(ruleIndex)) diff --git a/pfdl_scheduler/parser/PFDLParserVisitor.py b/pfdl_scheduler/parser/PFDLParserVisitor.py index 5549436..321dc46 100644 --- a/pfdl_scheduler/parser/PFDLParserVisitor.py +++ b/pfdl_scheduler/parser/PFDLParserVisitor.py @@ -1,4 +1,4 @@ -# Generated from PFDLParser.g4 by ANTLR 4.9.2 +# Generated from PFDLParser.g4 by ANTLR 4.9.3 from antlr4 import * if __name__ is not None and "." in __name__: from .PFDLParser import PFDLParser @@ -104,6 +104,11 @@ def visitVariable_definition(self, ctx:PFDLParser.Variable_definitionContext): return self.visitChildren(ctx) + # Visit a parse tree produced by PFDLParser#variable_type. + def visitVariable_type(self, ctx:PFDLParser.Variable_typeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by PFDLParser#primitive. def visitPrimitive(self, ctx:PFDLParser.PrimitiveContext): return self.visitChildren(ctx) diff --git a/pfdl_scheduler/parser/pfdl_tree_visitor.py b/pfdl_scheduler/parser/pfdl_tree_visitor.py index f847c52..b9ff2ef 100644 --- a/pfdl_scheduler/parser/pfdl_tree_visitor.py +++ b/pfdl_scheduler/parser/pfdl_tree_visitor.py @@ -262,7 +262,11 @@ def visitCounting_loop(self, ctx: PFDLParser.Counting_loopContext) -> CountingLo counting_loop.context = ctx counting_loop.counting_variable = ctx.STARTS_WITH_LOWER_C_STR().getText() - counting_loop.limit = self.visitAttribute_access(ctx.attribute_access()) + + if ctx.attribute_access(): + counting_loop.limit = self.visitAttribute_access(ctx.attribute_access()) + else: + counting_loop.limit = int(ctx.INTEGER().getText()) # check if parallel keyword is there if ctx.PARALLEL(): @@ -305,28 +309,36 @@ def visitVariable_definition( self, ctx: PFDLParser.Variable_definitionContext ) -> Tuple[str, Union[str, Array]]: identifier = ctx.STARTS_WITH_LOWER_C_STR().getText() + variable_type = self.visitVariable_type(ctx.variable_type()) + return (identifier, variable_type) + + def visitVariable_type(self, ctx: PFDLParser.Variable_typeContext) -> Union[str, Array]: variable_type = self.visitPrimitive(ctx.primitive()) if ctx.array(): - array = Array() - array.type_of_elements = variable_type - array.context = ctx.array() - length = self.visitArray(ctx.array()) - if not isinstance(length, int): - self.error_handler.print_error( - "Array length has to be specified by an integer", syntax_error=True - ) - else: - array.length = length - + array = self.initializeArray(ctx.array(), variable_type) variable_type = array - return (identifier, variable_type) + return variable_type def visitPrimitive(self, ctx: PFDLParser.PrimitiveContext): return ctx.getText() + def initializeArray(self, array_ctx: PFDLParser.ArrayContext, variable_type: str) -> Array: + array = Array() + array.type_of_elements = variable_type + array.context = array_ctx + length = self.visitArray(array_ctx) + if not isinstance(length, int): + self.error_handler.print_error( + "Array length has to be specified by an integer", syntax_error=True + ) + else: + array.length = length + + return array + def visitAttribute_access(self, ctx: PFDLParser.Attribute_accessContext) -> List[str]: access_list = [] @@ -354,16 +366,16 @@ def visitExpression(self, ctx: PFDLParser.ExpressionContext) -> Dict: ele = self.get_content(ctx.children[0]) if isinstance(ele, List): return ele - if helpers.is_int(ele): - return int(ele) - if helpers.is_float(ele): - return float(ele) - if helpers.is_boolean(ele): - return ele == "true" + elif not helpers.is_string(ele): + # strings should not appear here + casted_element = helpers.cast_element(ele) + # check if ele is a primitve datatype (number or bool) + if casted_element != ele: + return casted_element if length == 2: un_op = self.get_content(ctx.children[0]) ele = self.get_content(ctx.children[1]) - return dict(unop=un_op, value=ele) + return dict(unOp=un_op, value=ele) if length == 3: left = self.get_content(ctx.children[0]) diff --git a/pfdl_scheduler/petri_net/drawer.py b/pfdl_scheduler/petri_net/drawer.py index 696f3fd..1bd9e90 100644 --- a/pfdl_scheduler/petri_net/drawer.py +++ b/pfdl_scheduler/petri_net/drawer.py @@ -58,13 +58,14 @@ def draw_place(place, attr): else: attr["xlabel"] = place.name - attr["group"] = place.label("group_id") + attr["group"] = place.label("group_uuid") if 1 in place: attr["label"] = "•" else: attr["label"] = PLACE_LABEL attr["shape"] = PLACE_SHAPE + attr["ordering"] = "out" def draw_transition(trans, attr): @@ -75,7 +76,7 @@ def draw_transition(trans, attr): attr["height"] = TRANSITION_HEIGHT attr["width"] = TRANSITION_WIDTH attr["fillcolor"] = TRANSITION_FILL_COLOR - attr["group"] = trans.label("group_id") + attr["group"] = trans.label("group_uuid") def draw_arcs(arc, attr): diff --git a/pfdl_scheduler/petri_net/generator.py b/pfdl_scheduler/petri_net/generator.py index d907718..995098a 100644 --- a/pfdl_scheduler/petri_net/generator.py +++ b/pfdl_scheduler/petri_net/generator.py @@ -7,7 +7,8 @@ """Contains the PetriNetGenerator class.""" # standard libraries -from typing import Any, Callable, Dict, List, OrderedDict, Tuple +import copy +from typing import Any, Callable, Dict, List, OrderedDict import uuid import functools import json @@ -37,24 +38,34 @@ class Node(object): - def __init__(self, group_id: str, name="", parent: "Node" = None): - self.group_id: str = group_id + """Represents a type of component relative to its position in the call graph + + Attributes: + group_uuid: The id of the group of petri net components this node represents + """ + + def __init__(self, group_uuid: str, name="", parent: "Node" = None): + self.group_uuid: str = group_uuid self.name: str = name self.children: List[Node] = [] - self.cluster = None - + self.path = [] if parent: parent.add_child(self) + self.path = copy.deepcopy(parent.path) + self.path.append(len(parent.children)) def add_child(self, node: "Node"): self.children.append(node) + def get_path(self) -> List[str]: + return self.path + def toJSON(self): children_list = [] for child in self.children: child_dict = child.toJSON() children_list.append(child_dict) - json_dict = {"id": self.group_id, "name": self.name, "children": children_list} + json_dict = {"id": self.group_uuid, "name": self.name, "children": children_list} return json_dict @@ -66,8 +77,8 @@ class PetriNetGenerator: net: The snakes Petri Net instance. tasks: A dict representing the Tasks of the given Process object. transition_dict: A dict for mapping the UUIDs of the Transitions to their behavior. - place_dict: A dict for mapping the service id to the place name. - task_started_id: The id of the 'Task started' place. + place_dict: A dict for mapping the service uuid to the place name. + task_started_uuid: The uuid of the 'Task started' place. callbacks: A PetriNetCallbacks instance representing functions called while execution. generate_test_ids: A boolean indicating if test ids (counting from 0) should be generated. used_in_extension: A boolean indicating if the Generator is used within the extension. @@ -88,6 +99,7 @@ def __init__( used_in_extension: A boolean indicating if the Generator is used within the extension. generate_test_ids: A boolean indicating if test ids (counting from 0) should be generated. draw_net: A boolean indicating if the petri net should be drawn. + file_name: The desired filename of the petri net image. """ if used_in_extension: @@ -104,36 +116,35 @@ def __init__( self.tasks: Dict[str, Task] = None self.transition_dict: OrderedDict = OrderedDict() self.place_dict: Dict = {} - self.task_started_id: str = "" + self.task_started_uuid: str = "" self.callbacks: PetriNetCallbacks = PetriNetCallbacks() self.generate_test_ids: bool = generate_test_ids self.used_in_extension: bool = used_in_extension self.tree = None self.file_name = file_name - self.cluster = None - def add_callback(self, transition_id: str, callback_function: Callable, *args: Any) -> None: + def add_callback(self, transition_uuid: str, callback_function: Callable, *args: Any) -> None: """Registers the given callback function in the transition_dict. - If the transition the transition_id refers to is fired, the callback function + If the transition the transition_uuid refers to is fired, the callback function will be called with the given arguments inside the PetriNetLogic class. Args: - transition_id: The UUID of the transition where the callback is called if fired. + transition_uuid: The UUID of the transition where the callback is called if fired. callback_function: The callback function which should be called. *args: Arguments with which the callback function is called. """ if not self.used_in_extension: callback = functools.partial(callback_function, *args) - if transition_id not in self.transition_dict: - self.transition_dict[transition_id] = [] + if transition_uuid not in self.transition_dict: + self.transition_dict[transition_uuid] = [] - self.transition_dict[transition_id].append(callback) + self.transition_dict[transition_uuid].append(callback) def generate_petri_net(self, process: Process) -> PetriNet: """Generates a Petri Net from the given Process object. - Starts from the 'productionTask' and iterates over his statements. + Starts from the start task of the PFDL program and iterates over his statements. For each statement type like Condition or TaskCall a Petri Net component is generated. All components get connected at the end. @@ -141,44 +152,42 @@ def generate_petri_net(self, process: Process) -> PetriNet: A PetriNet instance representing the generated net. """ self.tasks = process.tasks - for task in process.tasks.values(): - if task.name == "productionTask": - group_id = str(uuid.uuid4()) - self.tree = Node(group_id, task.name) + start_task = process.tasks[process.start_task_name] + group_uuid = str(uuid.uuid4()) + self.tree = Node(group_uuid, start_task.name) - task_context = TaskAPI(task, None) - if self.generate_test_ids: - task_context.uuid = "0" + task_context = TaskAPI(start_task, None) + if self.generate_test_ids: + task_context.uuid = "0" - self.task_started_id = create_place( - task.name + "_started", self.net, group_id, [0, 0] - ) - connection_id = create_transition("", "", self.net, group_id) + self.task_started_uuid = create_place(start_task.name + "_started", self.net, self.tree) + connection_uuid = create_transition("", "", self.net, self.tree) - self.add_callback(connection_id, self.callbacks.task_started, task_context) + self.add_callback(connection_uuid, self.callbacks.task_started, task_context) - self.net.add_input(self.task_started_id, connection_id, Value(1)) - self.task_finished_id = create_place(task.name + "_finished", self.net, group_id) + self.net.add_input(self.task_started_uuid, connection_uuid, Value(1)) + self.task_finished_uuid = create_place(start_task.name + "_finished", self.net, self.tree) - second_connection_id = create_transition("", "", self.net, group_id) + second_connection_uuid = create_transition("", "", self.net, self.tree) - self.tree.cluster = Cluster( - [ - self.task_started_id, - connection_id, - second_connection_id, - self.task_finished_id, - ] - ) - self.generate_statements( - task_context, task.statements, connection_id, second_connection_id, self.tree - ) - self.net.add_output(self.task_finished_id, second_connection_id, Value(1)) - - self.add_callback(second_connection_id, self.callbacks.task_finished, task_context) + self.tree.cluster = Cluster( + [ + self.task_started_uuid, + connection_uuid, + second_connection_uuid, + self.task_finished_uuid, + ] + ) + self.generate_statements( + task_context, + start_task.statements, + connection_uuid, + second_connection_uuid, + self.tree, + ) + self.net.add_output(self.task_finished_uuid, second_connection_uuid, Value(1)) - # assign new clusters before drawing - self.net.clusters = self.tree.cluster + self.add_callback(second_connection_uuid, self.callbacks.task_finished, task_context) if self.draw_net: json_string = json.dumps(self.tree.toJSON(), indent=4) @@ -194,8 +203,8 @@ def generate_statements( self, task_context: TaskAPI, statements: List, - first_connection_id: str, - last_connection_id: str, + first_connection_uuid: str, + last_connection_uuid: str, node: Node, in_loop: bool = False, ) -> List[str]: @@ -206,12 +215,12 @@ def generate_statements( transition. Returns: - The ids of the last connections (transitions). + The uuids of the last connections (transitions). """ - current_connection_id = "" - previous_connection_id = first_connection_id + current_connection_uuid = "" + previous_connection_uuid = first_connection_uuid - connection_ids = [] + connection_uuids = [] for i, statement in enumerate(statements): multiple_statements = len(statements) > 1 @@ -219,155 +228,148 @@ def generate_statements( # and we are not in the last iteration if multiple_statements: if i < len(statements) - 1: - current_connection_id = create_transition( - "connection", "", self.net, node.group_id - ) - node.cluster.add_node(current_connection_id) + current_connection_uuid = create_transition("connection", "", self.net, node) else: - current_connection_id = last_connection_id + current_connection_uuid = last_connection_uuid else: - previous_connection_id = first_connection_id - current_connection_id = last_connection_id + previous_connection_uuid = first_connection_uuid + current_connection_uuid = last_connection_uuid args = ( statement, task_context, - previous_connection_id, - current_connection_id, + previous_connection_uuid, + current_connection_uuid, node, in_loop, ) if isinstance(statement, Service): - connection_ids = [self.generate_service(*args)] + connection_uuids = [self.generate_service(*args)] elif isinstance(statement, TaskCall): - connection_ids = self.generate_task_call(*args) + connection_uuids = self.generate_task_call(*args) elif isinstance(statement, Parallel): - connection_ids = [self.generate_parallel(*args)] + connection_uuids = [self.generate_parallel(*args)] elif isinstance(statement, CountingLoop): - connection_ids = [self.generate_counting_loop(*args)] + connection_uuids = [self.generate_counting_loop(*args)] elif isinstance(statement, WhileLoop): - connection_ids = [self.generate_while_loop(*args)] + connection_uuids = [self.generate_while_loop(*args)] + elif isinstance(statement, Condition): + connection_uuids = self.generate_condition(*args) else: - connection_ids = self.generate_condition(*args) + connection_uuids = self.handle_other_statements(*args) - previous_connection_id = current_connection_id + previous_connection_uuid = current_connection_uuid - return connection_ids + return connection_uuids def generate_service( self, service: Service, task_context: TaskAPI, - first_transition_id: str, - second_transition_id: str, + first_transition_uuid: str, + second_transition_uuid: str, node: Node, in_loop: bool = False, ) -> str: """Generate the Petri Net components for a Service Call. Returns: - The id of the last transition of the Service petri net component. + The uuid of the last transition of the Service petri net component. """ - group_id = str(uuid.uuid4()) - Node(group_id, service.name, node) + group_uuid = str(uuid.uuid4()) + service_node = Node(group_uuid, service.name, node) service_api = ServiceAPI(service, task_context, in_loop=in_loop) - service_started_id = create_place(service.name + " started", self.net, group_id) - service_finished_id = create_place(service.name + " finished", self.net, group_id) + service_started_uuid = create_place(service.name + " started", self.net, service_node) + service_finished_uuid = create_place(service.name + " finished", self.net, service_node) - self.place_dict[service_api.uuid] = service_finished_id + self.place_dict[service_api.uuid] = service_finished_uuid - service_done_id = create_place(service.name + " done", self.net, group_id) - service_done_transition_id = create_transition("service_done", "", self.net, group_id) + service_done_uuid = create_place(service.name + " done", self.net, service_node) + service_done_transition_uuid = create_transition("service_done", "", self.net, service_node) - self.add_callback(first_transition_id, self.callbacks.service_started, service_api) - self.add_callback(service_done_transition_id, self.callbacks.service_finished, service_api) + self.add_callback(first_transition_uuid, self.callbacks.service_started, service_api) + self.add_callback( + service_done_transition_uuid, self.callbacks.service_finished, service_api + ) - self.net.add_input(service_started_id, service_done_transition_id, Value(1)) - self.net.add_input(service_finished_id, service_done_transition_id, Value(1)) - self.net.add_output(service_done_id, service_done_transition_id, Value(1)) + self.net.add_input(service_started_uuid, service_done_transition_uuid, Value(1)) + self.net.add_input(service_finished_uuid, service_done_transition_uuid, Value(1)) + self.net.add_output(service_done_uuid, service_done_transition_uuid, Value(1)) - self.net.add_output(service_started_id, first_transition_id, Value(1)) - self.net.add_input(service_done_id, second_transition_id, Value(1)) + self.net.add_output(service_started_uuid, first_transition_uuid, Value(1)) + self.net.add_input(service_done_uuid, second_transition_uuid, Value(1)) - node.cluster.add_child( - ( - Cluster( - [ - service_started_id, - service_finished_id, - service_done_transition_id, - service_done_id, - ] - ) - ) + service_node.cluster = Cluster( + [ + service_started_uuid, + service_finished_uuid, + service_done_transition_uuid, + service_done_uuid, + ] ) - return service_done_transition_id + return service_done_transition_uuid def generate_task_call( self, task_call: TaskCall, task_context: TaskAPI, - first_transition_id: str, - second_transition_id: str, + first_transition_uuid: str, + second_transition_uuid: str, node: Node, in_loop: bool = False, ) -> List[str]: """Generate the Petri Net components for a Task Call. Returns: - The ids of the last transitions of the TaskCall petri net component. + The uuids of the last transitions of the TaskCall petri net component. """ called_task = self.tasks[task_call.name] new_task_context = TaskAPI(called_task, task_context, task_call=task_call, in_loop=in_loop) - group_id = str(uuid.uuid4()) - task_node = Node(group_id, task_call.name, node) - - task_cluster = Cluster([]) - node.cluster.add_child(task_cluster) - task_node.cluster = task_cluster + group_uuid = str(uuid.uuid4()) + task_node = Node(group_uuid, task_call.name, node) # Order for callbacks important: Task starts before statement and finishes after - self.add_callback(first_transition_id, self.callbacks.task_started, new_task_context) - last_connection_ids = self.generate_statements( + self.add_callback(first_transition_uuid, self.callbacks.task_started, new_task_context) + last_connection_uuids = self.generate_statements( new_task_context, called_task.statements, - first_transition_id, - second_transition_id, + first_transition_uuid, + second_transition_uuid, task_node, in_loop, ) - for last_connection_id in last_connection_ids: - self.add_callback(last_connection_id, self.callbacks.task_finished, new_task_context) + for last_connection_uuid in last_connection_uuids: + self.add_callback(last_connection_uuid, self.callbacks.task_finished, new_task_context) - return last_connection_ids + return last_connection_uuids def generate_parallel( self, parallel: Parallel, task_context: TaskAPI, - first_transition_id: str, - second_transition_id: str, + first_transition_uuid: str, + second_transition_uuid: str, node: Node, in_loop: bool = False, ) -> str: """Generate the Petri Net components for a Parallel statement. Returns: - The id of the last transition of the Parallel petri net component. + The uuid of the last transition of the Parallel petri net component. """ - group_id = str(uuid.uuid4()) - parallel_node = Node(group_id, "Parallel", node) + group_uuid = str(uuid.uuid4()) + parallel_node = Node(group_uuid, "Parallel", node) - sync_id = create_transition("", "", self.net, group_id) - parallel_finished_id = create_place("Parallel finished", self.net, group_id) + sync_uuid = create_transition("", "", self.net, parallel_node) + parallel_finished_uuid = create_place("Parallel finished", self.net, parallel_node) - cluster = Cluster([], Cluster([sync_id, parallel_finished_id])) + cluster = Cluster([], Cluster([sync_uuid, parallel_finished_uuid])) node.cluster.add_child(cluster) parallel_node.cluster = cluster @@ -376,58 +378,57 @@ def generate_parallel( cluster.add_child(parallel_cluster) parallel_node.cluster = parallel_cluster self.generate_task_call( - task_call, task_context, first_transition_id, sync_id, parallel_node, in_loop + task_call, task_context, first_transition_uuid, sync_uuid, parallel_node, in_loop ) - self.net.add_output(parallel_finished_id, sync_id, Value(1)) - self.net.add_input(parallel_finished_id, second_transition_id, Value(1)) - return sync_id + self.net.add_output(parallel_finished_uuid, sync_uuid, Value(1)) + self.net.add_input(parallel_finished_uuid, second_transition_uuid, Value(1)) + return sync_uuid def generate_condition( self, condition: Condition, task_context: TaskAPI, - first_transition_id: str, - second_transition_id: str, + first_transition_uuid: str, + second_transition_uuid: str, node: Node, in_loop: bool = False, ) -> List[str]: """Generate Petri Net components for the Condition statement. Returns: - The ids of the last transitions of the Condition petri net component. + The uuids of the last transitions of the Condition petri net component. """ - group_id = str(uuid.uuid4()) - condition_node = Node(group_id, "Condition", node) + group_uuid = str(uuid.uuid4()) + condition_node = Node(group_uuid, "Condition", node) - passed_id = create_place("Passed", self.net, group_id) - failed_id = create_place("Failed", self.net, group_id) + passed_uuid = create_place("Passed", self.net, condition_node) + failed_uuid = create_place("Failed", self.net, condition_node) - expression_id = create_place( + expression_uuid = create_place( "If " + self.parse_expression(condition.expression), self.net, - group_id, + condition_node, ) - first_passed_transition_id = create_transition("", "", self.net, group_id) - first_failed_transition_id = create_transition("", "", self.net, group_id) + first_passed_transition_uuid = create_transition("", "", self.net, condition_node) + first_failed_transition_uuid = create_transition("", "", self.net, condition_node) - self.net.add_input(expression_id, first_passed_transition_id, Value(1)) - self.net.add_input(expression_id, first_failed_transition_id, Value(1)) + self.net.add_input(expression_uuid, first_passed_transition_uuid, Value(1)) + self.net.add_input(expression_uuid, first_failed_transition_uuid, Value(1)) - self.net.add_input(passed_id, first_passed_transition_id, Value(1)) - self.net.add_input(failed_id, first_failed_transition_id, Value(1)) + self.net.add_input(passed_uuid, first_passed_transition_uuid, Value(1)) + self.net.add_input(failed_uuid, first_failed_transition_uuid, Value(1)) - finished_id = create_place("Condition_Finished", self.net, group_id) + finished_uuid = create_place("Condition_Finished", self.net, condition_node) - second_passed_transition_id = create_transition("", "", self.net, group_id) - self.net.add_output(finished_id, second_passed_transition_id, Value(1)) + second_passed_transition_uuid = create_transition("", "", self.net, condition_node) + self.net.add_output(finished_uuid, second_passed_transition_uuid, Value(1)) - cluster = Cluster([passed_id, failed_id, expression_id, finished_id]) - node.cluster.add_child(cluster) + cluster = Cluster([passed_uuid, failed_uuid, expression_uuid, finished_uuid]) - cluster_passed = Cluster([first_passed_transition_id, second_passed_transition_id]) - cluster_failed = Cluster([first_failed_transition_id]) + cluster_passed = Cluster([first_passed_transition_uuid, second_passed_transition_uuid]) + cluster_failed = Cluster([first_failed_transition_uuid]) cluster.add_child(cluster_passed) cluster.add_child(cluster_failed) condition_node.cluster = cluster_passed @@ -435,119 +436,119 @@ def generate_condition( self.generate_statements( task_context, condition.passed_stmts, - first_passed_transition_id, - second_passed_transition_id, + first_passed_transition_uuid, + second_passed_transition_uuid, condition_node, in_loop, ) - self.net.add_output(expression_id, first_transition_id, Value(1)) - self.net.add_input(finished_id, second_transition_id, Value(1)) + self.net.add_output(expression_uuid, first_transition_uuid, Value(1)) + self.net.add_input(finished_uuid, second_transition_uuid, Value(1)) - args = (condition, passed_id, failed_id, task_context) - self.add_callback(first_transition_id, self.callbacks.condition_started, *args) + args = (condition, passed_uuid, failed_uuid, task_context) + self.add_callback(first_transition_uuid, self.callbacks.condition_started, *args) if condition.failed_stmts: condition_node.cluster = cluster_failed - second_failed_transition_id = create_transition("", "", self.net, group_id) - cluster_failed.add_node(second_failed_transition_id) + second_failed_transition_uuid = create_transition("", "", self.net, condition_node) + cluster_failed.add_node(second_failed_transition_uuid) self.generate_statements( task_context, condition.failed_stmts, - first_failed_transition_id, - second_failed_transition_id, + first_failed_transition_uuid, + second_failed_transition_uuid, condition_node, in_loop, ) - self.net.add_output(finished_id, second_failed_transition_id, Value(1)) - return [second_passed_transition_id, second_failed_transition_id] + self.net.add_output(finished_uuid, second_failed_transition_uuid, Value(1)) + return [second_passed_transition_uuid, second_failed_transition_uuid] else: - self.net.add_output(finished_id, first_failed_transition_id, Value(1)) - return [second_passed_transition_id, first_failed_transition_id] + self.net.add_output(finished_uuid, first_failed_transition_uuid, Value(1)) + return [second_passed_transition_uuid, first_failed_transition_uuid] def generate_counting_loop( self, loop: CountingLoop, task_context: TaskAPI, - first_transition_id: str, - second_transition_id: str, + first_transition_uuid: str, + second_transition_uuid: str, node: Node, in_loop: bool = False, ) -> str: """Generates the Petri Net components for a Couting Loop. Returns: - The id of the last transition of the CountingLoop petri net component. + The uuid of the last transition of the CountingLoop petri net component. """ if loop.parallel: return self.generate_parallel_loop( - loop, task_context, first_transition_id, second_transition_id, node + loop, task_context, first_transition_uuid, second_transition_uuid, node ) - group_id = str(uuid.uuid4()) - counting_loop_node = Node(group_id, "Counting Loop", node) - loop_id = create_place("Loop", self.net, group_id) + group_uuid = str(uuid.uuid4()) + counting_loop_node = Node(group_uuid, "Counting Loop", node) + loop_uuid = create_place("Loop", self.net, counting_loop_node) loop_text = "Loop" - loop_statements_id = create_place(loop_text, self.net, group_id) - loop_finished_id = create_place("Number of Steps Done", self.net, group_id) + loop_statements_uuid = create_place(loop_text, self.net, counting_loop_node) + loop_finished_uuid = create_place("Number of Steps Done", self.net, counting_loop_node) - condition_passed_transition_id = create_transition("", "", self.net, group_id) - condition_failed_transition_id = create_transition("", "", self.net, group_id) - iteration_step_done_transition_id = create_transition("", "", self.net, group_id) + condition_passed_transition_uuid = create_transition("", "", self.net, counting_loop_node) + condition_failed_transition_uuid = create_transition("", "", self.net, counting_loop_node) + iteration_step_done_transition_uuid = create_transition( + "", "", self.net, counting_loop_node + ) - self.net.add_input(loop_id, condition_passed_transition_id, Value(1)) - self.net.add_input(loop_statements_id, condition_passed_transition_id, Value(1)) - self.net.add_input(loop_id, condition_failed_transition_id, Value(1)) - self.net.add_input(loop_finished_id, condition_failed_transition_id, Value(1)) - self.net.add_output(loop_id, iteration_step_done_transition_id, Value(1)) + self.net.add_input(loop_uuid, condition_passed_transition_uuid, Value(1)) + self.net.add_input(loop_statements_uuid, condition_passed_transition_uuid, Value(1)) + self.net.add_input(loop_uuid, condition_failed_transition_uuid, Value(1)) + self.net.add_input(loop_finished_uuid, condition_failed_transition_uuid, Value(1)) + self.net.add_output(loop_uuid, iteration_step_done_transition_uuid, Value(1)) - loop_done_id = create_place("Loop Done", self.net, group_id) + loop_done_uuid = create_place("Loop Done", self.net, counting_loop_node) cluster = Cluster( [ - loop_id, - loop_statements_id, - loop_finished_id, - condition_passed_transition_id, - condition_failed_transition_id, - iteration_step_done_transition_id, - loop_done_id, + loop_uuid, + loop_statements_uuid, + loop_finished_uuid, + condition_passed_transition_uuid, + condition_failed_transition_uuid, + iteration_step_done_transition_uuid, + loop_done_uuid, ] ) - - node.cluster.add_child(cluster) counting_loop_node.cluster = cluster self.generate_statements( task_context, loop.statements, - condition_passed_transition_id, - iteration_step_done_transition_id, + condition_passed_transition_uuid, + iteration_step_done_transition_uuid, counting_loop_node, True, ) - self.net.add_output(loop_done_id, condition_failed_transition_id, Value(1)) - self.net.add_output(loop_id, first_transition_id, Value(1)) - self.net.add_input(loop_done_id, second_transition_id, Value(1)) + self.net.add_output(loop_done_uuid, condition_failed_transition_uuid, Value(1)) + self.net.add_output(loop_uuid, first_transition_uuid, Value(1)) + self.net.add_input(loop_done_uuid, second_transition_uuid, Value(1)) - args = (loop, loop_statements_id, loop_finished_id, task_context) - self.add_callback(first_transition_id, self.callbacks.counting_loop_started, *args) + args = (loop, loop_statements_uuid, loop_finished_uuid, task_context) + self.add_callback(first_transition_uuid, self.callbacks.counting_loop_started, *args) self.add_callback( - iteration_step_done_transition_id, self.callbacks.counting_loop_started, *args + iteration_step_done_transition_uuid, self.callbacks.counting_loop_started, *args ) - return condition_failed_transition_id + return condition_failed_transition_uuid def generate_parallel_loop( self, loop: CountingLoop, task_context: TaskAPI, - first_transition_id: str, - second_transition_id: str, + first_transition_uuid: str, + second_transition_uuid: str, node: Node, ) -> str: """Generates the static petri net components for a ParallelLoop. @@ -556,127 +557,145 @@ def generate_parallel_loop( of parallel startet Tasks is only known at runtime. Returns: - The id of the last transition of the ParallelLoop petri net component. + The uuid of the last transition of the ParallelLoop petri net component. """ - group_id = str(uuid.uuid4()) - parallel_loop_node = Node(group_id, "Parallel Loop", node) + group_uuid = str(uuid.uuid4()) + parallel_loop_node = Node(group_uuid, "Parallel Loop", node) parallel_loop_started = create_place( "Start " + loop.statements[0].name + " in parallel", self.net, - group_id, + parallel_loop_node, ) cluster = Cluster([parallel_loop_started]) - node.cluster.add_child(cluster) + parallel_loop_node.cluster = cluster - self.net.add_output(parallel_loop_started, first_transition_id, Value(1)) - self.net.add_input(parallel_loop_started, second_transition_id, Value(1)) + self.net.add_output(parallel_loop_started, first_transition_uuid, Value(1)) + self.net.add_input(parallel_loop_started, second_transition_uuid, Value(1)) args = ( loop, task_context, loop.statements[0], parallel_loop_started, - first_transition_id, - second_transition_id, + first_transition_uuid, + second_transition_uuid, parallel_loop_node, ) - self.add_callback(first_transition_id, self.callbacks.parallel_loop_started, *args) - return second_transition_id + self.add_callback(first_transition_uuid, self.callbacks.parallel_loop_started, *args) + return second_transition_uuid - def remove_place_on_runtime(self, place_id: str) -> None: + def handle_other_statements( + self, + statement: Any, + task_context: TaskAPI, + first_transition_uuid: str, + second_transition_uuid: str, + node: Node, + in_loop: bool = False, + ) -> List[str]: + """Generates Petri Net components for newly added PFDL components. + + This function can be used by plugin developers to generate Petri Net components + if they add new components through their plugin. + + Returns: + A list of uuids of the last transition in the respective component. + """ + return None + + def remove_place_on_runtime(self, place_uuid: str) -> None: """Removes a place from the petri net at runtime. + This method tries to remove the place with the given id from the petri net. + Due to the clustering plugin in the petri net library, the `remove` place method + + Args: - place_id: The id as string of the task which should be removed from the net. + place_uuid: The uuid as string of the task which should be removed from the net. """ - if self.net.has_place(place_id): - # temporary fix - # self.net.clusters.remove_node(self.task_started_id) - # self.net.remove_place(self.task_started_id) - + if self.net.has_place(place_uuid): + self.net.remove_place(place_uuid) if self.draw_net: draw_petri_net(self.net, self.path_for_image) def generate_empty_parallel_loop( - self, first_transition_id: str, second_transition_id: str + self, first_transition_uuid: str, second_transition_uuid: str, node: Node ) -> None: - empty_loop_place = create_place("Execute 0 tasks", self.net) - self.net.add_output(empty_loop_place, first_transition_id, Value(1)) - self.net.add_input(empty_loop_place, second_transition_id, Value(1)) + empty_loop_place = create_place("Execute 0 tasks", self.net, node) + self.net.add_output(empty_loop_place, first_transition_uuid, Value(1)) + self.net.add_input(empty_loop_place, second_transition_uuid, Value(1)) def generate_while_loop( self, loop: CountingLoop, task_context: TaskAPI, - first_transition_id: str, - second_transition_id: str, + first_transition_uuid: str, + second_transition_uuid: str, node: Node, in_loop: bool = False, ) -> str: """Generate the Petri Net components for a While Loop. Returns: - The id of the last transition of the WhileLoop petri net component. + The uuid of the last transition of the WhileLoop petri net component. """ - group_id = str(uuid.uuid4()) - while_loop_node = Node(group_id, "While Loop", node) + group_uuid = str(uuid.uuid4()) + while_loop_node = Node(group_uuid, "While Loop", node) - loop_id = create_place("Loop", self.net, group_id) + loop_uuid = create_place("Loop", self.net, while_loop_node) loop_text = "Loop" - loop_statements_id = create_place(loop_text, self.net, group_id) - loop_finished_id = create_place("Number of Steps Done", self.net, group_id) + loop_statements_uuid = create_place(loop_text, self.net, while_loop_node) + loop_finished_uuid = create_place("Number of Steps Done", self.net, while_loop_node) - condition_passed_transition_id = create_transition("", "", self.net, group_id) - condition_failed_transition_id = create_transition("", "", self.net, group_id) - iteration_step_done_transition_id = create_transition("", "", self.net, group_id) + condition_passed_transition_uuid = create_transition("", "", self.net, while_loop_node) + condition_failed_transition_uuid = create_transition("", "", self.net, while_loop_node) + iteration_step_done_transition_uuid = create_transition("", "", self.net, while_loop_node) - self.net.add_input(loop_id, condition_passed_transition_id, Value(1)) - self.net.add_input(loop_statements_id, condition_passed_transition_id, Value(1)) - self.net.add_input(loop_id, condition_failed_transition_id, Value(1)) - self.net.add_input(loop_finished_id, condition_failed_transition_id, Value(1)) - self.net.add_output(loop_id, iteration_step_done_transition_id, Value(1)) + self.net.add_input(loop_uuid, condition_passed_transition_uuid, Value(1)) + self.net.add_input(loop_statements_uuid, condition_passed_transition_uuid, Value(1)) + self.net.add_input(loop_uuid, condition_failed_transition_uuid, Value(1)) + self.net.add_input(loop_finished_uuid, condition_failed_transition_uuid, Value(1)) + self.net.add_output(loop_uuid, iteration_step_done_transition_uuid, Value(1)) - loop_done_id = create_place("Loop Done", self.net, group_id) + loop_done_uuid = create_place("Loop Done", self.net, while_loop_node) cluster = Cluster( [ - loop_id, - loop_statements_id, - loop_finished_id, - condition_failed_transition_id, - loop_done_id, - condition_passed_transition_id, - iteration_step_done_transition_id, + loop_uuid, + loop_statements_uuid, + loop_finished_uuid, + condition_failed_transition_uuid, + loop_done_uuid, + condition_passed_transition_uuid, + iteration_step_done_transition_uuid, ] ) - - node.cluster.add_child(cluster) while_loop_node.cluster = cluster self.generate_statements( task_context, loop.statements, - condition_passed_transition_id, - iteration_step_done_transition_id, + condition_passed_transition_uuid, + iteration_step_done_transition_uuid, while_loop_node, True, ) - self.net.add_output(loop_id, first_transition_id, Value(1)) - self.net.add_input(loop_done_id, second_transition_id, Value(1)) + self.net.add_output(loop_uuid, first_transition_uuid, Value(1)) + self.net.add_input(loop_done_uuid, second_transition_uuid, Value(1)) - args = (loop, loop_statements_id, loop_finished_id, task_context) - self.add_callback(first_transition_id, self.callbacks.while_loop_started, *args) + args = (loop, loop_statements_uuid, loop_finished_uuid, task_context) + self.add_callback(first_transition_uuid, self.callbacks.while_loop_started, *args) self.add_callback( - iteration_step_done_transition_id, self.callbacks.while_loop_started, *args + iteration_step_done_transition_uuid, self.callbacks.while_loop_started, *args ) - self.net.add_output(loop_done_id, condition_failed_transition_id, Value(1)) + self.net.add_output(loop_done_uuid, condition_failed_transition_uuid, Value(1)) - return condition_failed_transition_id + return condition_failed_transition_uuid def parse_expression(self, expression: Dict) -> str: """Parses the given expression to a printable format. @@ -706,7 +725,7 @@ def parse_expression(self, expression: Dict) -> str: ) -def create_place(name: str, net: PetriNet, group_id: str, cluster: List = []) -> str: +def create_place(name: str, net: PetriNet, node: Node) -> str: """Utility function for creating a place with the snakes module. This function is used to add a place with the given name and to add labels for @@ -715,20 +734,18 @@ def create_place(name: str, net: PetriNet, group_id: str, cluster: List = []) -> Args: name: A string representing the displayed name of the place. net: The petri net instance this place should be added to. - group_id: + group_uuid: The id of a group of petri net components this place belongs to Returns: A UUID as string for the added place. """ - place_id = str(uuid.uuid4()) - net.add_place(Place(place_id, []), cluster=cluster) - net.place(place_id).label(name=name, group_id=group_id) - return place_id + place_uuid = str(uuid.uuid4()) + net.add_place(Place(place_uuid, []), cluster=node.get_path()) + net.place(place_uuid).label(name=name, group_uuid=node.group_uuid) + return place_uuid -def create_transition( - transition_name: str, transition_type: str, net: PetriNet, group_id: str -) -> str: +def create_transition(transition_name: str, transition_type: str, net: PetriNet, node: Node) -> str: """Utility function for creating a transition with the snakes module. This function is used to add a transition with the given name and to add labels for @@ -737,16 +754,16 @@ def create_transition( Args: transition_name: A string representing the displayed name of the transition. net: The petri net instance this transition should be added to. - group_id: + group_uuid: The id of a group of petri net components this transition belongs to Returns: A UUID as string for the added transition. """ - transition_id = str(uuid.uuid4()) - net.add_transition(Transition(transition_id)) - net.transition(transition_id).label( + transition_uuid = str(uuid.uuid4()) + net.add_transition(Transition(transition_uuid), cluster=node.get_path()) + net.transition(transition_uuid).label( name=transition_name, transitionType=transition_type, - group_id=group_id, + group_uuid=node.group_uuid, ) - return transition_id + return transition_uuid diff --git a/pfdl_scheduler/petri_net/logic.py b/pfdl_scheduler/petri_net/logic.py index df7fae6..cc247c0 100644 --- a/pfdl_scheduler/petri_net/logic.py +++ b/pfdl_scheduler/petri_net/logic.py @@ -11,7 +11,7 @@ from typing import Dict # 3rd party packages -from nets import Value, PetriNet +from nets import PetriNet, Value # local sources from pfdl_scheduler.petri_net.drawer import draw_petri_net @@ -30,12 +30,12 @@ class PetriNetLogic: petri_net_generator: A reference to the PetriNetGenerator. petri_net: A reference to the generated petri net. draw_net: Indiciating whether the net should be drawn. - transition_dict: A reference to the dict in the generator which maps the ids to callbacks. + transition_dict: A reference to the dict in the generator which maps the uuids to callbacks. """ def __init__( self, petri_net_generator: PetriNetGenerator, draw_net: bool = True, file_name: str = "" - ): + ) -> None: """Initialize the object. Args: @@ -49,7 +49,12 @@ def __init__( self.file_name = file_name def draw_petri_net(self) -> None: - """Saves the given petri net as an image in the current working directory. + """Saves the given petri net in the current working directory. + + If the `draw_net` flag is set, this method will save the petri net in a "temp" folder + inside the root folder of the project. The petri net is saved as an image and as a dot + file to allow further processing. The dot file also contains the "call_tree", a tree + structure that describes the call hierarchy of PFDL tasks. Args: name: The name of the image. @@ -66,18 +71,22 @@ def draw_petri_net(self) -> None: file.write(json.dumps(self.petri_net_generator.tree.toJSON(), indent=4)) def evaluate_petri_net(self) -> None: - """Tries to fire every transition as long as all transitions - were tried and nothing can be done anymore. + """Triggers the evaluation of the petri net and its tokens. + + This method tries to fire every transition successively until no transition + can be fired anymore. If a transition is fired, the whole loop starts again, as + a new petri net state could allow past transitions to be fired now. + Each method call also calls the `draw_petri_net` method. """ index = 0 transitions = list(self.petri_net._trans) while index < len(transitions): - transition_id = transitions[index] + transition_uuid = transitions[index] - if self.petri_net.transition(transition_id).enabled(Value(1)): - if transition_id in self.transition_dict: - callbacks = self.transition_dict[transition_id] + if self.petri_net.transition(transition_uuid).enabled(Value(1)): + if transition_uuid in self.transition_dict: + callbacks = self.transition_dict[transition_uuid] temp = None for callback in callbacks: @@ -87,18 +96,19 @@ def evaluate_petri_net(self) -> None: callbacks.remove(temp) if temp: + # execute other callbacks first before handling parallel loop functionality for callback in list(callbacks): callback() callbacks.remove(callback) temp() return else: - self.petri_net.transition(transition_id).fire(Value(1)) + self.petri_net.transition(transition_uuid).fire(Value(1)) for callback in callbacks: callback() else: - self.petri_net.transition(transition_id).fire(Value(1)) + self.petri_net.transition(transition_uuid).fire(Value(1)) index = 0 else: @@ -111,15 +121,18 @@ def fire_event(self, event: Event) -> bool: Args: event: The Event object that is fired. + + Returns: + True if the given event could be resolved into an existing place in the petri net. """ name_in_petri_net = "" if event.event_type == START_PRODUCTION_TASK: - name_in_petri_net = self.petri_net_generator.task_started_id + name_in_petri_net = self.petri_net_generator.task_started_uuid elif event.event_type == SET_PLACE: - name_in_petri_net = event.data["place_id"] + name_in_petri_net = event.data["place_uuid"] elif event.event_type == SERVICE_FINISHED: - name_in_petri_net = self.petri_net_generator.place_dict[event.data["service_id"]] + name_in_petri_net = self.petri_net_generator.place_dict[event.data["service_uuid"]] if self.petri_net.has_place(name_in_petri_net): self.petri_net.place(name_in_petri_net).add(1) diff --git a/pfdl_scheduler/scheduler.py b/pfdl_scheduler/scheduler.py index c02298c..d1f0fc5 100644 --- a/pfdl_scheduler/scheduler.py +++ b/pfdl_scheduler/scheduler.py @@ -22,8 +22,7 @@ from pfdl_scheduler.api.task_api import TaskAPI from pfdl_scheduler.api.service_api import ServiceAPI -from pfdl_scheduler.utils.parsing_utils import load_file -from pfdl_scheduler.utils.parsing_utils import parse_file +from pfdl_scheduler.utils.parsing_utils import parse_program from pfdl_scheduler.petri_net.generator import Node, PetriNetGenerator from pfdl_scheduler.petri_net.logic import PetriNetLogic @@ -64,7 +63,7 @@ class Scheduler(Subject): petri_net_logic: A PetriNetLogic instance for execution of the petri net. task_callbacks: TaskCallbacks instance which holds the registered callbacks. variable_access_function: The function which will be called when the scheduler needs a variable. - loop_counters: A dict for mapping task ids to the current loop counter (counting loops). + loop_counters: A dict for mapping task uuids to the current loop counter (counting loops). awaited_events: A list of awaited `Event`s. Only these events can be passed to the net. generate_test_ids: Indicates whether test ids should be generated. test_id_counters: A List consisting of counters for the test ids of tasks and services. @@ -73,30 +72,48 @@ class Scheduler(Subject): def __init__( self, - pfdl_file_path: str, + pfdl_program: str, generate_test_ids: bool = False, draw_petri_net: bool = True, - scheduler_id: str = "", + scheduler_uuid: str = "", dashboard_host_address: str = "", ) -> None: """Initialize the object. - If the given path leads to a valid PFDL file the parsing will be started. If no errors - occur the model of the PFDL File will be transformed into a petri net and be drawn if - the `draw_petri_net` flag is set. If `generate_test_ids` is set the ids of the called + If the given program contains a path that leads to a valid PFDL file or consists of a + valid PFDL string directly, the parsing will be started. If no errors occur the model + of the PFDL file will be transformed into a petri net and be drawn if the + `draw_petri_net` flag is set. If `generate_test_ids` is set the ids of the called tasks and services will be an enumeration starting at 0. Args: - pfdl_file_path: The path to the PFDL file. + pfdl_program: A path to the PFDL file or directly the PFDL program as a string. generate_test_ids: A boolean indicating whether test ids should be generated. draw_petri_net: A boolean indicating whether the petri net should be drawn. - scheduler_id: A unique ID to identify the Scheduer / Production Order + scheduler_uuid: A unique ID to identify the Scheduer / Production Order dashboard_host_address: The address of the Dashboard (if existing) """ - if scheduler_id == "": - self.scheduler_id: str = str(uuid.uuid4()) + self.init_scheduler(scheduler_uuid, generate_test_ids) + self.pfdl_file_valid, self.process, pfdl_string = parse_program(pfdl_program) + + if self.pfdl_file_valid: + self.petri_net_generator = PetriNetGenerator( + "", + generate_test_ids=self.generate_test_ids, + draw_net=draw_petri_net, + file_name=self.scheduler_uuid, + ) + self.setup_scheduling(draw_petri_net) + if dashboard_host_address != "": + self.attach( + DashboardObserver(dashboard_host_address, self.scheduler_uuid, pfdl_string) + ) + + def init_scheduler(self, scheduler_uuid: str, generate_test_ids: bool): + if scheduler_uuid == "": + self.scheduler_uuid: str = str(uuid.uuid4()) else: - self.scheduler_id: str = scheduler_id + self.scheduler_uuid: str = scheduler_uuid self.running: bool = False self.pfdl_file_valid: bool = False self.process: Process = None @@ -108,30 +125,18 @@ def __init__( self.awaited_events: List[Event] = [] self.generate_test_ids: bool = generate_test_ids self.test_id_counters: List[int] = [0, 0] - self.pfdl_file_valid, self.process, pfdl_string = parse_file(pfdl_file_path) - if self.pfdl_file_valid: - self.petri_net_generator = PetriNetGenerator( - "", - generate_test_ids=generate_test_ids, - draw_net=draw_petri_net, - file_name=self.scheduler_id, - ) - self.register_for_petrinet_callbacks() + self.observers: List[Observer] = [] - self.petri_net_generator.generate_petri_net(self.process) - self.petri_net_logic = PetriNetLogic( - self.petri_net_generator, draw_petri_net, file_name=self.scheduler_id - ) + def setup_scheduling(self, draw_petri_net: bool): + self.register_for_petrinet_callbacks() + + self.petri_net_generator.generate_petri_net(self.process) + self.petri_net_logic = PetriNetLogic( + self.petri_net_generator, draw_petri_net, file_name=self.scheduler_uuid + ) awaited_event = Event(event_type=START_PRODUCTION_TASK, data={}) self.awaited_events.append(awaited_event) - self.observers: List[Observer] = [] - - # enable logging - self.attach(LogEntryObserver(self.scheduler_id)) - - if dashboard_host_address != "": - self.attach(DashboardObserver(dashboard_host_address, self.scheduler_id, pfdl_string)) def attach(self, observer: Observer) -> None: """Attach (add) an observer object to the observers list.""" @@ -180,7 +185,7 @@ def fire_event(self, event: Event) -> bool: if event in self.awaited_events: if self.petri_net_logic.fire_event(event): self.awaited_events.remove(event) - self.notify(NotificationType.PETRI_NET, self.scheduler_id) + self.notify(NotificationType.PETRI_NET, self.scheduler_uuid) return True return False @@ -258,16 +263,21 @@ def register_variable_access_function(self, var_access_func: Callable[[str], str def on_task_started(self, task_api: TaskAPI) -> None: """Executes Scheduling logic when a Task is started.""" - new_uuid = str(uuid.uuid4()) - if self.generate_test_ids: + if task_api.in_loop: + if self.generate_test_ids: + task_api.uuid = str(self.test_id_counters[0]) + self.test_id_counters[0] = self.test_id_counters[0] + 1 + else: + task_api.uuid = str(uuid.uuid4()) + + if task_api.task_call: + task_api.input_parameters = copy.deepcopy(task_api.task_call.input_parameters) + self.substitute_loop_indexes(task_api) + elif self.generate_test_ids: new_uuid = str(self.test_id_counters[0]) self.test_id_counters[0] = self.test_id_counters[0] + 1 + task_api.uuid = new_uuid - task_api.uuid = new_uuid - if task_api.task_call: - task_api.input_parameters = copy.deepcopy(task_api.task_call.input_parameters) - - self.substitute_loop_indexes(task_api) for callback in self.task_callbacks.task_started: callback(task_api) @@ -299,22 +309,33 @@ def substitute_loop_indexes(self, call_api: Union[ServiceAPI, TaskAPI]) -> None: def on_service_started(self, service_api: ServiceAPI) -> None: """Executes Scheduling logic when a Service is started.""" - new_uuid = str(uuid.uuid4()) - if self.generate_test_ids: + if service_api.in_loop: + new_uuid = str(uuid.uuid4()) + if self.generate_test_ids: + new_uuid = str(self.test_id_counters[1]) + self.test_id_counters[1] = self.test_id_counters[1] + 1 + + self.petri_net_generator.place_dict[new_uuid] = self.petri_net_generator.place_dict[ + service_api.uuid + ] + service_api.uuid = new_uuid + + if service_api.input_parameters: + service_api.input_parameters = copy.deepcopy(service_api.service.input_parameters) + + self.substitute_loop_indexes(service_api) + elif self.generate_test_ids: new_uuid = str(self.test_id_counters[1]) self.test_id_counters[1] = self.test_id_counters[1] + 1 - self.petri_net_generator.place_dict[new_uuid] = self.petri_net_generator.place_dict[ - service_api.uuid - ] - service_api.uuid = new_uuid - if service_api.input_parameters: - service_api.input_parameters = copy.deepcopy(service_api.service.input_parameters) + self.petri_net_generator.place_dict[new_uuid] = self.petri_net_generator.place_dict[ + service_api.uuid + ] + service_api.uuid = new_uuid - awaited_event = Event(event_type=SERVICE_FINISHED, data={"service_id": service_api.uuid}) + awaited_event = Event(event_type=SERVICE_FINISHED, data={"service_uuid": service_api.uuid}) self.awaited_events.append(awaited_event) - self.substitute_loop_indexes(service_api) for callback in self.task_callbacks.service_started: callback(service_api) @@ -342,11 +363,11 @@ def on_condition_started( ) -> None: """Executes Scheduling logic when a Condition statement is started.""" if self.check_expression(condition.expression, task_context): - awaited_event = Event(event_type=SET_PLACE, data={"place_id": then_uuid}) + awaited_event = Event(event_type=SET_PLACE, data={"place_uuid": then_uuid}) self.awaited_events.append(awaited_event) self.fire_event(awaited_event) else: - awaited_event = Event(event_type=SET_PLACE, data={"place_id": else_uuid}) + awaited_event = Event(event_type=SET_PLACE, data={"place_uuid": else_uuid}) self.awaited_events.append(awaited_event) self.fire_event(awaited_event) @@ -355,11 +376,11 @@ def on_while_loop_started( ) -> None: """Executes Scheduling logic when a While Loop is started.""" if self.check_expression(loop.expression, task_context): - awaited_event = Event(event_type=SET_PLACE, data={"place_id": then_uuid}) + awaited_event = Event(event_type=SET_PLACE, data={"place_uuid": then_uuid}) self.awaited_events.append(awaited_event) self.fire_event(awaited_event) else: - awaited_event = Event(event_type=SET_PLACE, data={"place_id": else_uuid}) + awaited_event = Event(event_type=SET_PLACE, data={"place_uuid": else_uuid}) self.awaited_events.append(awaited_event) self.fire_event(awaited_event) @@ -382,12 +403,12 @@ def on_counting_loop_started( loop_limit = self.get_loop_limit(loop, task_context) if loop_counter < loop_limit: - awaited_event = Event(event_type=SET_PLACE, data={"place_id": then_uuid}) + awaited_event = Event(event_type=SET_PLACE, data={"place_uuid": then_uuid}) self.awaited_events.append(awaited_event) self.fire_event(awaited_event) else: - awaited_event = Event(event_type=SET_PLACE, data={"place_id": else_uuid}) + awaited_event = Event(event_type=SET_PLACE, data={"place_uuid": else_uuid}) self.awaited_events.append(awaited_event) # has to be executed at last @@ -399,8 +420,8 @@ def on_parallel_loop_started( task_context: TaskAPI, parallelTask: Task, parallel_loop_started, - first_transition_id: str, - second_transition_id: str, + first_transition_uuid: str, + second_transition_uuid: str, node: Node, ) -> None: """Executes Scheduling logic when a Parallel Loop is started.""" @@ -412,8 +433,8 @@ def on_parallel_loop_started( self.petri_net_generator.generate_task_call( parallelTask, task_context, - first_transition_id, - second_transition_id, + first_transition_uuid, + second_transition_uuid, node, False, ) @@ -425,7 +446,7 @@ def on_parallel_loop_started( ] = ParallelLoopCounter() else: self.petri_net_generator.generate_empty_parallel_loop( - first_transition_id, second_transition_id + first_transition_uuid, second_transition_uuid ) self.petri_net_generator.remove_place_on_runtime(parallel_loop_started) @@ -434,6 +455,9 @@ def on_parallel_loop_started( self.petri_net_logic.evaluate_petri_net() def get_loop_limit(self, loop: CountingLoop, task_context: TaskAPI) -> int: + # loop limit is already a number so just return it + if isinstance(loop.limit, int): + return loop.limit loop_limit = 0 variable = loop.limit[0] loop_limit = self.variable_access_function(variable, task_context) @@ -448,11 +472,11 @@ def on_task_finished(self, task_api: TaskAPI) -> None: callback(task_api) order_finished = False - if task_api.task.name == "productionTask": + if task_api.task.name == self.process.start_task_name: self.running = False order_finished = True self.petri_net_logic.draw_petri_net() - self.notify(NotificationType.PETRI_NET, self.scheduler_id) + self.notify(NotificationType.PETRI_NET, self.scheduler_uuid) log_entry = "Task " + task_api.task.name + " with UUID '" + task_api.uuid + "' finished." self.notify(NotificationType.LOG_EVENT, (log_entry, logging.INFO, order_finished)) diff --git a/pfdl_scheduler/scheduling/event.py b/pfdl_scheduler/scheduling/event.py index 664a342..2fec82f 100644 --- a/pfdl_scheduler/scheduling/event.py +++ b/pfdl_scheduler/scheduling/event.py @@ -22,7 +22,7 @@ class Event: """Data class for controlling the PetriNet instance. Currently avaiable Events: - - Event(event_type="service_finished", data={"service_id": }) + - Event(event_type="service_finished", data={"service_uuid": }) Attributes: event_type: A string representing the type of the event. diff --git a/pfdl_scheduler/utils/dashboard_observer.py b/pfdl_scheduler/utils/dashboard_observer.py index 518927f..b9858b6 100644 --- a/pfdl_scheduler/utils/dashboard_observer.py +++ b/pfdl_scheduler/utils/dashboard_observer.py @@ -52,9 +52,9 @@ class DashboardObserver(Observer): The Observer will send a post request to the dashboard with the data. """ - def __init__(self, host: str, scheduler_id: str, pfdl_string: str) -> None: + def __init__(self, host: str, scheduler_uuid: str, pfdl_string: str) -> None: self.host: str = host - self.scheduler_id: str = scheduler_id + self.scheduler_uuid: str = scheduler_uuid current_timestamp: int = int(round(datetime.timestamp(datetime.now()))) self.starting_date: int = current_timestamp self.pfdl_string: str = pfdl_string @@ -63,7 +63,7 @@ def __init__(self, host: str, scheduler_id: str, pfdl_string: str) -> None: threading.Thread(target=send_post_requests, daemon=True).start() request_data = { - "order_id": scheduler_id, + "order_uuid": scheduler_uuid, "starting_date": current_timestamp, "last_update": current_timestamp, "status": ORDER_STARTED, @@ -76,13 +76,11 @@ def update(self, notification_type: NotificationType, data: Any) -> None: if notification_type == NotificationType.PETRI_NET: if not self.order_finished: content = "" - with open( - PETRI_NET_FILE_LOCATION + self.scheduler_id + "." + PETRI_NET_TYPE - ) as file: + with open(PETRI_NET_FILE_LOCATION + self.scheduler_uuid + "." + PETRI_NET_TYPE) as file: content = file.read() request_data = { - "order_id": self.scheduler_id, + "order_uuid": self.scheduler_uuid, "content": content, "type_pn": PETRI_NET_TYPE, } @@ -97,7 +95,7 @@ def update(self, notification_type: NotificationType, data: Any) -> None: self.order_finished = True request_data = { - "order_id": self.scheduler_id, + "order_uuid": self.scheduler_uuid, "log_message": log_event, "log_date": int(round(datetime.timestamp(datetime.now()))), "log_level": log_level, @@ -109,7 +107,7 @@ def update(self, notification_type: NotificationType, data: Any) -> None: order_status = ORDER_FINISHED request_data = { - "order_id": self.scheduler_id, + "order_uuid": self.scheduler_uuid, "starting_date": self.starting_date, "last_update": int(round(datetime.timestamp(datetime.now()))), "status": order_status, diff --git a/pfdl_scheduler/utils/helpers.py b/pfdl_scheduler/utils/helpers.py index 64857a1..358439c 100644 --- a/pfdl_scheduler/utils/helpers.py +++ b/pfdl_scheduler/utils/helpers.py @@ -7,7 +7,7 @@ """Helper functions used in the project (especially in the SemanticErrorChecker).""" # standard libraries -from typing import Any, Dict, List +from typing import Dict, List, Union import operator # local sources @@ -15,27 +15,6 @@ from pfdl_scheduler.model.task import Task -def check_type_of_value(value: Any, value_type: str) -> bool: - """Checks if the given value is the given type in the DSL. - - Returns: - True if the value is from the given value type. - """ - if value_type == "number": - # bool is a subclass of int so check it before - if isinstance(value, bool): - return False - return isinstance(value, (int, float)) - if value_type == "boolean": - return isinstance(value, bool) - if value_type == "string": - return isinstance(value, str) - if isinstance(value, Struct): - return value.name == value_type - # value was a string - return True - - def get_type_of_variable_list( var_list: List[str], task: Task, struct_definitions: Dict[str, Struct] ) -> str: @@ -123,6 +102,23 @@ def is_int(string: str) -> bool: return True +def cast_element(string: str) -> Union[str, int, float, bool]: + """Tries to cast the given string to a primitive datatype. + + Returns: + The casted element if casting was successful, otherwise the input string + """ + if is_int(string): + return int(string) + elif is_float(string): + return float(string) + elif is_boolean(string): + return string == "true" + elif is_string(string): + return string.replace('"', "") + return string + + def parse_operator(op: str) -> operator: """Parses a PFDL operator in form of a string into a Python executable operator func.""" ops = { diff --git a/pfdl_scheduler/utils/log_entry_observer.py b/pfdl_scheduler/utils/log_entry_observer.py index b4723b5..3775e51 100644 --- a/pfdl_scheduler/utils/log_entry_observer.py +++ b/pfdl_scheduler/utils/log_entry_observer.py @@ -36,9 +36,9 @@ class LogEntryObserver(Observer): LogLevels are based of https://docs.python.org/3/library/logging.html#logging-levels """ - def __init__(self, scheduler_id: str): + def __init__(self, scheduler_uuid: str): logging.basicConfig( - filename=LOG_FILE_LOCATION + scheduler_id + LOG_FILE_FORMAT, + filename=LOG_FILE_LOCATION + scheduler_uuid + LOG_FILE_FORMAT, encoding=LOG_FILE_ENCODING, level=logging.DEBUG, filemode=LOG_FILE_FILEMODE, diff --git a/pfdl_scheduler/utils/parsing_utils.py b/pfdl_scheduler/utils/parsing_utils.py index 8e29466..56a1454 100644 --- a/pfdl_scheduler/utils/parsing_utils.py +++ b/pfdl_scheduler/utils/parsing_utils.py @@ -8,6 +8,7 @@ # standard libraries import re +import os from typing import Tuple, Union from pathlib import Path @@ -67,17 +68,17 @@ def parse_string( return (False, None) -def parse_file(file_path: str) -> Tuple[bool, Union[None, Process], str]: - """Loads the content of the file from the given path and calls the parse_string function. +def parse_program(program: str) -> Tuple[bool, Union[None, Process], str]: + """Loads the content of the program from either the given path or the PFDL program directly and calls the parse_string function. Args: - file_path: The path to the PFDL file. + program: Either a path to the PFDL file or directly the PFDL program as a string. Returns: A boolan indicating validity of the PFDL file, the content of the file, and the process object if so, otherwise None. """ - pfdl_string = load_file(file_path) + pfdl_string, file_path = extract_content_and_file_path(program) return *parse_string(pfdl_string, file_path), pfdl_string @@ -93,6 +94,29 @@ def write_tokens_to_file(token_stream: CommonTokenStream) -> None: file.write(token_text + "\n") +def extract_content_and_file_path(program: str) -> Tuple[str, str]: + """Extracts the file path and loads the PFDL string for a given program. + + Args: + program: Either a path to the PFDL file or directly the PFDL program as a string. + + Returns: + The content of the PFDL file as a string and the file path if it is contained in given the program, + otherwise an empty string. + + """ + file_path = "" + if os.path.exists(program): + # PFDL program was passed as a file path + file_path = program + pfdl_string = load_file(program) + else: + # expect program to contain a PFDL string + pfdl_string = program + + return (pfdl_string, file_path) + + def load_file(file_path: str) -> str: """Loads the content of the file from the given path. diff --git a/pfdl_scheduler/validation/error_handler.py b/pfdl_scheduler/validation/error_handler.py index 81f248e..84a691f 100644 --- a/pfdl_scheduler/validation/error_handler.py +++ b/pfdl_scheduler/validation/error_handler.py @@ -11,9 +11,9 @@ class ErrorHandler: - """Keeps track of the total error amount in an PFDL file. + """Keeps track of the total error amount in a PFDL file. - Provides a method for printing an erro which counts the errors. + Provides a method for printing an error which counts the errors. Attributes: total_error_count: Total number of errors. diff --git a/pfdl_scheduler/validation/semantic_error_checker.py b/pfdl_scheduler/validation/semantic_error_checker.py index 431b0db..4e5086b 100644 --- a/pfdl_scheduler/validation/semantic_error_checker.py +++ b/pfdl_scheduler/validation/semantic_error_checker.py @@ -7,7 +7,7 @@ """Contains the SemanticErrorChecker class.""" # standard libraries -from typing import Dict, List, Union +from typing import Dict, List, Union, Any # 3rd party libraries from antlr4.ParserRuleContext import ParserRuleContext @@ -29,7 +29,7 @@ from pfdl_scheduler.utils import helpers # global defines -from pfdl_scheduler.parser.pfdl_tree_visitor import PRIMITIVE_DATATYPES, IN_KEY, OUT_KEY, START_TASK +from pfdl_scheduler.parser.pfdl_tree_visitor import IN_KEY, OUT_KEY class SemanticErrorChecker: @@ -105,7 +105,7 @@ def check_tasks(self) -> bool: start_task_found = False for task in self.tasks.values(): - if task.name == START_TASK: + if task.name == self.process.start_task_name: start_task_found = True # use & so all methods will be executed even if a method returns False @@ -117,7 +117,7 @@ def check_tasks(self) -> bool: valid = False if not start_task_found: - error_msg = "The file contains no 'productionTask' (Starting Point)" + error_msg = f"The file contains no '{self.process.start_task_name}' (Starting Point)" self.error_handler.print_error(error_msg, line=1, column=0, off_symbol_length=5) return False @@ -602,7 +602,6 @@ def check_for_wrong_attribute_type_in_struct( if isinstance(correct_attribute_type, str): if correct_attribute_type in self.structs: - # check for structs which has structs as attribute if isinstance(attribute, Struct): attribute.name = correct_attribute_type @@ -621,7 +620,7 @@ def check_for_wrong_attribute_type_in_struct( ) self.error_handler.print_error(error_msg, context=struct_instance.context) return False - if not helpers.check_type_of_value(attribute, correct_attribute_type): + if not self.check_type_of_value(attribute, correct_attribute_type): error_msg = ( f"Attribute '{identifier}' has the wrong type in the instantiated" f" Struct '{struct_instance.name}', expected '{correct_attribute_type}'" @@ -656,7 +655,7 @@ def check_array(self, instantiated_array: Array, array_definition: Array) -> boo value.name = array_definition.type_of_elements if not self.check_instantiated_struct_attributes(value): return False - if not helpers.check_type_of_value(value, element_type): + if not self.check_type_of_value(value, element_type): error_msg = ( f"Array has elements that does not match " f"with the defined type '{element_type}'" @@ -710,12 +709,19 @@ def check_counting_loop(self, counting_loop: CountingLoop, task: Task) -> bool: Returns: True if the Counting Loop statement is valid. """ - valid = True - for statement in counting_loop.statements: - if not self.check_statement(statement, task): - valid = False + if counting_loop.parallel: + if len(counting_loop.statements) == 1 and isinstance(counting_loop.statements[0], TaskCall): + return True + error_msg = "Only a single task is allowed in a parallel loop statement!" + self.error_handler.print_error(error_msg, context=counting_loop.context) + return False + else: + valid = True + for statement in counting_loop.statements: + if not self.check_statement(statement, task): + valid = False - return valid + return valid def check_conditional_statement(self, condition: Condition, task: Task) -> bool: """Calls check methods for the conditional statement. @@ -773,6 +779,7 @@ def check_single_expression( if not self.check_attribute_access(expression, context, task): return False + # only numbers and booleans are allowed, so check the variable type variable_type = helpers.get_type_of_variable_list(expression, task, self.structs) if not (isinstance(variable_type, str) and variable_type in ["number", "boolean"]): msg = "The given attribute can not be resolved to a boolean expression" @@ -806,7 +813,10 @@ def check_binary_operation(self, expression, context: ParserRuleContext, task: T if self.expression_is_string(left, task) and self.expression_is_string(right, task): return True - msg = "Types of Right and left side of the comparison dont match" + msg = ( + "Types of right and left side of the comparison dont match. " + "This might be caused by some of the Rule parameters that are not initialised." + ) self.error_handler.print_error(msg, context=context) return False if expression["binOp"] in ["*", "/", "+", "-"]: @@ -911,6 +921,26 @@ def variable_type_exists(self, variable_type: str) -> bool: return False return True + def check_type_of_value(self, value: Any, value_type: str) -> bool: + """Checks if the given value is the given type in the DSL. + + Returns: + True if the value is from the given value type. + """ + if value_type == "number": + # bool is a subclass of int so check it before + if isinstance(value, bool): + return False + return isinstance(value, (int, float)) + if value_type == "boolean": + return isinstance(value, bool) + if value_type == "string": + return isinstance(value, str) + if isinstance(value, Struct): + return value.name == value_type + # value was a string + return True + def instantiated_array_length_correct( self, instantiated_array: Array, array_definition: Array ) -> bool: diff --git a/scheduler_demo.py b/scheduler_demo.py index d582f16..de19463 100644 --- a/scheduler_demo.py +++ b/scheduler_demo.py @@ -37,23 +37,23 @@ def __init__(self, scheduler: Scheduler) -> None: def cb_task_started(self, task_api: TaskAPI) -> None: task_name = task_api.task.name - task_id = task_api.uuid - print("Task " + task_name + " with UUID '" + task_id + "' started") + task_uuid = task_api.uuid + print("Task " + task_name + " with UUID '" + task_uuid + "' started") def cb_service_started(self, service_api: ServiceAPI) -> None: service_name = service_api.service.name - service_id = service_api.uuid - print("Service " + service_name + " with UUID '" + service_id + "' started") + service_uuid = service_api.uuid + print("Service " + service_name + " with UUID '" + service_uuid + "' started") def cb_service_finished(self, service_api: ServiceAPI) -> None: service_name = service_api.service.name - service_id = service_api.uuid - print("Service " + service_name + " with UUID '" + service_id + "' finished") + service_uuid = service_api.uuid + print("Service " + service_name + " with UUID '" + service_uuid + "' finished") def cb_task_finished(self, task_api: TaskAPI) -> None: task_name = task_api.task.name - task_id = task_api.uuid - print("Task " + task_name + " with UUID '" + task_id + "' finished") + task_uuid = task_api.uuid + print("Task " + task_name + " with UUID '" + task_uuid + "' finished") def variable_access_function(self, var_name, task_context: TaskAPI) -> Struct: """Simulate a variable access function which returns a Struct variable. @@ -84,10 +84,10 @@ def start(self): while self.scheduler.running: input_str = str(input("Wait for input:>")) splitted = input_str.split(",") - service_id = splitted[0] + service_uuid = splitted[0] event_type = splitted[1] - event = Event(event_type=event_type, data={"service_id": service_id}) + event = Event(event_type=event_type, data={"service_uuid": service_uuid}) self.scheduler.fire_event(event) diff --git a/tests/integration_tests/test_scheduling_callbacks.py b/tests/integration_tests/test_scheduling_callbacks.py index 99d6cd2..c9bded6 100644 --- a/tests/integration_tests/test_scheduling_callbacks.py +++ b/tests/integration_tests/test_scheduling_callbacks.py @@ -86,7 +86,7 @@ def test_simple_task(self) -> None: self.assertEqual(self.task_started_triggered, ["0", "1"]) self.assertEqual(self.service_started_triggered, ["0"]) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) self.assertEqual(self.service_finished_triggered, ["0"]) self.assertEqual(self.task_finished_triggered, ["1", "0"]) @@ -97,7 +97,7 @@ def test_multiple_services(self) -> None: self.assertEqual(self.task_started_triggered, ["0", "1"]) self.assertEqual(self.service_started_triggered, ["0"]) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) self.assertEqual(self.task_started_triggered, []) self.assertEqual(self.task_finished_triggered, []) @@ -105,7 +105,7 @@ def test_multiple_services(self) -> None: self.assertEqual(self.service_finished_triggered, ["0"]) self.assertEqual(self.service_started_triggered, ["1"]) - self.fire_event(Event("service_finished", data={"service_id": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) self.assertEqual(self.service_finished_triggered, ["1"]) self.assertEqual(self.task_finished_triggered, ["1", "0"]) @@ -120,7 +120,7 @@ def test_parallel_loop(self) -> None: self.assertEqual(self.task_started_triggered, ["0"]) self.assertEqual(self.service_started_triggered, ["0"]) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) self.assertEqual(self.task_started_triggered, ["1", "2", "3"]) self.assertEqual(self.task_finished_triggered, []) @@ -128,17 +128,17 @@ def test_parallel_loop(self) -> None: self.assertEqual(self.service_finished_triggered, ["0"]) self.assertEqual(self.service_started_triggered, ["1", "2", "3"]) - self.fire_event(Event("service_finished", data={"service_id": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) self.assertEqual(self.service_finished_triggered, ["1"]) self.assertEqual(self.task_finished_triggered, ["1"]) - self.fire_event(Event("service_finished", data={"service_id": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) self.assertEqual(self.service_finished_triggered, ["2"]) self.assertEqual(self.task_finished_triggered, ["2"]) - self.fire_event(Event("service_finished", data={"service_id": "3"})) + self.fire_event(Event("service_finished", data={"service_uuid": "3"})) self.assertEqual(self.service_finished_triggered, ["3"]) self.assertEqual(self.task_finished_triggered, ["3", "0"]) @@ -149,12 +149,12 @@ def test_parallel_tasks(self) -> None: self.assertEqual(self.task_started_triggered, ["0", "1", "2"]) self.assertEqual(self.service_started_triggered, ["0", "1"]) - self.fire_event(Event("service_finished", data={"service_id": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) self.assertEqual(self.service_finished_triggered, ["1"]) self.assertEqual(self.task_finished_triggered, ["2"]) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) self.assertEqual(self.service_finished_triggered, ["0"]) self.assertEqual(self.task_finished_triggered, ["1", "0"]) @@ -168,17 +168,17 @@ def test_service_and_condition(self) -> None: self.assertEqual(self.task_started_triggered, ["0", "1"]) self.assertEqual(self.service_started_triggered, ["0"]) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) self.assertEqual(self.service_finished_triggered, ["0"]) self.assertEqual(self.task_finished_triggered, []) - self.fire_event(Event("service_finished", data={"service_id": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) self.assertEqual(self.service_finished_triggered, ["1"]) self.assertEqual(self.task_finished_triggered, []) - self.fire_event(Event("service_finished", data={"service_id": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) self.assertEqual(self.service_finished_triggered, ["2"]) self.assertEqual(self.task_finished_triggered, ["1", "0"]) @@ -190,22 +190,22 @@ def test_service_and_condition(self) -> None: self.assertEqual(self.task_started_triggered, ["0", "1"]) self.assertEqual(self.service_started_triggered, ["0"]) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) self.assertEqual(self.service_finished_triggered, ["0"]) self.assertEqual(self.task_finished_triggered, []) - self.fire_event(Event("service_finished", data={"service_id": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) self.assertEqual(self.service_finished_triggered, ["1"]) self.assertEqual(self.task_finished_triggered, []) - self.fire_event(Event("service_finished", data={"service_id": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) self.assertEqual(self.service_finished_triggered, ["2"]) self.assertEqual(self.task_finished_triggered, []) - self.fire_event(Event("service_finished", data={"service_id": "3"})) + self.fire_event(Event("service_finished", data={"service_uuid": "3"})) self.assertEqual(self.service_finished_triggered, ["3"]) self.assertEqual(self.task_finished_triggered, ["1", "0"]) @@ -215,23 +215,23 @@ def test_task_synchronisation(self) -> None: self.assertEqual(self.task_started_triggered, ["0", "1", "2"]) self.assertEqual(self.service_started_triggered, ["0", "1"]) - self.fire_event(Event("service_finished", data={"service_id": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) self.assertEqual(self.service_finished_triggered, ["1"]) self.assertEqual(self.task_finished_triggered, ["2"]) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) self.assertEqual(self.service_finished_triggered, ["0"]) self.assertEqual(self.task_finished_triggered, ["1"]) - self.fire_event(Event("service_finished", data={"service_id": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) self.assertEqual(self.service_finished_triggered, ["2"]) self.assertEqual(self.task_finished_triggered, ["3", "0"]) def test_counting_loop(self) -> None: - # service and task ids dont follow number order cause of scheduling logic for loops + # service and task uuids dont follow number order cause of scheduling logic for loops self.setup("task_with_counting_loop") # iterate 3 times @@ -241,25 +241,25 @@ def test_counting_loop(self) -> None: self.assertEqual(self.task_started_triggered, ["0", "1"]) self.assertEqual(self.service_started_triggered, ["0"]) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) self.assertEqual(self.service_started_triggered, ["1"]) self.assertEqual(self.service_finished_triggered, ["0"]) self.assertEqual(self.task_started_triggered, ["2"]) - self.fire_event(Event("service_finished", data={"service_id": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) self.assertEqual(self.service_started_triggered, ["2"]) self.assertEqual(self.service_finished_triggered, ["1"]) self.assertEqual(self.task_started_triggered, ["3"]) - self.fire_event(Event("service_finished", data={"service_id": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) self.assertEqual(self.service_started_triggered, ["3"]) self.assertEqual(self.service_finished_triggered, ["2"]) self.assertEqual(self.task_started_triggered, ["4"]) - self.fire_event(Event("service_finished", data={"service_id": "3"})) + self.fire_event(Event("service_finished", data={"service_uuid": "3"})) self.assertEqual(self.service_started_triggered, []) self.assertEqual(self.service_finished_triggered, ["3"]) @@ -277,7 +277,7 @@ def test_while_loop(self) -> None: self.assertEqual(self.task_started_triggered, ["0", "1"]) self.assertEqual(self.service_started_triggered, ["0"]) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) self.assertEqual(self.service_started_triggered, ["1"]) self.assertEqual(self.service_finished_triggered, ["0"]) @@ -285,7 +285,7 @@ def test_while_loop(self) -> None: wetness = 2 - self.fire_event(Event("service_finished", data={"service_id": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) self.assertEqual(self.service_started_triggered, ["2"]) self.assertEqual(self.service_finished_triggered, ["1"]) @@ -293,7 +293,7 @@ def test_while_loop(self) -> None: wetness = 1 - self.fire_event(Event("service_finished", data={"service_id": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) self.assertEqual(self.service_started_triggered, []) self.assertEqual(self.service_finished_triggered, ["2"]) diff --git a/tests/integration_tests/test_scheduling_marking.py b/tests/integration_tests/test_scheduling_marking.py index 48459c6..9c29fce 100644 --- a/tests/integration_tests/test_scheduling_marking.py +++ b/tests/integration_tests/test_scheduling_marking.py @@ -41,14 +41,16 @@ def setUp(self) -> None: self.task_started_triggered: List[str] = [] self.task_finished_triggered: List[str] = [] - def load_file(self, test_file_name: str) -> None: + def load_file(self, test_file_name: str, is_pfdl_string: bool) -> None: """Loads a file from the given path and parses it if it is a PFDL program.""" + if is_pfdl_string: + pfdl_program = test_file_name + else: + pfdl_program = TEST_FILE_FOLDER_PATH + test_file_name + ".pfdl" + self.scheduler = Scheduler(pfdl_program, True, False) - file_path = TEST_FILE_FOLDER_PATH + test_file_name + ".pfdl" - self.scheduler = Scheduler(file_path, True, False) - - def setup(self, test_case_name: str) -> None: - self.load_file(test_case_name) + def setup(self, test_case_name: str, is_pfdl_string: bool = False) -> None: + self.load_file(test_case_name, is_pfdl_string) self.assertFalse(self.scheduler.running) self.scheduler.start() @@ -65,7 +67,7 @@ def fire_event(self, event: Event) -> None: self.scheduler.fire_event(event) def token_in_last_place(self) -> bool: - last_place_marking = {self.scheduler.petri_net_generator.task_finished_id: MultiSet(1)} + last_place_marking = {self.scheduler.petri_net_generator.task_finished_uuid: MultiSet(1)} final_marking = Marking(last_place_marking) return self.petri_net.get_marking() == final_marking @@ -73,7 +75,21 @@ def token_in_last_place(self) -> bool: def test_simple_task(self) -> None: self.setup("simple_task") - event = Event("service_finished", data={"service_id": "0"}) + event = Event("service_finished", data={"service_uuid": "0"}) + self.fire_event(event) + + self.assertTrue(self.token_in_last_place()) + + def test_simple_task_with_pfdl_string(self) -> None: + file_path = TEST_FILE_FOLDER_PATH + "simple_task.pfdl" + file_content = "" + with open(file_path, "r", encoding="utf-8") as file: + file_content = file.read() + + # directly pass the pfdl string to the scheduler + self.setup(file_content, True) + + event = Event("service_finished", data={"service_uuid": "0"}) self.fire_event(event) self.assertTrue(self.token_in_last_place()) @@ -81,8 +97,8 @@ def test_simple_task(self) -> None: def test_multiple_services(self) -> None: self.setup("multiple_services") - self.fire_event(Event("service_finished", data={"service_id": "0"})) - self.fire_event(Event("service_finished", data={"service_id": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) self.assertTrue(self.token_in_last_place()) @@ -93,18 +109,18 @@ def test_parallel_loop(self) -> None: access_func = lambda var, context: Struct(attributes={"parts_count": 3}) self.scheduler.register_variable_access_function(access_func) - self.fire_event(Event("service_finished", data={"service_id": "0"})) - self.fire_event(Event("service_finished", data={"service_id": "1"})) - self.fire_event(Event("service_finished", data={"service_id": "2"})) - self.fire_event(Event("service_finished", data={"service_id": "3"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "3"})) self.assertTrue(self.token_in_last_place()) def test_parallel_tasks(self) -> None: self.setup("parallel_tasks") - self.fire_event(Event("service_finished", data={"service_id": "1"})) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) self.assertTrue(self.token_in_last_place()) @@ -114,9 +130,9 @@ def test_service_and_condition(self) -> None: access_func = lambda var, context: Struct(attributes={"wetness": 11}) self.scheduler.register_variable_access_function(access_func) - self.fire_event(Event("service_finished", data={"service_id": "0"})) - self.fire_event(Event("service_finished", data={"service_id": "1"})) - self.fire_event(Event("service_finished", data={"service_id": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) self.assertTrue(self.token_in_last_place()) @@ -125,34 +141,34 @@ def test_service_and_condition(self) -> None: access_func = lambda var, context: Struct(attributes={"wetness": 3}) self.scheduler.register_variable_access_function(access_func) - self.fire_event(Event("service_finished", data={"service_id": "0"})) - self.fire_event(Event("service_finished", data={"service_id": "1"})) - self.fire_event(Event("service_finished", data={"service_id": "2"})) - self.fire_event(Event("service_finished", data={"service_id": "3"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "3"})) self.assertTrue(self.token_in_last_place()) def test_task_synchronisation(self) -> None: self.setup("task_synchronisation") - self.fire_event(Event("service_finished", data={"service_id": "1"})) - self.fire_event(Event("service_finished", data={"service_id": "0"})) - self.fire_event(Event("service_finished", data={"service_id": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) self.assertTrue(self.token_in_last_place()) def test_counting_loop(self) -> None: - # service and task ids dont follow number order cause of scheduling logic for loops + # service and task uuids dont follow number order cause of scheduling logic for loops self.setup("task_with_counting_loop") # iterate 3 times access_func = lambda var, context: Struct(attributes={"parts_count": 3}) self.scheduler.register_variable_access_function(access_func) - self.fire_event(Event("service_finished", data={"service_id": "0"})) - self.fire_event(Event("service_finished", data={"service_id": "1"})) - self.fire_event(Event("service_finished", data={"service_id": "2"})) - self.fire_event(Event("service_finished", data={"service_id": "3"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "3"})) self.assertTrue(self.token_in_last_place()) @@ -164,13 +180,13 @@ def test_while_loop(self) -> None: access_func = lambda var, context: Struct(attributes={"wetness": wetness}) self.scheduler.register_variable_access_function(access_func) - self.fire_event(Event("service_finished", data={"service_id": "0"})) + self.fire_event(Event("service_finished", data={"service_uuid": "0"})) wetness = 2 - self.fire_event(Event("service_finished", data={"service_id": "1"})) + self.fire_event(Event("service_finished", data={"service_uuid": "1"})) wetness = 1 - self.fire_event(Event("service_finished", data={"service_id": "2"})) + self.fire_event(Event("service_finished", data={"service_uuid": "2"})) self.assertTrue(self.token_in_last_place()) diff --git a/tests/test_files/scheduling/task_synchronisation.pfdl b/tests/test_files/scheduling/task_synchronisation.pfdl index c8e716f..cf456b0 100644 --- a/tests/test_files/scheduling/task_synchronisation.pfdl +++ b/tests/test_files/scheduling/task_synchronisation.pfdl @@ -20,7 +20,7 @@ Struct CuttingResult sheet_parts: SheetPart[] End -Struct TransportOrderStep +Struct TransportOrderStepStruct location: string End @@ -50,14 +50,14 @@ Task cuttingTask End Task transport - Transport + TransportService In - TransportOrderStep + TransportOrderStepStruct { "location": "start" } - TransportOrderStep + TransportOrderStepStruct { "location": "goal" } -End \ No newline at end of file +End diff --git a/tests/unit_test/test_pfdl_tree_visitor.py b/tests/unit_test/test_pfdl_tree_visitor.py index b9de19f..6ad61ba 100644 --- a/tests/unit_test/test_pfdl_tree_visitor.py +++ b/tests/unit_test/test_pfdl_tree_visitor.py @@ -12,7 +12,7 @@ # standard libraries import unittest -from unittest.mock import MagicMock, Mock +from unittest.mock import MagicMock from unittest.mock import patch from pfdl_scheduler.model.parallel import Parallel @@ -20,7 +20,6 @@ # local sources from pfdl_scheduler.validation.error_handler import ErrorHandler from pfdl_scheduler.parser.PFDLParser import PFDLParser -from pfdl_scheduler.parser.PFDLParserVisitor import PFDLParserVisitor from pfdl_scheduler.model.process import Process from pfdl_scheduler.model.struct import Struct from pfdl_scheduler.model.task import Task @@ -36,10 +35,8 @@ from pfdl_scheduler.parser.pfdl_tree_visitor import ( PFDLTreeVisitor, - PRIMITIVE_DATATYPES, IN_KEY, OUT_KEY, - START_TASK, ) from antlr4 import ParserRuleContext @@ -56,7 +53,7 @@ def setUp(self) -> None: self.visitor: PFDLTreeVisitor = PFDLTreeVisitor(self.error_handler) def check_if_print_error_is_called(self, method, *args) -> None: - """Runs the given method wiht the help of a mock object and checks if print error is called. + """Runs the given method with the help of a mock object and checks if print error is called. Args: method: The method which should be tested. @@ -489,7 +486,7 @@ def test_visitWhileLoop(self): service = Service() condition = Condition() - expression = {"unop": "!", "value": "True"} + expression = {"unOp": "!", "value": "True"} with patch.object(self.visitor, "visitExpression", return_value=expression) as mock: with patch.object( self.visitor, "visitStatement", MagicMock(side_effect=[service, condition]) @@ -552,6 +549,26 @@ def test_visitCountingLoop(self): mock.assert_called_once_with(attribute_access_context) mock_2.assert_called_with(statement_context_2) + # with integer as loop limit + counting_loop_context.children = [ + statement_context_1, + statement_context_2, + ] + create_and_add_token(PFDLParser.STARTS_WITH_LOWER_C_STR, "i", counting_loop_context) + create_and_add_token(PFDLParser.INTEGER, "5", counting_loop_context) + with patch.object( + self.visitor, "visitStatement", MagicMock(side_effect=[service, condition]) + ) as mock_2: + counting_loop = self.visitor.visitCounting_loop(counting_loop_context) + self.assertEqual(counting_loop.counting_variable, "i") + self.assertEqual(counting_loop.limit, 5) + self.assertFalse(counting_loop.parallel) + self.assertEqual(len(counting_loop.statements), 2) + self.assertEqual(counting_loop.statements[0], service) + self.assertEqual(counting_loop.statements[1], condition) + self.assertEqual(counting_loop.context, counting_loop_context) + mock_2.assert_called_with(statement_context_2) + def test_visitCondition(self): condition_context = PFDLParser.ConditionContext(None) expression_context = PFDLParser.ExpressionContext(None) @@ -564,7 +581,7 @@ def test_visitCondition(self): passed_statements = [service, while_loop] - expression = {"unop": "!", "value": "True"} + expression = {"unOp": "!", "value": "True"} # without failed with patch.object(self.visitor, "visitExpression", return_value=expression) as mock: @@ -651,51 +668,75 @@ def test_visitVariable_definition(self): variable_definition_context = PFDLParser.Variable_definitionContext(None) # without array variable_definition_context.children = [ - PFDLParser.PrimitiveContext(None), + PFDLParser.Variable_typeContext(None), ] create_and_add_token( PFDLParser.STARTS_WITH_LOWER_C_STR, "variable", variable_definition_context ) - with patch.object(self.visitor, "visitPrimitive", return_value="number"): + with patch.object(self.visitor, "visitVariable_type", return_value="number"): self.assertEqual( self.visitor.visitVariable_definition(variable_definition_context), ("variable", "number"), ) + def test_visitVariable_type(self): + variable_type_context = PFDLParser.Variable_typeContext(None) + + # without array + variable_type_context.children = [ + PFDLParser.PrimitiveContext(None), + ] + with patch.object(self.visitor, "visitPrimitive", return_value="string"): + with patch.object(self.visitor, "initializeArray", return_value=-1) as mock: + self.assertEqual(self.visitor.visitVariable_type(variable_type_context), "string") + + # no array to initialize + mock.assert_not_called() + # with array - variable_definition_context.children = [ + array_context = PFDLParser.ArrayContext(None) + variable_type_context.children = [ PFDLParser.PrimitiveContext(None), - PFDLParser.ArrayContext(None), + array_context, ] - create_and_add_token( - PFDLParser.STARTS_WITH_LOWER_C_STR, "variable", variable_definition_context - ) with patch.object(self.visitor, "visitPrimitive", return_value="string"): - # without length - with patch.object(self.visitor, "visitArray", return_value=-1): - self.assertEqual( - self.visitor.visitVariable_definition(variable_definition_context), - ("variable", Array("string")), - ) - # with length - with patch.object(self.visitor, "visitArray", return_value=10): - array = Array("string") - array.length = 10 - self.assertEqual( - self.visitor.visitVariable_definition(variable_definition_context), - ("variable", array), - ) - # with invalid length (string) - with patch.object(self.visitor, "visitArray", return_value="not a number"): + with patch.object( + self.visitor, "initializeArray", return_value=Array("string") + ) as mock: self.assertEqual( - self.visitor.visitVariable_definition(variable_definition_context), - ("variable", Array("string")), - ) - self.check_if_print_error_is_called( - self.visitor.visitVariable_definition, variable_definition_context + self.visitor.visitVariable_type(variable_type_context), Array("string") ) + mock.assert_called_with(array_context, "string") + + def test_initializeArray(self): + array_context = PFDLParser.ArrayContext(None) + variable_type = "string" + + # without length + with patch.object(self.visitor, "visitArray", return_value=-1): + self.assertEqual( + self.visitor.initializeArray(array_context, variable_type), Array("string") + ) + + # with length + with patch.object(self.visitor, "visitArray", return_value=10): + expected_array = Array("string") + expected_array.length = 10 + self.assertEqual( + self.visitor.initializeArray(array_context, variable_type), expected_array + ) + + # with invalid length (string) + with patch.object(self.visitor, "visitArray", return_value="not a number"): + self.assertEqual( + self.visitor.initializeArray(array_context, variable_type), Array("string") + ) + self.check_if_print_error_is_called( + self.visitor.initializeArray, array_context, variable_type + ) + def test_visitPrimitive(self): primitive_context = PFDLParser.PrimitiveContext(None) create_and_add_token(PFDLParser.NUMBER_P, "number", primitive_context) @@ -814,9 +855,9 @@ def test_visitExpression(self): ): expression = self.visitor.visitExpression(expression_context) self.assertEqual(len(expression), 2) - self.assertTrue("unop" in expression) + self.assertTrue("unOp" in expression) self.assertTrue("value" in expression) - self.assertEqual(expression, {"unop": "!", "value": "value"}) + self.assertEqual(expression, {"unOp": "!", "value": "value"}) # case length = 3 expression_context.children = [ diff --git a/tests/unit_test/test_semantic_error_checker.py b/tests/unit_test/test_semantic_error_checker.py index b848e30..607d128 100644 --- a/tests/unit_test/test_semantic_error_checker.py +++ b/tests/unit_test/test_semantic_error_checker.py @@ -1714,10 +1714,10 @@ def test_check_expression(self): self.assertFalse(self.checker.check_expression(variable_list_2, None, task)) self.assertTrue( - self.checker.check_expression({"unop": "!", "value": variable_list}, None, task) + self.checker.check_expression({"unOp": "!", "value": variable_list}, None, task) ) self.assertTrue( - self.checker.check_expression({"unop": "!", "value": variable_list_3}, None, task) + self.checker.check_expression({"unOp": "!", "value": variable_list_3}, None, task) ) expression = { @@ -1726,7 +1726,7 @@ def test_check_expression(self): "right": {"left": 5, "binOp": "<", "right": variable_list}, } self.assertTrue( - self.checker.check_expression({"unop": "!", "value": expression}, None, task) + self.checker.check_expression({"unOp": "!", "value": expression}, None, task) ) expression = { "left": variable_list_3, @@ -1734,7 +1734,7 @@ def test_check_expression(self): "right": {"left": "(", "binOp": "true", "right": ")"}, } self.assertTrue( - self.checker.check_expression({"unop": "!", "value": expression}, None, task) + self.checker.check_expression({"unOp": "!", "value": expression}, None, task) ) expression = { "left": variable_list_3, @@ -1746,14 +1746,14 @@ def test_check_expression(self): }, } self.assertTrue( - self.checker.check_expression({"unop": "!", "value": expression}, None, task) + self.checker.check_expression({"unOp": "!", "value": expression}, None, task) ) self.assertFalse( - self.checker.check_expression({"unop": "!", "value": variable_list_2}, None, task) + self.checker.check_expression({"unOp": "!", "value": variable_list_2}, None, task) ) self.check_if_print_error_is_called( - self.checker.check_expression, {"unop": "!", "value": variable_list_2}, None, task + self.checker.check_expression, {"unOp": "!", "value": variable_list_2}, None, task ) expression = { @@ -1762,10 +1762,10 @@ def test_check_expression(self): "right": {"left": 5, "binOp": "<", "right": variable_list}, } self.assertFalse( - self.checker.check_expression({"unop": "!", "value": expression}, None, task) + self.checker.check_expression({"unOp": "!", "value": expression}, None, task) ) self.check_if_print_error_is_called( - self.checker.check_expression, {"unop": "!", "value": expression}, None, task + self.checker.check_expression, {"unOp": "!", "value": expression}, None, task ) expression = { @@ -1774,10 +1774,10 @@ def test_check_expression(self): "right": {"left": "True", "binOp": "<", "right": variable_list}, } self.assertFalse( - self.checker.check_expression({"unop": "!", "value": expression}, None, task) + self.checker.check_expression({"unOp": "!", "value": expression}, None, task) ) self.check_if_print_error_is_called( - self.checker.check_expression, {"unop": "!", "value": expression}, None, task + self.checker.check_expression, {"unOp": "!", "value": expression}, None, task ) expression = { @@ -1790,10 +1790,10 @@ def test_check_expression(self): }, } self.assertFalse( - self.checker.check_expression({"unop": "!", "value": expression}, None, task) + self.checker.check_expression({"unOp": "!", "value": expression}, None, task) ) self.check_if_print_error_is_called( - self.checker.check_expression, {"unop": "!", "value": expression}, None, task + self.checker.check_expression, {"unOp": "!", "value": expression}, None, task ) self.assertTrue( @@ -1990,10 +1990,10 @@ def test_check_unary_operation(self): variable_list_3 = ["variable", "attribute_3"] self.assertTrue( - self.checker.check_unary_operation({"unop": "!", "value": variable_list}, None, task) + self.checker.check_unary_operation({"unOp": "!", "value": variable_list}, None, task) ) self.assertTrue( - self.checker.check_unary_operation({"unop": "!", "value": variable_list_3}, None, task) + self.checker.check_unary_operation({"unOp": "!", "value": variable_list_3}, None, task) ) expression = { @@ -2002,7 +2002,7 @@ def test_check_unary_operation(self): "right": {"left": 5, "binOp": "<", "right": variable_list}, } self.assertTrue( - self.checker.check_unary_operation({"unop": "!", "value": expression}, None, task) + self.checker.check_unary_operation({"unOp": "!", "value": expression}, None, task) ) expression = { "left": variable_list_3, @@ -2010,7 +2010,7 @@ def test_check_unary_operation(self): "right": {"left": "(", "binOp": "true", "right": ")"}, } self.assertTrue( - self.checker.check_unary_operation({"unop": "!", "value": expression}, None, task) + self.checker.check_unary_operation({"unOp": "!", "value": expression}, None, task) ) expression = { "left": variable_list_3, @@ -2022,11 +2022,11 @@ def test_check_unary_operation(self): }, } self.assertTrue( - self.checker.check_unary_operation({"unop": "!", "value": expression}, None, task) + self.checker.check_unary_operation({"unOp": "!", "value": expression}, None, task) ) self.assertFalse( - self.checker.check_unary_operation({"unop": "!", "value": variable_list_2}, None, task) + self.checker.check_unary_operation({"unOp": "!", "value": variable_list_2}, None, task) ) expression = { "left": variable_list_2, @@ -2034,7 +2034,7 @@ def test_check_unary_operation(self): "right": {"left": 5, "binOp": "<", "right": variable_list}, } self.assertFalse( - self.checker.check_unary_operation({"unop": "!", "value": expression}, None, task) + self.checker.check_unary_operation({"unOp": "!", "value": expression}, None, task) ) expression = { "left": variable_list_3, @@ -2042,7 +2042,7 @@ def test_check_unary_operation(self): "right": {"left": "True", "binOp": "<", "right": variable_list}, } self.assertFalse( - self.checker.check_unary_operation({"unop": "!", "value": expression}, None, task) + self.checker.check_unary_operation({"unOp": "!", "value": expression}, None, task) ) expression = { "left": variable_list_3, @@ -2054,7 +2054,7 @@ def test_check_unary_operation(self): }, } self.assertFalse( - self.checker.check_unary_operation({"unop": "!", "value": expression}, None, task) + self.checker.check_unary_operation({"unOp": "!", "value": expression}, None, task) ) def test_check_binary_operation(self): diff --git a/validate_pfdl_file.py b/validate_pfdl_file.py index cc4e25f..7016c2f 100644 --- a/validate_pfdl_file.py +++ b/validate_pfdl_file.py @@ -10,7 +10,7 @@ import argparse -from pfdl_scheduler.utils.parsing_utils import parse_file +from pfdl_scheduler.utils.parsing_utils import parse_program EXAMPLES_PATH = "examples/" @@ -22,7 +22,7 @@ def main(): args = parser.parse_args() if args.file_path != None: - parse_file(args.file_path) + parse_program(args.file_path) else: folder_path = EXAMPLES_PATH if args.folder_path != None: @@ -32,7 +32,7 @@ def main(): for example_filename in example_filenames: print("File " + example_filename + " parsed:") - parse_file(folder_path + example_filename) + parse_program(folder_path + example_filename) print("\n")