diff --git a/lang/ast/scopegraph.go b/lang/ast/scopegraph.go new file mode 100644 index 00000000..374633f8 --- /dev/null +++ b/lang/ast/scopegraph.go @@ -0,0 +1,201 @@ +// Mgmt +// Copyright (C) 2013-2023+ James Shubin and the project contributors +// Written by James Shubin and the project contributors +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package ast + +import ( + "fmt" + + "github.com/purpleidea/mgmt/lang/interfaces" + "github.com/purpleidea/mgmt/pgraph" +) + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *StmtBind) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *StmtRes) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) + name, ok := obj.Name.(interfaces.ScopeGrapher) + if !ok { + panic("can't graph scope") // programming error + } + name.ScopeGraph(g) + g.AddEdge(obj, obj.Name, &pgraph.SimpleEdge{Name: "name"}) + for _, resContents := range obj.Contents { + switch r := resContents.(type) { + case *StmtResField: + rValue, ok := r.Value.(interfaces.ScopeGrapher) + if !ok { + panic("can't graph scope") // programming error + } + rValue.ScopeGraph(g) + g.AddEdge(obj, r.Value, &pgraph.SimpleEdge{Name: r.Field}) + } + } +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *StmtEdge) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *StmtIf) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *StmtProg) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) + for _, stmt := range obj.Body { + stmt, ok := stmt.(interfaces.ScopeGrapher) + if !ok { + panic("can't graph scope") // programming error + } + stmt.ScopeGraph(g) + g.AddEdge(obj, stmt, &pgraph.SimpleEdge{Name: ""}) + } +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *StmtFunc) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *StmtClass) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *StmtInclude) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *StmtImport) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *StmtComment) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprBool) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprStr) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprInt) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprFloat) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprList) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprMap) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprStruct) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprFunc) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) + if obj.Body != nil { + body, ok := obj.Body.(interfaces.ScopeGrapher) + if !ok { + panic("can't graph scope") // programming error + } + body.ScopeGraph(g) + g.AddEdge(obj, obj.Body, &pgraph.SimpleEdge{Name: "body"}) + } +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprCall) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) + expr, ok := obj.expr.(interfaces.ScopeGrapher) + if !ok { + panic("can't graph scope") // programming error + } + expr.ScopeGraph(g) + g.AddEdge(obj, obj.expr, &pgraph.SimpleEdge{Name: "expr"}) + + for i, arg := range obj.Args { + arg, ok := arg.(interfaces.ScopeGrapher) + if !ok { + panic("can't graph scope") // programming error + } + arg.ScopeGraph(g) + g.AddEdge(obj, arg, &pgraph.SimpleEdge{Name: fmt.Sprintf("arg%d", i)}) + } +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprVar) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) + target := obj.scope.Variables[obj.Name] + newTarget, ok := target.(interfaces.ScopeGrapher) + if !ok { + panic("can't graph scope") // programming error + } + newTarget.ScopeGraph(g) + g.AddEdge(obj, target, &pgraph.SimpleEdge{Name: "target"}) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprParam) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprPoly) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) + definition, ok := obj.Definition.(interfaces.ScopeGrapher) + if !ok { + panic("can't graph scope") // programming error + } + definition.ScopeGraph(g) + g.AddEdge(obj, obj.Definition, &pgraph.SimpleEdge{Name: "def"}) +} + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprIf) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +} diff --git a/lang/interfaces/ast.go b/lang/interfaces/ast.go index cfba6ad4..ebb617f5 100644 --- a/lang/interfaces/ast.go +++ b/lang/interfaces/ast.go @@ -134,6 +134,15 @@ type Expr interface { Value() (types.Value, error) } +// ScopeGrapher adds a method to turn an AST (Expr or Stmt) into a graph so that +// we can debug the SetScope compilation phase. +type ScopeGrapher interface { + Node + + // ScopeGraph adds nodes and vertices to the supplied graph. + ScopeGraph(g *pgraph.Graph) +} + // Data provides some data to the node that could be useful during its lifetime. type Data struct { // Fs represents a handle to the filesystem that we're running on. This diff --git a/lang/interfaces/structs.go b/lang/interfaces/structs.go index 9a0ecdee..8ade67e0 100644 --- a/lang/interfaces/structs.go +++ b/lang/interfaces/structs.go @@ -187,3 +187,8 @@ func (obj *ExprAny) Value() (types.Value, error) { } return obj.V, nil } + +// ScopeGraph adds nodes and vertices to the supplied graph. +func (obj *ExprAny) ScopeGraph(g *pgraph.Graph) { + g.AddVertex(obj) +}