bool Or::transform( MergeGraph& merge_graph, const CallFactory& call_factory, NodeReporter reporter ) { node_p me = shared_from_this(); bool result = false; node_list_t to_remove; BOOST_FOREACH(const node_p& child, children()) { if (child->is_literal()) { if (! child->eval(EvalContext()).empty()) { node_p replacement = c_true; merge_graph.replace(me, replacement); return true; } else { to_remove.push_back(child); } } } BOOST_FOREACH(const node_p& child, to_remove) { result = true; merge_graph.remove(me, child); }
TEST_F(TestMergeGraph, DoubleReplace) { MergeGraph g; node_p n = parse("(A (B (C)))"); node_p m = parse("(B (C))"); node_p m2 = parse("(A)"); node_p m3 = parse("(B)"); size_t n_i = 0; size_t m_i = 0; EXPECT_NO_THROW(n_i = g.add_root(n)); EXPECT_NO_THROW(m_i = g.add_root(m)); EXPECT_NO_THROW(g.replace(m, m2)); EXPECT_NO_THROW(g.replace(m2, m3)); EXPECT_EQ("(A (B))", g.root(n_i)->to_s()); EXPECT_EQ("(B)", g.root(m_i)->to_s()); EXPECT_TRUE(g.write_validation_report(cerr)); EXPECT_EQ(m3, g.find_transform(m)); g.clear_transform_record(); EXPECT_THROW(g.find_transform(m), IronBee::enoent); }
void pre_eval_graph( reporter_t reporter, MergeGraph& graph, Environment environment ) { bfs_down( graph.roots().first, graph.roots().second, boost::make_function_output_iterator( pre_eval_graph_helper(reporter, environment) ) ); }
TEST_F(TestMergeGraph, KnownRoot) { MergeGraph g; node_p n = parse("(A (B (C)) (B (C)))"); node_p m = parse("(B (C))"); node_p backup_m = m; EXPECT_NO_THROW(g.add_root(n)); EXPECT_NO_THROW(g.add_root(m)); EXPECT_NE(backup_m, m); EXPECT_TRUE(g.write_validation_report(cerr)); }
TEST_F(TestMergeGraph, Easy) { node_p n = parse("(A (B (C)))"); MergeGraph g; size_t n_i = 0; EXPECT_TRUE(g.empty()); EXPECT_NO_THROW(n_i = g.add_root(n)); EXPECT_EQ(n, g.root(n_i)); EXPECT_EQ(1UL, g.root_indices(n).size()); EXPECT_EQ(n_i, *g.root_indices(n).begin()); EXPECT_FALSE(g.empty()); EXPECT_TRUE(g.write_validation_report(cerr)); }
TEST_F(TestMergeGraph, Basic) { node_p n = parse("(A (B (C)) (B (C)))"); MergeGraph g; size_t n_i = 0; EXPECT_NO_THROW(n_i = g.add_root(n)); EXPECT_EQ(n, g.root(n_i)); EXPECT_EQ(1UL, g.root_indices(n).size()); EXPECT_EQ(n_i, *g.root_indices(n).begin()); EXPECT_EQ(3UL, num_descendants(n)); EXPECT_TRUE(g.write_validation_report(cerr)); }
TEST_F(TestMergeGraph, ReplaceLoop) { MergeGraph g; node_p n = parse("(A (B (C)))"); node_p m = parse("(B (C))"); node_p m2 = parse("(A (B (C)))"); size_t n_i = 0; size_t m_i = 0; EXPECT_NO_THROW(n_i = g.add_root(n)); EXPECT_NO_THROW(m_i = g.add_root(m)); EXPECT_TRUE(g.write_validation_report(cerr)); EXPECT_NO_THROW(g.replace(m, m2)); EXPECT_EQ("(A (A (B (C))))", g.root(n_i)->to_s()); EXPECT_EQ("(A (B (C)))", g.root(m_i)->to_s()); EXPECT_TRUE(g.write_validation_report(cerr)); EXPECT_EQ(m2, g.find_transform(m)); }
TEST_F(TestMergeGraph, AddLoop) { MergeGraph g; node_p n = parse("(A (B (C)))"); node_p m = parse("(B (C))"); node_p o = parse("(B (C))"); size_t n_i = 0; size_t m_i = 0; EXPECT_NO_THROW(n_i = g.add_root(n)); EXPECT_NO_THROW(m_i = g.add_root(m)); EXPECT_NO_THROW(g.add(m, o)); EXPECT_EQ("(A (B (C) (B (C))))", g.root(n_i)->to_s()); EXPECT_EQ("(B (C) (B (C)))", g.root(m_i)->to_s()); EXPECT_TRUE(g.write_validation_report(cerr)); }
bool Template::transform( MergeGraph& merge_graph, const CallFactory& call_factory, Environment environment, NodeReporter reporter ) { node_p me = shared_from_this(); // Construct map of argument name to children. typedef map<string, node_p> arg_map_t; arg_map_t arg_map; { template_arg_list_t::const_iterator arg_i = m_args.begin(); node_list_t::const_iterator children_i = children().begin(); while (arg_i != m_args.end() && children_i != children().end()) { arg_map.insert(make_pair(*arg_i, tree_copy(*children_i, call_factory))); ++arg_i; ++children_i; } if (arg_i != m_args.end() || children_i != children().end()) { reporter.error( "Number of children not equal to number of arguments. " "Should have been caught in validation." ); return false; } } // Construct copy of body to replace me with. node_p replacement = tree_copy(m_body, call_factory); // Special case. Body might be itself a ref node. { string top_ref = template_ref(m_body); if (! top_ref.empty()) { arg_map_t::const_iterator arg_i = arg_map.find(top_ref); if (arg_i == arg_map.end()) { reporter.error( "Reference to \"" + top_ref + "\" but not such " "argument to template " + name() = "." ); return false; } node_p replacement = arg_i->second; merge_graph.replace(me, replacement); merge_graph.add_origin( replacement, m_origin_prefix + m_body->to_s() ); return true; } } // Replace arguments. typedef map<node_p, string> origin_info_t; origin_info_t origin_info; { node_list_t todo; todo.push_back(replacement); while (! todo.empty()) { node_p n = todo.front(); todo.pop_front(); // Enforce that we are working on a tree, not a dag. assert(n->parents().size() <= 1); string ref_param = template_ref(n); if (! ref_param.empty()) { arg_map_t::const_iterator arg_i = arg_map.find(ref_param); if (arg_i == arg_map.end()) { reporter.error( "Reference to \"" + ref_param + "\" but not such " "argument to template " + name() = "." ); continue; } node_p arg = arg_i->second; n->parents().front().lock()->replace_child(n, arg); origin_info[arg] = m_origin_prefix + n->to_s(); } else { copy( n->children().begin(), n->children().end(), back_inserter(todo) ); origin_info[n] = m_origin_prefix + n->to_s(); } } } // Replace with body. merge_graph.replace(me, replacement); BOOST_FOREACH(origin_info_t::const_reference v, origin_info) { merge_graph.add_origin(v.first, v.second); }
TEST_F(TestMergeGraph, MultipleRoots) { MergeGraph g; node_p n = parse("(A (B (C)) (B (C)))"); size_t n_i = 0; node_p m = parse("(C (B (C)))"); size_t m_i = 0; EXPECT_NO_THROW(n_i = g.add_root(n)); EXPECT_NO_THROW(m_i = g.add_root(m)); EXPECT_EQ(n, g.root(n_i)); EXPECT_EQ(1UL, g.root_indices(n).size()); EXPECT_EQ(n_i, *g.root_indices(n).begin()); EXPECT_EQ(m, g.root(m_i)); EXPECT_EQ(1UL, g.root_indices(m).size()); EXPECT_EQ(m_i, *g.root_indices(m).begin()); EXPECT_EQ(2UL, g.size()); EXPECT_EQ(n, *g.roots().first); EXPECT_EQ(m, *boost::next(g.roots().first)); EXPECT_TRUE(g.write_validation_report(cerr)); }
TEST_F(TestMergeGraph, Remove) { MergeGraph g; node_p n = parse("(A (B (C)))"); node_p m = parse("(B (C))"); size_t n_i = 0; size_t m_i = 0; EXPECT_NO_THROW(n_i = g.add_root(n)); EXPECT_NO_THROW(m_i = g.add_root(m)); node_p to_remove = parse("(C)"); EXPECT_NO_THROW(g.remove(m, to_remove)); EXPECT_EQ("(A (B))", g.root(n_i)->to_s()); EXPECT_EQ("(B)", g.root(m_i)->to_s()); EXPECT_TRUE(g.write_validation_report(cerr)); EXPECT_NO_THROW(g.remove(n, m)); EXPECT_EQ(2UL, g.size()); EXPECT_EQ("(A)", g.root(n_i)->to_s()); EXPECT_EQ("(B)", g.root(m_i)->to_s()); EXPECT_TRUE(g.write_validation_report(cerr)); EXPECT_FALSE(g.find_transform(to_remove)); }
bool Template::transform( MergeGraph& merge_graph, const CallFactory& call_factory, NodeReporter reporter ) { node_p me = shared_from_this(); // Construct map of argument name to children. typedef map<string, node_p> arg_map_t; arg_map_t arg_map; { template_arg_list_t::const_iterator arg_i = m_args.begin(); node_list_t::const_iterator children_i = children().begin(); while (arg_i != m_args.end() && children_i != children().end()) { arg_map.insert(make_pair(*arg_i, *children_i)); ++arg_i; ++children_i; } if (arg_i != m_args.end() || children_i != children().end()) { reporter.error( "Number of children not equal to number of arguments. " "Should have been caught in validation." ); return false; } } // Construct copy of body to replace me with. node_p replacement = tree_copy(m_body, call_factory); // Special case. Body might be itself a ref node. { string top_ref = template_ref(m_body); if (! top_ref.empty()) { arg_map_t::const_iterator arg_i = arg_map.find(top_ref); if (arg_i == arg_map.end()) { reporter.error( "Reference to \"" + top_ref + "\" but not such " "argument to template " + name() = "." ); return false; } node_p replacement = arg_i->second; merge_graph.replace(me, replacement); return true; } } // Make list of all descendants. We don't want to iterate over the // replacements, so we make the entire list in advance. list<node_p> to_transform; bfs_down(replacement, back_inserter(to_transform)); BOOST_FOREACH(const node_p& node, to_transform) { BOOST_FOREACH(const node_p& child, node->children()) { string ref_param = template_ref(child); if (! ref_param.empty()) { arg_map_t::const_iterator arg_i = arg_map.find(ref_param); if (arg_i == arg_map.end()) { reporter.error( "Reference to \"" + ref_param + "\" but not such " "argument to template " + name() = "." ); continue; } node->replace_child(child, arg_i->second); } } }