From 14c4b9988fe7321e2f796f92416cffec9389921c Mon Sep 17 00:00:00 2001 From: LoLo5689 Date: Fri, 15 Nov 2024 13:34:43 +0100 Subject: [PATCH 1/6] expr2rulenode --- src/rulenode_operators.jl | 130 +++++++++++++++++++++++++++++++++++++ test/runtests.jl | 8 ++- test/test_expr2rulenode.jl | 47 ++++++++++++++ 3 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 test/test_expr2rulenode.jl diff --git a/src/rulenode_operators.jl b/src/rulenode_operators.jl index e9f395b..4ab65d0 100644 --- a/src/rulenode_operators.jl +++ b/src/rulenode_operators.jl @@ -211,6 +211,136 @@ function _rulenode2expr(typ::Symbol, rulenode::AbstractRuleNode, grammar::Abstra end +""" + expr2ulenode(expr::Expr, grammar::ContextSensitiveGrammar) + +Converts an expression into a [`AbstractRuleNode`](@ref) corresponding to the rule definitions in the grammar. +""" + +function grammar_map_right_to_left(grammar::ContextSensitiveGrammar) + tags = Dict{Any,Any}() + for (l, r) in zip(grammar.types, grammar.rules) + tags[r] = l + end + return tags +end + +function _expr2rulenode(expr::Expr, grammar::ContextSensitiveGrammar, tags::Dict{Any,Any}) + if expr.head == :call + + if !haskey(tags, expr) + + parameters = [_expr2rulenode(expr.args[i], grammar, tags) for i in (2:length(expr.args))] + pl = map( x -> x[1], parameters) + pr = map( x -> x[2], parameters) + + temp = [expr.args[1] ;pl] + newexpr = Expr(:call, temp...) + rule = findfirst(==(newexpr), grammar.rules) + + + oldpl = copy(pl) + oldpr = copy(pr) + pnr = length(pl) + + while isnothing(rule) + + updatedrule = findfirst(==(pl[pnr]), grammar.rules) + + if isnothing(updatedrule) + pl[pnr] = oldpl[pnr] + pr[pnr] = oldpr[pnr] + pnr = pnr - 1 + continue + end + + pl[pnr] = tags[pl[pnr]] + pr[pnr] = RuleNode(updatedrule, [pr[pnr]]) + + temp = [expr.args[1] ;pl] + newexpr = Expr(:call, temp...) + rule = findfirst(==(newexpr), grammar.rules) + + pnr = length(pl) + end + return (tags[newexpr], RuleNode(rule, pr)) + else + rule = findfirst(==(expr), grammar.rules) + return (tags[expr], RuleNode(rule, [])) + end + elseif expr.head == :block + (l1, r1) = _expr2rulenode( expr.args[1], grammar, tags) + (l2, r2) = _expr2rulenode( expr.args[3], grammar, tags) + + temp = (l1, l2) + + newexpr = Expr(:block, temp...) + rule = findfirst(==(newexpr), grammar.rules) + + pl = [l1, l2] + pr = [r1, r2] + + oldpl = copy(pl) + oldpr = copy(pr) + pnr = length(pl) + + while isnothing(rule) + + updatedrule = findfirst(==(pl[pnr]), grammar.rules) + + if isnothing(updatedrule) + pl[pnr] = oldpl[pnr] + pr[pnr] = oldpr[pnr] + pnr = pnr - 1 + continue + end + + pl[pnr] = tags[pl[pnr]] + pr[pnr] = RuleNode(updatedrule, [pr[pnr]]) + + temp = (pl[1], pl[2]) + newexpr = Expr(:block, temp...) + rule = findfirst(==(newexpr), grammar.rules) + + pnr = length(pl) + end + return (tags[newexpr], RuleNode(rule, pr)) + + elseif expr.head == :quote + return _expr2rulenode(expr.args[1], grammar, tags) + else + error("Only call and block expressions are supported") + end +end + +function _expr2rulenode(expr::Any, grammar::ContextSensitiveGrammar, tags::Dict{Any,Any}) + rule = findfirst(==(expr), grammar.rules) + return (tags[expr], RuleNode(rule, [])) +end + +function expr2rulenode(expr::Expr, grammar::ContextSensitiveGrammar, startSymbol::Symbol) + tags = grammar_map_right_to_left(grammar) + (s, rn) = _expr2rulenode(expr, grammar, tags) + while s != startSymbol + + updatedrule = findfirst(==(s), grammar.rules) + + if isnothing(updatedrule) + error("INVALID STARTING SYMBOL") + end + + s = tags[s] + rn = RuleNode(updatedrule, [rn]) + end + return rn +end + +function expr2rulenode(expr::Expr, grammar::ContextSensitiveGrammar) + tags = grammar_map_right_to_left(grammar) + (s, rn) = _expr2rulenode(expr, grammar, tags) + return rn +end + """ Calculates the log probability associated with a rulenode in a probabilistic grammar. """ diff --git a/test/runtests.jl b/test/runtests.jl index b26dd0c..f4ece75 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,8 +2,10 @@ using HerbCore using HerbGrammar using Test + @testset "HerbGrammar.jl" verbose=true begin - include("test_csg.jl") - include("test_rulenode_operators.jl") - include("test_rulenode2expr.jl") + #include("test_csg.jl") + #include("test_rulenode_operators.jl") + #include("test_rulenode2expr.jl") + include("test_expr2rulenode.jl") end diff --git a/test/test_expr2rulenode.jl b/test/test_expr2rulenode.jl new file mode 100644 index 0000000..664313e --- /dev/null +++ b/test/test_expr2rulenode.jl @@ -0,0 +1,47 @@ +@testset verbose=true "expr2rulenode" begin + + g1 = @cfgrammar begin + Number = |(1:2) + Number = x + Number = Number + Number + Number = Number * Number + Number = DiffNumber + DiffNumber = |(3:4) + end + + expr1 = :(1 + 2) + expr2 = :((x * (1 + 3)) + (4 * x)) + @test expr2rulenode(expr1, g1) == RuleNode(4, [RuleNode(1, []), RuleNode(2, [])]) + @test expr2rulenode(expr2, g1) == RuleNode(4, [ RuleNode(5, [RuleNode(3, []), RuleNode(4, [RuleNode(1, []), RuleNode(6,[RuleNode(7, [])])])]), RuleNode(5,[RuleNode(6, [RuleNode(8, [])]), RuleNode(3, [])])]) + + + g2 = @csgrammar begin + Start = Sequence #1 + + Sequence = Operation #2 + Sequence = (Operation; Sequence) #3 + Operation = Transformation #4 + Operation = ControlStatement #5 + + Transformation = moveRight() | moveDown() | moveLeft() | moveUp() | drop() | grab() #6 + ControlStatement = IF(Condition, Sequence, Sequence) #12 + ControlStatement = WHILE(Condition, Sequence) #13 + + Condition = atTop() | atBottom() | atLeft() | atRight() | notAtTop() | notAtBottom() | notAtLeft() | notAtRight() #14 + end + + expr3 = :(moveUp()) + expr4 = :(moveUp(); (moveRight())) + expr5 = :(IF(atTop(), ((moveUp(); (moveRight()))), moveRight())) + + @test expr2rulenode(expr3, g2) == RuleNode(9, []) + @test expr2rulenode(expr3, g2, :Start) == RuleNode(1, [RuleNode(2, [RuleNode(4, [RuleNode(9, [])])])]) + + @test expr2rulenode(expr4, g2) == RuleNode(3, [RuleNode(4, [RuleNode(9, [])]) , RuleNode(2, [RuleNode(4, [RuleNode(6, [])])])]) + @test expr2rulenode(expr4, g2, :Start) == RuleNode(1, [RuleNode(3, [RuleNode(4, [RuleNode(9, [])]) , RuleNode(2, [RuleNode(4, [RuleNode(6, [])])])])]) + + @test expr2rulenode(expr5, g2) == RuleNode(12, [RuleNode(14, []), RuleNode(3, [RuleNode(4, [RuleNode(9, [])]) , RuleNode(2, [RuleNode(4, [RuleNode(6, [])])])]), RuleNode(2, [RuleNode(4, [RuleNode(6, [])])])]) + @test expr2rulenode(expr5, g2, :Start) == RuleNode(1, [RuleNode(2, [RuleNode(5, [RuleNode(12, [RuleNode(14, []), RuleNode(3, [RuleNode(4, [RuleNode(9, [])]) , RuleNode(2, [RuleNode(4, [RuleNode(6, [])])])]), RuleNode(2, [RuleNode(4, [RuleNode(6, [])])])])])])]) + +end + From 57337b79b9a62d570df0c20457fa36eda1e60e1b Mon Sep 17 00:00:00 2001 From: LoLo5689 Date: Fri, 15 Nov 2024 13:48:24 +0100 Subject: [PATCH 2/6] Uncomment other tests --- test/runtests.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index f4ece75..1a7221f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,8 +4,8 @@ using Test @testset "HerbGrammar.jl" verbose=true begin - #include("test_csg.jl") - #include("test_rulenode_operators.jl") - #include("test_rulenode2expr.jl") + include("test_csg.jl") + include("test_rulenode_operators.jl") + include("test_rulenode2expr.jl") include("test_expr2rulenode.jl") end From 47f8ed5fa536a227140ec14cf6447b1fed4f14c8 Mon Sep 17 00:00:00 2001 From: LoLo5689 Date: Mon, 18 Nov 2024 11:07:54 +0100 Subject: [PATCH 3/6] AbstractGrammar --- src/rulenode_operators.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rulenode_operators.jl b/src/rulenode_operators.jl index 4ab65d0..06bee99 100644 --- a/src/rulenode_operators.jl +++ b/src/rulenode_operators.jl @@ -212,12 +212,12 @@ end """ - expr2ulenode(expr::Expr, grammar::ContextSensitiveGrammar) + expr2ulenode(expr::Expr, grammar::AbstractGrammar) Converts an expression into a [`AbstractRuleNode`](@ref) corresponding to the rule definitions in the grammar. """ -function grammar_map_right_to_left(grammar::ContextSensitiveGrammar) +function grammar_map_right_to_left(grammar::AbstractGrammar) tags = Dict{Any,Any}() for (l, r) in zip(grammar.types, grammar.rules) tags[r] = l @@ -225,7 +225,7 @@ function grammar_map_right_to_left(grammar::ContextSensitiveGrammar) return tags end -function _expr2rulenode(expr::Expr, grammar::ContextSensitiveGrammar, tags::Dict{Any,Any}) +function _expr2rulenode(expr::Expr, grammar::AbstractGrammar, tags::Dict{Any,Any}) if expr.head == :call if !haskey(tags, expr) @@ -313,12 +313,12 @@ function _expr2rulenode(expr::Expr, grammar::ContextSensitiveGrammar, tags::Dict end end -function _expr2rulenode(expr::Any, grammar::ContextSensitiveGrammar, tags::Dict{Any,Any}) +function _expr2rulenode(expr::Any, grammar::AbstractGrammar, tags::Dict{Any,Any}) rule = findfirst(==(expr), grammar.rules) return (tags[expr], RuleNode(rule, [])) end -function expr2rulenode(expr::Expr, grammar::ContextSensitiveGrammar, startSymbol::Symbol) +function expr2rulenode(expr::Expr, grammar::AbstractGrammar, startSymbol::Symbol) tags = grammar_map_right_to_left(grammar) (s, rn) = _expr2rulenode(expr, grammar, tags) while s != startSymbol @@ -335,7 +335,7 @@ function expr2rulenode(expr::Expr, grammar::ContextSensitiveGrammar, startSymbol return rn end -function expr2rulenode(expr::Expr, grammar::ContextSensitiveGrammar) +function expr2rulenode(expr::Expr, grammar::AbstractGrammar) tags = grammar_map_right_to_left(grammar) (s, rn) = _expr2rulenode(expr, grammar, tags) return rn From 4c13d57c250a008475f1f08b1eb0e3e2e4d39780 Mon Sep 17 00:00:00 2001 From: LoLo5689 Date: Mon, 18 Nov 2024 11:16:19 +0100 Subject: [PATCH 4/6] export --- src/HerbGrammar.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/HerbGrammar.jl b/src/HerbGrammar.jl index 5c22fc6..7914c0d 100644 --- a/src/HerbGrammar.jl +++ b/src/HerbGrammar.jl @@ -50,6 +50,7 @@ export clearconstraints!, addconstraint!, merge_grammars!, + expr2rulenode, @pcfgrammar, From 0c76903069bdf5fa53419ef2e52cd6458d4c6d45 Mon Sep 17 00:00:00 2001 From: Lorenzo <19820958+LoLo5689@users.noreply.github.com> Date: Mon, 25 Nov 2024 11:25:31 +0100 Subject: [PATCH 5/6] Added Symbol support --- src/rulenode_operators.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/rulenode_operators.jl b/src/rulenode_operators.jl index 06bee99..d4fc378 100644 --- a/src/rulenode_operators.jl +++ b/src/rulenode_operators.jl @@ -341,6 +341,29 @@ function expr2rulenode(expr::Expr, grammar::AbstractGrammar) return rn end +function expr2rulenode(expr::Symbol, grammar::AbstractGrammar, startSymbol::Symbol) + tags = get_tags(grammar) + (s, rn) = expr2rulenode(expr, grammar, tags) + while s != startSymbol + + updatedrule = findfirst(==(s), grammar.rules) + + if isnothing(updatedrule) + error("INVALID STARTING SYMBOL") + end + + s = tags[s] + rn = RuleNode(updatedrule, [rn]) + end + return rn +end + +function expr2rulenode(expr::Symbol, grammar::AbstractGrammar) + tags = get_tags(grammar) + (s, rn) = expr2rulenode(expr, grammar, tags) + return rn +end + """ Calculates the log probability associated with a rulenode in a probabilistic grammar. """ From b133e0bb04ec38dd6f4da37df6cddcb1dadc8cd7 Mon Sep 17 00:00:00 2001 From: Lorenzo <19820958+LoLo5689@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:33:15 +0100 Subject: [PATCH 6/6] Updated docstrings --- src/rulenode_operators.jl | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/rulenode_operators.jl b/src/rulenode_operators.jl index d4fc378..2774cf0 100644 --- a/src/rulenode_operators.jl +++ b/src/rulenode_operators.jl @@ -210,12 +210,9 @@ function _rulenode2expr(typ::Symbol, rulenode::AbstractRuleNode, grammar::Abstra retval, j end - -""" - expr2ulenode(expr::Expr, grammar::AbstractGrammar) - -Converts an expression into a [`AbstractRuleNode`](@ref) corresponding to the rule definitions in the grammar. -""" +# --------------------------------------------- +# expr2rulenode and associated functions +# --------------------------------------------- function grammar_map_right_to_left(grammar::AbstractGrammar) tags = Dict{Any,Any}() @@ -318,6 +315,11 @@ function _expr2rulenode(expr::Any, grammar::AbstractGrammar, tags::Dict{Any,Any} return (tags[expr], RuleNode(rule, [])) end +""" + expr2rulenode(expr::Expr, grammar::AbstractGrammar, startSymbol::Symbol) + +Converts an expression into a [`AbstractRuleNode`](@ref) corresponding to the rule definitions in the grammar. +""" function expr2rulenode(expr::Expr, grammar::AbstractGrammar, startSymbol::Symbol) tags = grammar_map_right_to_left(grammar) (s, rn) = _expr2rulenode(expr, grammar, tags) @@ -335,12 +337,22 @@ function expr2rulenode(expr::Expr, grammar::AbstractGrammar, startSymbol::Symbol return rn end +""" + expr2rulenode(expr::Expr, grammar::AbstractGrammar) + +Converts an expression into a [`AbstractRuleNode`](@ref) corresponding to the rule definitions in the grammar. +""" function expr2rulenode(expr::Expr, grammar::AbstractGrammar) tags = grammar_map_right_to_left(grammar) (s, rn) = _expr2rulenode(expr, grammar, tags) return rn end +""" + expr2rulenode(expr::Symbol, grammar::AbstractGrammar, startSymbol::Symbol) + +Converts an expression into a [`AbstractRuleNode`](@ref) corresponding to the rule definitions in the grammar. +""" function expr2rulenode(expr::Symbol, grammar::AbstractGrammar, startSymbol::Symbol) tags = get_tags(grammar) (s, rn) = expr2rulenode(expr, grammar, tags) @@ -358,6 +370,11 @@ function expr2rulenode(expr::Symbol, grammar::AbstractGrammar, startSymbol::Symb return rn end +""" + expr2rulenode(expr::Symbol, grammar::AbstractGrammar) + +Converts an expression into a [`AbstractRuleNode`](@ref) corresponding to the rule definitions in the grammar. +""" function expr2rulenode(expr::Symbol, grammar::AbstractGrammar) tags = get_tags(grammar) (s, rn) = expr2rulenode(expr, grammar, tags)