diff --git a/src/rulenode_operators.jl b/src/rulenode_operators.jl index 5c8cc14..b5ef545 100644 --- a/src/rulenode_operators.jl +++ b/src/rulenode_operators.jl @@ -293,12 +293,48 @@ nchildren(grammar::Grammar, node::RuleNode)::Int = length(child_types(grammar, n """ isvariable(grammar::Grammar, node::RuleNode)::Bool -Returns true if the rule used by `node` represents a variable. +Return true if the rule used by `node` represents a variable in a program (essentially, an input to the program) """ -isvariable(grammar::Grammar, node::RuleNode)::Bool = grammar.isterminal[node.ind] && grammar.rules[node.ind] isa Symbol +isvariable(grammar::Grammar, node::RuleNode)::Bool = ( + grammar.isterminal[node.ind] && + grammar.rules[node.ind] isa Symbol && + !_is_defined_in_modules(grammar.rules[node.ind], [Main, Base]) +) +""" + isvariable(grammar::Grammar, node::RuleNode, mod::Module)::Bool + +Return true if the rule used by `node` represents a variable. + +Taking into account the symbols defined in the given module(s). +""" +isvariable(grammar::Grammar, node::RuleNode, mod::Module...)::Bool = ( + grammar.isterminal[node.ind] && + grammar.rules[node.ind] isa Symbol && + !_is_defined_in_modules(grammar.rules[node.ind], [mod..., Main, Base]) +) + +""" + isvariable(grammar::Grammar, ind::Int)::Bool -isvariable(grammar::Grammar, ind::Int)::Bool = grammar.isterminal[ind] && grammar.rules[ind] isa Symbol +Return true if the rule with index `ind` represents a variable. +""" +isvariable(grammar::Grammar, ind::Int)::Bool = ( + grammar.isterminal[ind] && + grammar.rules[ind] isa Symbol && + !_is_defined_in_modules(grammar.rules[ind], [Main, Base]) +) +""" + isvariable(grammar::Grammar, ind::Int, mod::Module)::Bool +Return true if the rule with index `ind` represents a variable. + +Taking into account the symbols defined in the given module(s). +""" +isvariable(grammar::Grammar, ind::Int, mod::Module...)::Bool = ( + grammar.isterminal[ind] && + grammar.rules[ind] isa Symbol && + !_is_defined_in_modules(grammar.rules[ind], [mod..., Main, Base]) +) """ contains_returntype(node::RuleNode, grammar::Grammar, sym::Symbol, maxdepth::Int=typemax(Int)) diff --git a/src/utils.jl b/src/utils.jl index 76a937d..e1f7ca6 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -78,20 +78,24 @@ function _add_to_symboltable!(tab::SymbolTable, rule::Expr, mod::Module) return true end +function _apply_if_defined_in_modules(func::Function, s::Symbol, mods::Vector{Module}) + for mod in mods + if isdefined(mod, s) + func(mod, s) + return true + end + end + return false +end + +function _is_defined_in_modules(s::Symbol, mods::Vector{Module}) + _apply_if_defined_in_modules((mod, s) -> nothing, s, mods) +end function _add_to_symboltable!(tab::SymbolTable, s::Symbol, mod::Module) - if isdefined(mod, s) - tab[s] = getfield(mod, s) - return true - elseif isdefined(Base, s) - tab[s] = getfield(Base, s) - return true - elseif isdefined(Main, s) - tab[s] = getfield(Main, s) - return true - else - return false - end + _add_to_table! = (mod, s) -> tab[s] = getfield(mod, s) + + return _apply_if_defined_in_modules(_add_to_table!, s, [mod, Base, Main]) end diff --git a/test/runtests.jl b/test/runtests.jl index b64a4c3..60de23b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,4 +3,5 @@ using Test @testset "HerbGrammar.jl" verbose=true begin include("test_cfg.jl") + include("test_rulenode_operators.jl") end diff --git a/test/test_rulenode_operators.jl b/test/test_rulenode_operators.jl new file mode 100644 index 0000000..dee0c14 --- /dev/null +++ b/test/test_rulenode_operators.jl @@ -0,0 +1,18 @@ +module SomeDefinitions + a_variable_that_is_defined = 7 +end + +@testset verbose = true "RuleNode Operators" begin + @testset "Check if a symbol is a variable" begin + g₁ = @cfgrammar begin + Real = |(1:5) + Real = a_variable + Real = a_variable_that_is_defined + end + + @test !isvariable(g₁, RuleNode(5, g₁), SomeDefinitions) + @test isvariable(g₁, RuleNode(6, g₁), SomeDefinitions) + @test !isvariable(g₁, RuleNode(7, g₁), SomeDefinitions) + @test isvariable(g₁, RuleNode(7, g₁)) + end +end