def execute_banana_string(banana, driver=None, emitter=emit.PrintEmitter()): """ Execute the provided banana string. It will run the parse phase, and the typechecker. :type banana: str :param banana: The string to parse and type check. :type driver: monasca_analytics.spark.driver.DriverExecutor | None :param driver: Driver that will manage the created components and connect them together. :type emitter: emit.Emitter :param emitter: Emitter for reporting errors/warning. """ try: # Convert the grammar into an AST parser = grammar.banana_grammar(emitter) ast = parser.parse(banana) # Compute the type table for the given AST type_table = typeck.typeck(ast) # Remove from the tree path that are "dead" deadpathck.deadpathck(ast, type_table, emitter) # Check that there's at least one path to be executed deadpathck.contains_at_least_one_path_to_a_sink(ast, type_table) # Evaluate the script if driver is not None: ev.eval_ast(ast, type_table, driver) except exception.BananaException as err: emitter.emit_error(err.get_span(), str(err)) except p.ParseSyntaxException as err: emitter.emit_error(span_util.from_pyparsing_exception(err), err.msg) except p.ParseFatalException as err: emitter.emit_error(span_util.from_pyparsing_exception(err), err.msg) except p.ParseException as err: emitter.emit_error(span_util.from_pyparsing_exception(err), err.msg)
def compute_type_table(banana): """ Compute the type table for the provided banana string if possible. :type banana: str :param banana: The string to parse and type check. """ # Convert the grammar into an AST parser = grammar.banana_grammar() ast = parser.parse(banana) # Compute the type table for the given AST return typeck.typeck(ast)
def test_banana_should_pass_when_more_source_sink(self): banana_str = "" +\ "a = CloudMarkovChainSource()\n" +\ "b = StdoutSink()\n" +\ "c = CloudIngestor()\n" +\ "d = LiNGAM()\n" +\ "a -> c -> d -> b" # Convert the grammar into an AST parser = grammar.banana_grammar() ast = parser.parse(banana_str) # Compute the type table for the given AST type_table = typeck.typeck(ast) # Remove from the tree path that are "dead" deadpathck.deadpathck(ast, type_table) deadpathck.contains_at_least_one_path_to_a_sink(ast, type_table) # We should reach this line. self.assertTrue(True)
def compute_evaluation_context(banana, cb=lambda *a, **k: None): """ Compute the evaluation context for the provided banana string. :type banana_str: str :param banana_str: The string to parse and type check. :param cb: Callback called after each statement """ parser = grammar.banana_grammar() ast = parser.parse(banana) type_table = typeck.typeck(ast) context = ctx.EvaluationContext() def custom_cb(_type, lhs, value): cb(context, _type, lhs, value) ev.eval_statements_generic(ast.statements, type_table, context, custom_cb)
def test_banana_should_fail_when_no_sink(self): banana_str = "" +\ "a = CloudMarkovChainSource()\n" +\ "b = StdoutSink()\n" +\ "c = CloudIngestor()\n" +\ "d = LiNGAM()\n" +\ "a -> c -> d" # Convert the grammar into an AST parser = grammar.banana_grammar() ast = parser.parse(banana_str) # Compute the type table for the given AST type_table = typeck.typeck(ast) # Remove from the tree path that are "dead" deadpathck.deadpathck(ast, type_table) self.assertRaises(exception.BananaNoFullPath, deadpathck.contains_at_least_one_path_to_a_sink, ast, type_table)
def test_banana_should_not_remove_anything(self): banana_str = "" +\ "a = CloudMarkovChainSource()\n" +\ "b = StdoutSink()\n" +\ "c = CloudIngestor()\n" +\ "d = LiNGAM()\n" +\ "a -> c -> d -> b" emitter = CustomEmitter() # Convert the grammar into an AST parser = grammar.banana_grammar(emitter) ast = parser.parse(banana_str) # Compute the type table for the given AST type_table = typeck.typeck(ast) # Remove from the tree path that are "dead" deadpathck.deadpathck(ast, type_table, emitter) self.assertEqual(emitter.nb_errors, 0) self.assertEqual(emitter.nb_warnings, 0) self.assertEqual(len(ast.components), 4) self.assertEqual(len(list(ast.connections.connections)), 3)
def test_banana_should_not_remove_anything(self): banana_str = "" +\ "a = CloudMarkovChainSource()\n" +\ "b = StdoutSink()\n" +\ "c = CloudIngestor()\n" +\ "d = LiNGAM()\n" +\ "a -> c -> d -> b" emitter = CustomEmitter() # Convert the grammar into an AST parser = grammar.banana_grammar(emitter) ast = parser.parse(banana_str) # Compute the type table for the given AST type_table = typeck.typeck(ast) # Remove from the tree path that are "dead" deadpathck.deadpathck(ast, type_table, emitter) self.assertEqual(emitter.nb_errors, 0) self.assertEqual(emitter.nb_warnings, 0) self.assertEqual(len(ast.components), 4) self.assertEqual(len(list(ast.connections.connections)), 3)
def try_compute_type_table(banana): """ Compute the type table for the provided banana string if possible. Does not throw any exception if it fails. :type banana: str :param banana: The string to parse and type check. """ try: # Convert the grammar into an AST parser = grammar.banana_grammar() ast = parser.parse(banana) # Compute the type table for the given AST return typeck.typeck(ast) except exception.BananaException: return None except p.ParseSyntaxException: return None except p.ParseFatalException: return None except p.ParseException: return None
def upgrade_test_case(): grammar = banana_grammar() regex_raise = re.compile("#(?: )*RAISE(?: )*([^\n]+)") regex_ast_eq = re.compile("#(?: )*AST_EQ(?: )(?: )*([^\n]+)") regex_stmt_eq = re.compile("#(?: )*STMT_EQ(?: )(?: )*([^\n]+)") regex_conn_eq = re.compile("#(?: )*CONN_EQ(?: )(?: )*([^\n]+)") for root, dirs, files in os.walk('./banana/grammar/should_pass'): for filename in files: name_no_ext, _ = os.path.splitext(filename) _has_some_file_that_should["pass"] = True with open(os.path.join(root, filename), 'r') as f: content = f.read() expected_ast = regex_ast_eq.search(content) if expected_ast is not None: expected_ast = expected_ast.group(1) expected_stmt = regex_stmt_eq.search(content) if expected_stmt is not None: expected_stmt = expected_stmt.group(1) expected_conn = regex_conn_eq.search(content) if expected_conn is not None: expected_conn = expected_conn.group(1) def create_test(test_str, expect_ast, expect_stmt, exp_conn): def should_pass(self): tree = grammar.parse(test_str) if expect_ast is not None: self.assertEqual(str(tree), expect_ast) if expect_stmt is not None: self.assertEqual(tree.statements_to_str(), expect_stmt) if exp_conn is not None: self.assertEqual(str(tree.connections), exp_conn) if exp_conn is None and expect_ast is None and\ expect_stmt is None: raise Exception("Expected at least one check!") should_pass.__name__ = "test_banana_pass_" + name_no_ext return should_pass setattr(GrammarTestCase, "test_banana_pass_" + name_no_ext, create_test(content, expected_ast, expected_stmt, expected_conn)) for root, dirs, files in os.walk('./banana/grammar/should_fail'): for filename in files: name_no_ext, _ = os.path.splitext(filename) _has_some_file_that_should["fail"] = True with open(os.path.join(root, filename), 'r') as f: content = f.read() def create_test(test_str): def should_fail(self): expected_error = regex_raise.search(test_str).group(1) expected_exception = get_exception_from_str( expected_error) self.assertRaises( expected_exception, grammar.parse, test_str) should_fail.__name__ = "test_banana_fail_" + name_no_ext return should_fail setattr(GrammarTestCase, "test_banana_fail_" + name_no_ext, create_test(content))
def upgrade_test_case(): grammar = banana_grammar() regex_raise = re.compile("#(?: )*RAISE(?: )*([^\n]+)") regex_ast_eq = re.compile("#(?: )*AST_EQ(?: )(?: )*([^\n]+)") regex_stmt_eq = re.compile("#(?: )*STMT_EQ(?: )(?: )*([^\n]+)") regex_conn_eq = re.compile("#(?: )*CONN_EQ(?: )(?: )*([^\n]+)") for root, dirs, files in os.walk('./banana/grammar/should_pass'): for filename in files: name_no_ext, _ = os.path.splitext(filename) _has_some_file_that_should["pass"] = True with open(os.path.join(root, filename), 'r') as f: content = f.read() expected_ast = regex_ast_eq.search(content) if expected_ast is not None: expected_ast = expected_ast.group(1) expected_stmt = regex_stmt_eq.search(content) if expected_stmt is not None: expected_stmt = expected_stmt.group(1) expected_conn = regex_conn_eq.search(content) if expected_conn is not None: expected_conn = expected_conn.group(1) def create_test(test_str, expect_ast, expect_stmt, exp_conn): def should_pass(self): tree = grammar.parse(test_str) if expect_ast is not None: self.assertEqual(str(tree), expect_ast) if expect_stmt is not None: self.assertEqual(tree.statements_to_str(), expect_stmt) if exp_conn is not None: self.assertEqual(str(tree.connections), exp_conn) if exp_conn is None and expect_ast is None and\ expect_stmt is None: raise Exception("Expected at least one check!") should_pass.__name__ = "test_banana_pass_" + name_no_ext return should_pass setattr( GrammarTestCase, "test_banana_pass_" + name_no_ext, create_test(content, expected_ast, expected_stmt, expected_conn)) for root, dirs, files in os.walk('./banana/grammar/should_fail'): for filename in files: name_no_ext, _ = os.path.splitext(filename) _has_some_file_that_should["fail"] = True with open(os.path.join(root, filename), 'r') as f: content = f.read() def create_test(test_str): def should_fail(self): expected_error = regex_raise.search(test_str).group(1) expected_exception = get_exception_from_str( expected_error) self.assertRaises(expected_exception, grammar.parse, test_str) should_fail.__name__ = "test_banana_fail_" + name_no_ext return should_fail setattr(GrammarTestCase, "test_banana_fail_" + name_no_ext, create_test(content))