diff --git a/src/HerbGrammar.jl b/src/HerbGrammar.jl index 927b56f..a4814da 100644 --- a/src/HerbGrammar.jl +++ b/src/HerbGrammar.jl @@ -72,6 +72,8 @@ export read_pcsg, add_rule!, remove_rule!, - cleanup_removed_rules! + cleanup_removed_rules!, + + RuleNodeTypeCheckError end # module HerbGrammar diff --git a/src/nodelocation.jl b/src/nodelocation.jl index 424d69d..8175194 100644 --- a/src/nodelocation.jl +++ b/src/nodelocation.jl @@ -28,19 +28,34 @@ function Base.get(root::AbstractRuleNode, loc::NodeLoc) end end +struct RuleNodeTypeCheckError <: Exception + message::String +end + +Base.showerror(io::IO, e::RuleNodeTypeCheckError) = print(io, e.message) """ insert!(loc::NodeLoc, rulenode::RuleNode) Replaces the subtree pointed to by loc with the given rulenode. """ -function Base.insert!(root::RuleNode, loc::NodeLoc, rulenode::RuleNode) - parent, i = loc.parent, loc.i - if loc.i > 0 - parent.children[i] = rulenode - else - root.ind = rulenode.ind - root._val = rulenode._val - root.children = rulenode.children - end - return root +function Base.insert!(root::RuleNode, loc::NodeLoc, rulenode::RuleNode, grammar::AbstractGrammar) + subtree = get(root, loc) + return_type_subtree = return_type(grammar, subtree.ind) + return_type_replacement = return_type(grammar, rulenode.ind) + # if the types do not match throw an error + if return_type_replacement !== return_type_subtree + throw(RuleNodeTypeCheckError("The provided replacement node does have the correct type to be replaced in the tree. + The subtree of the current tree expects a rule with type $return_type_subtree , but + the provided replacement has type $return_type_replacement")) + end + + parent, i = loc.parent, loc.i + if loc.i > 0 + parent.children[i] = rulenode + else + root.ind = rulenode.ind + root._val = rulenode._val + root.children = rulenode.children + end + return root end diff --git a/test/test_rulenode_operators.jl b/test/test_rulenode_operators.jl index dee0c14..0cfa59d 100644 --- a/test/test_rulenode_operators.jl +++ b/test/test_rulenode_operators.jl @@ -1,5 +1,5 @@ module SomeDefinitions - a_variable_that_is_defined = 7 +a_variable_that_is_defined = 7 end @testset verbose = true "RuleNode Operators" begin @@ -15,4 +15,30 @@ end @test !isvariable(g₁, RuleNode(7, g₁), SomeDefinitions) @test isvariable(g₁, RuleNode(7, g₁)) end + @testset "Check typecheck for insert!" begin + g = @cfgrammar begin + Start = Int + Int + Int = 1 + Int = 2 + B = "notgood" + end + + root = RuleNode(1, [RuleNode(2), RuleNode(2)]) # 1 + 1 + replacement = RuleNode(4) # notgood + @test rulenode2expr(replacement, g) == :("notgood") + location = NodeLoc(root, 1) # first child + + # attempting to replace type Int by type B should not work + @test_throws HerbGrammar.RuleNodeTypeCheckError insert!(root, location, replacement, g) + + root = RuleNode(1, [RuleNode(2), RuleNode(2)]) # 1 + 1 + replacement = RuleNode(3) # number 2 + @test rulenode2expr(replacement, g) == :2 + location = NodeLoc(root, 1) # first child + + # replacing from (1 + 1) -> (2 + 1) should work + insert!(root, location, replacement, g) + + @test rulenode2expr(root, g) == :(2 + 1) + end end