Projects STRLCPY bearer Commits 46de7f95
🤬
  • ■ ■ ■ ■ ■ ■
    .envrc.example
    skipped 5 lines
    6 6  export GOOGLE_MAX_ATTEMPT="5"
    7 7  export BEARER_EXECUTABLE_PATH="./bearer"
    8 8  export GITHUB_WORKSPACE="/path/to/bearer/project"
     9 +export CGO_CPPFLAGS="-I/usr/local/homebrew/include"
     10 + 
  • ■ ■ ■ ■ ■
    .gitignore
    skipped 12 lines
    13 13   
    14 14   
    15 15  .envrc
     16 + 
     17 +# souffle
     18 +./souffle/generated
     19 +./pkg/souffle/rules/generated.cpp
     20 + 
  • ■ ■ ■ ■
    new/detector/implementation/custom/custom.go
    skipped 28 lines
    29 29  func New(lang languagetypes.Language, detectorType string, patterns []settings.RulePattern) (types.Detector, error) {
    30 30   var compiledPatterns []Pattern
    31 31   for _, pattern := range patterns {
    32  - patternQuery, err := lang.CompilePatternQuery(pattern.Pattern)
     32 + patternQuery, err := lang.CompilePatternQuery(detectorType, pattern.Pattern)
    33 33   if err != nil {
    34 34   return nil, fmt.Errorf("error compiling pattern: %s", err)
    35 35   }
    skipped 57 lines
  • ■ ■ ■ ■ ■
    new/language/base/base.go
    skipped 4 lines
    5 5   "github.com/bearer/bearer/new/language/patternquery"
    6 6   "github.com/bearer/bearer/new/language/tree"
    7 7   "github.com/bearer/bearer/new/language/types"
     8 + soufflequery "github.com/bearer/bearer/pkg/souffle/query"
    8 9  )
    9 10   
    10 11  type Language struct {
     12 + souffle bool
    11 13   implementation implementation.Implementation
    12 14  }
    13 15   
    14  -func New(implementation implementation.Implementation) *Language {
    15  - return &Language{implementation: implementation}
     16 +func New(souffle bool, implementation implementation.Implementation) *Language {
     17 + return &Language{souffle: souffle, implementation: implementation}
    16 18  }
    17 19   
    18 20  func (lang *Language) Parse(input string) (*tree.Tree, error) {
    skipped 13 lines
    32 34   return tree.CompileQuery(lang.implementation.SitterLanguage(), input)
    33 35  }
    34 36   
    35  -func (lang *Language) CompilePatternQuery(input string) (types.PatternQuery, error) {
     37 +func (lang *Language) CompilePatternQuery(ruleName, input string) (types.PatternQuery, error) {
     38 + if lang.souffle {
     39 + return soufflequery.Compile(lang.implementation, ruleName, input)
     40 + }
     41 + 
    36 42   return patternquery.Compile(lang, lang.implementation, input)
    37 43  }
    38 44   
  • ■ ■ ■ ■ ■ ■
    new/language/implementation/implementation.go
    skipped 4 lines
    5 5   
    6 6   patternquerytypes "github.com/bearer/bearer/new/language/patternquery/types"
    7 7   "github.com/bearer/bearer/new/language/tree"
     8 + astlanguage "github.com/bearer/bearer/pkg/ast/languages/ruby"
    8 9  )
    9 10   
    10 11  type Implementation interface {
     12 + ASTLanguage() *astlanguage.Language
    11 13   SitterLanguage() *sitter.Language
    12 14   // AnalyzeFlow unifies nodes that represent the same value in the tree.
    13 15   //
    skipped 126 lines
  • ■ ■ ■ ■ ■
    new/language/implementation/ruby/ruby.go
    skipped 12 lines
    13 13   "github.com/bearer/bearer/new/language/implementation"
    14 14   patternquerytypes "github.com/bearer/bearer/new/language/patternquery/types"
    15 15   "github.com/bearer/bearer/new/language/tree"
     16 + astlanguage "github.com/bearer/bearer/pkg/ast/languages/ruby"
    16 17   "github.com/bearer/bearer/pkg/util/regex"
    17 18  )
    18 19   
    skipped 13 lines
    32 33   ellipsisRegex = regexp.MustCompile(`\$<\.\.\.>`)
    33 34  )
    34 35   
    35  -type rubyImplementation struct{}
     36 +type rubyImplementation struct {
     37 + astLanguage *astlanguage.Language
     38 +}
    36 39   
    37 40  func Get() implementation.Implementation {
    38  - return &rubyImplementation{}
     41 + astLanguage := astlanguage.New()
     42 + return &rubyImplementation{astLanguage: astLanguage}
     43 +}
     44 + 
     45 +func (implementation *rubyImplementation) ASTLanguage() *astlanguage.Language {
     46 + return implementation.astLanguage
    39 47  }
    40 48   
    41 49  func (*rubyImplementation) SitterLanguage() *sitter.Language {
    skipped 219 lines
  • ■ ■ ■ ■ ■ ■
    new/language/patternquery/builder/builder.go
    skipped 7 lines
    8 8   "golang.org/x/exp/slices"
    9 9   
    10 10   "github.com/bearer/bearer/new/language/implementation"
     11 + builderinput "github.com/bearer/bearer/new/language/patternquery/builder/input"
    11 12   "github.com/bearer/bearer/new/language/patternquery/types"
    12 13   "github.com/bearer/bearer/new/language/tree"
    13 14   languagetypes "github.com/bearer/bearer/new/language/types"
    14 15   "github.com/bearer/bearer/pkg/parser/nodeid"
    15 16  )
    16 17   
    17  -type InputParams struct {
    18  - Variables []types.Variable
    19  - MatchNodeOffset int
    20  - UnanchoredOffsets []int
    21  -}
    22  - 
    23 18  type Result struct {
    24 19   Query string
    25 20   ParamToVariable map[string]string
    skipped 5 lines
    31 26   langImplementation implementation.Implementation
    32 27   stringBuilder strings.Builder
    33 28   idGenerator nodeid.Generator
    34  - inputParams InputParams
     29 + inputParams builderinput.InputParams
    35 30   variableToParams map[string][]string
    36 31   paramToContent map[string]map[string]string
    37 32   matchNode *tree.Node
    skipped 4 lines
    42 37   langImplementation implementation.Implementation,
    43 38   input string,
    44 39  ) (*Result, error) {
    45  - processedInput, inputParams, err := processInput(langImplementation, input)
     40 + processedInput, inputParams, err := builderinput.Process(langImplementation, input)
    46 41   if err != nil {
    47 42   return nil, err
    48 43   }
    skipped 259 lines
  • ■ ■ ■ ■ ■
    new/language/patternquery/builder/input.go new/language/patternquery/builder/input/input.go
    1  -package builder
     1 +package input
    2 2   
    3 3  import (
    4 4   "errors"
    5 5   "fmt"
    6 6   
    7 7   "github.com/bearer/bearer/new/language/implementation"
     8 + "github.com/bearer/bearer/new/language/patternquery/types"
    8 9  )
    9 10   
    10  -func processInput(langImplementation implementation.Implementation, input string) (string, *InputParams, error) {
     11 +type InputParams struct {
     12 + Variables []types.Variable
     13 + MatchNodeOffset int
     14 + UnanchoredOffsets []int
     15 +}
     16 + 
     17 +func Process(langImplementation implementation.Implementation, input string) (string, *InputParams, error) {
    11 18   inputWithoutVariables, variables, err := langImplementation.ExtractPatternVariables(input)
    12 19   if err != nil {
    13 20   return "", nil, fmt.Errorf("error processing variables: %s", err)
    skipped 56 lines
  • ■ ■ ■ ■
    new/language/types/types.go
    skipped 15 lines
    16 16  type Language interface {
    17 17   Parse(input string) (*tree.Tree, error)
    18 18   CompileQuery(input string) (*tree.Query, error)
    19  - CompilePatternQuery(input string) (PatternQuery, error)
     19 + CompilePatternQuery(ruleName, input string) (PatternQuery, error)
    20 20  }
    21 21   
  • ■ ■ ■ ■ ■ ■
    pkg/ast/idgenerator/idgenerator.go
     1 +package idgenerator
     2 + 
     3 +type Generator struct {
     4 + next uint32
     5 +}
     6 + 
     7 +func New() *Generator {
     8 + return &Generator{}
     9 +}
     10 + 
     11 +func (generator *Generator) Get() uint32 {
     12 + next := generator.next
     13 + generator.next++
     14 + return next
     15 +}
     16 + 
  • ■ ■ ■ ■ ■ ■
    pkg/ast/languages/ruby/common/common.go
     1 +package common
     2 + 
     3 +import (
     4 + sitter "github.com/smacker/go-tree-sitter"
     5 + "golang.org/x/exp/slices"
     6 + 
     7 + "github.com/bearer/bearer/pkg/util/set"
     8 +)
     9 + 
     10 +var (
     11 + leafNodeTypes = []string{
     12 + "identifier",
     13 + "constant",
     14 + "integer",
     15 + "float",
     16 + "complex",
     17 + "rational",
     18 + "string_content",
     19 + "simple_symbol",
     20 + "hash_key_symbol",
     21 + }
     22 + 
     23 + nodeTypeToFieldNames = map[string][]string{
     24 + "method": {"name", "parameters"},
     25 + "singleton_method": {"object", "name", "parameters"},
     26 + "splat_parameter": {"name"},
     27 + "hash_splat_parameter": {"name"},
     28 + "block_parameter": {"name"},
     29 + "keyword_parameter": {"name", "value"},
     30 + "optional_parameter": {"name", "value"},
     31 + "class": {"name", "superclass"},
     32 + "singleton_class": {"value"},
     33 + "module": {"name"},
     34 + "if_modifier": {"body", "condition"},
     35 + "unless_modifier": {"body", "condition"},
     36 + "while_modifier": {"body", "condition"},
     37 + "until_modifier": {"body", "condition"},
     38 + "rescue_modifier": {"body", "handler"},
     39 + "while": {"condition", "body"},
     40 + "until": {"condition", "body"},
     41 + "for": {"pattern", "value", "body"},
     42 + "case": {"value"},
     43 + "when": {"pattern", "body"},
     44 + "if": {"condition", "consequence", "alternative"},
     45 + "unless": {"condition", "consequence", "alternative"},
     46 + "elsif": {"condition", "consequence", "alternative"},
     47 + "rescue": {"exceptions", "variable", "body"},
     48 + "element_reference": {"object"},
     49 + "scope_resolution": {"scope", "name"},
     50 + "call": {"receiver", "method", "arguments", "block"},
     51 + "do_block": {"parameters"},
     52 + "block": {"parameters"},
     53 + "assignment": {"left", "right"},
     54 + "operator_assignment": {"left", "right", "operator"},
     55 + "conditional": {"condition", "consequence", "alternative"},
     56 + "range": {"begin", "end", "operator"},
     57 + "binary": {"left", "right", "operator"},
     58 + "unary": {"operator", "operand"},
     59 + "setter": {"name"},
     60 + "alias": {"name", "alias"},
     61 + "pair": {"key", "value"},
     62 + "lambda": {"parameters", "body"},
     63 + }
     64 + 
     65 + specialCasedNotMissing = map[string][]string{
     66 + "call": {"arguments"},
     67 + }
     68 +)
     69 + 
     70 +func MatchContent(node *sitter.Node) bool {
     71 + return slices.Contains(leafNodeTypes, node.Type())
     72 +}
     73 + 
     74 +// FIXME: move to patterns?
     75 +func GetMissingFields(node *sitter.Node) set.Set[string] {
     76 + allFields := nodeTypeToFieldNames[node.Type()]
     77 + notMissing := specialCasedNotMissing[node.Type()]
     78 + 
     79 + missingFields := set.New[string]()
     80 + for _, fieldName := range allFields {
     81 + if node.ChildByFieldName(fieldName) == nil && !slices.Contains(notMissing, fieldName) {
     82 + missingFields.Add(fieldName)
     83 + }
     84 + }
     85 + 
     86 + return missingFields
     87 +}
     88 + 
     89 +func FieldName(node *sitter.Node) string {
     90 + parent := node.Parent()
     91 + if parent == nil {
     92 + return ""
     93 + }
     94 + 
     95 + for _, fieldName := range nodeTypeToFieldNames[parent.Type()] {
     96 + child := parent.ChildByFieldName(fieldName)
     97 + if child != nil && child.Equal(node) {
     98 + return fieldName
     99 + }
     100 + }
     101 + 
     102 + return ""
     103 +}
     104 + 
  • ■ ■ ■ ■ ■ ■
    pkg/ast/languages/ruby/patterns/patterns.go
     1 +package patterns
     2 + 
     3 +import (
     4 + "fmt"
     5 + 
     6 + sitter "github.com/smacker/go-tree-sitter"
     7 + 
     8 + builderinput "github.com/bearer/bearer/new/language/patternquery/builder/input"
     9 + querytypes "github.com/bearer/bearer/new/language/patternquery/types"
     10 + "github.com/bearer/bearer/pkg/ast/idgenerator"
     11 + "github.com/bearer/bearer/pkg/ast/languages/ruby/common"
     12 + "github.com/bearer/bearer/pkg/ast/walker"
     13 + "github.com/bearer/bearer/pkg/util/set"
     14 + writerbase "github.com/bearer/bearer/pkg/util/souffle/writer/base"
     15 + filewriter "github.com/bearer/bearer/pkg/util/souffle/writer/file"
     16 +)
     17 + 
     18 +type nodeVariableGenerator struct {
     19 + ids map[*sitter.Node]uint32
     20 + idGenerator *idgenerator.Generator
     21 +}
     22 + 
     23 +func newNodeVariableGenerator() *nodeVariableGenerator {
     24 + return &nodeVariableGenerator{
     25 + ids: make(map[*sitter.Node]uint32),
     26 + idGenerator: idgenerator.New(),
     27 + }
     28 +}
     29 + 
     30 +func (generator *nodeVariableGenerator) Get(node *sitter.Node) string {
     31 + id := generator.getId(node)
     32 + return fmt.Sprintf("node%d", id)
     33 +}
     34 + 
     35 +func (generator *nodeVariableGenerator) getId(node *sitter.Node) uint32 {
     36 + if id, cached := generator.ids[node]; cached {
     37 + return id
     38 + }
     39 + 
     40 + id := generator.idGenerator.Get()
     41 + generator.ids[node] = id
     42 + return id
     43 +}
     44 + 
     45 +type patternWriter struct {
     46 + *filewriter.Writer
     47 + inputParams *builderinput.InputParams
     48 + ruleName string
     49 + input []byte
     50 + literals []writerbase.Literal
     51 + childIndex uint32
     52 + rootElement writerbase.LiteralElement
     53 + parentElement writerbase.LiteralElement
     54 + nodeVariableGenerator *nodeVariableGenerator
     55 + tempIdGenerator *idgenerator.Generator
     56 + handled set.Set[*sitter.Node]
     57 +}
     58 + 
     59 +func CompileRule(
     60 + walker *walker.Walker,
     61 + inputParams *builderinput.InputParams,
     62 + ruleName string,
     63 + input []byte,
     64 + rootNode *sitter.Node,
     65 + writer *filewriter.Writer,
     66 +) error {
     67 + w := &patternWriter{
     68 + Writer: writer,
     69 + inputParams: inputParams,
     70 + ruleName: ruleName,
     71 + input: input,
     72 + nodeVariableGenerator: newNodeVariableGenerator(),
     73 + tempIdGenerator: idgenerator.New(),
     74 + handled: set.New[*sitter.Node](),
     75 + }
     76 + 
     77 + err := walker.Walk(rootNode, w.visitNode)
     78 + if err != nil {
     79 + return err
     80 + }
     81 + 
     82 + return writer.WriteRule(
     83 + writer.Predicate("Rule", writer.Symbol(w.ruleName), w.rootElement),
     84 + w.literals...,
     85 + )
     86 +}
     87 + 
     88 +func (writer *patternWriter) visitNode(node *sitter.Node, visitChildren func() error) error {
     89 + if writer.handled.Has(node) {
     90 + return nil
     91 + }
     92 + 
     93 + nodeElement := writer.Identifier(writer.nodeVariableGenerator.Get(node))
     94 + 
     95 + if node.Type() == "program" {
     96 + if node.ChildCount() != 1 {
     97 + return fmt.Errorf("expected 1 root node in pattern but got %d", node.ChildCount())
     98 + }
     99 + 
     100 + return visitChildren()
     101 + }
     102 + 
     103 + if writer.rootElement == nil {
     104 + writer.rootElement = nodeElement
     105 + }
     106 + 
     107 + if writer.parentElement != nil {
     108 + if fname := common.FieldName(node); fname != "" {
     109 + writer.literals = append(
     110 + writer.literals,
     111 + writer.Predicate("AST_NodeField", writer.parentElement, nodeElement, writer.Symbol(fname)),
     112 + )
     113 + } else {
     114 + writer.literals = append(
     115 + writer.literals,
     116 + writer.Predicate("AST_ParentChild", writer.parentElement, writer.Unsigned(writer.childIndex), nodeElement),
     117 + )
     118 + 
     119 + writer.childIndex++
     120 + }
     121 + }
     122 + 
     123 + if variable := writer.getVariableFor(node); variable != nil {
     124 + // TODO
     125 + return nil
     126 + }
     127 + 
     128 + writer.literals = append(
     129 + writer.literals,
     130 + writer.Predicate("AST_NodeType", nodeElement, writer.Symbol(node.Type())),
     131 + )
     132 + 
     133 + if common.MatchContent(node) {
     134 + writer.literals = append(
     135 + writer.literals,
     136 + writer.Predicate("AST_NodeContent", nodeElement, writer.Symbol(node.Content(writer.input))),
     137 + )
     138 + }
     139 + 
     140 + for fieldName := range common.GetMissingFields(node) {
     141 + writer.literals = append(
     142 + writer.literals,
     143 + writer.NegativePredicate("AST_NodeField", nodeElement, writer.Any(), writer.Symbol(fieldName)),
     144 + )
     145 + }
     146 + 
     147 + // Handle `call` vs `call()`
     148 + if node.Type() == "call" {
     149 + if arguments := node.ChildByFieldName("arguments"); arguments == nil || arguments.NamedChildCount() == 0 {
     150 + writer.handled.Add(arguments)
     151 + writer.literals = append(writer.literals, writer.optionalEmpty(node, "arguments"))
     152 + }
     153 + }
     154 + 
     155 + // Handle { a: 1 } vs { :a => 1 }
     156 + if node.Type() == "pair" {
     157 + key := node.ChildByFieldName("key")
     158 + if key.Type() == "simple_symbol" || key.Type() == "hash_key_symbol" {
     159 + writer.handled.Add(key)
     160 + 
     161 + symbolName := key.Content(writer.input)
     162 + if key.Type() == "simple_symbol" {
     163 + symbolName = symbolName[1:]
     164 + }
     165 + 
     166 + writer.literals = append(writer.literals, writer.eitherNodeLiteral(
     167 + node,
     168 + "key",
     169 + literalNode{nodeType: "simple_symbol", content: ":" + symbolName},
     170 + literalNode{nodeType: "hash_key_symbol", content: symbolName},
     171 + ))
     172 + }
     173 + }
     174 + 
     175 + oldParentElement := writer.parentElement
     176 + oldChildIndex := writer.childIndex
     177 + writer.childIndex = 0
     178 + writer.parentElement = nodeElement
     179 + err := visitChildren()
     180 + writer.childIndex = oldChildIndex
     181 + writer.parentElement = oldParentElement
     182 + 
     183 + return err
     184 +}
     185 + 
     186 +func (writer *patternWriter) optionalEmpty(node *sitter.Node, fieldName string) writerbase.Literal {
     187 + nodeElement := writer.Identifier(writer.nodeVariableGenerator.Get(node))
     188 + tempVariable := writer.tempVariable()
     189 + 
     190 + return writer.Disjunction(
     191 + writer.NegativePredicate("AST_NodeField", nodeElement, writer.Any(), writer.Symbol(fieldName)),
     192 + writer.Conjunction(
     193 + writer.Predicate("AST_NodeField", nodeElement, tempVariable, writer.Symbol(fieldName)),
     194 + writer.NegativePredicate(
     195 + "AST_ParentChild",
     196 + tempVariable,
     197 + writer.Any(),
     198 + writer.Any(),
     199 + ),
     200 + ),
     201 + )
     202 +}
     203 + 
     204 +type literalNode struct {
     205 + nodeType string
     206 + content string
     207 +}
     208 + 
     209 +func (writer *patternWriter) eitherNodeLiteral(
     210 + node *sitter.Node,
     211 + fieldName string,
     212 + literalNodes ...literalNode,
     213 +) writerbase.Literal {
     214 + nodeElement := writer.Identifier(writer.nodeVariableGenerator.Get(node))
     215 + tempVariable := writer.tempVariable()
     216 + 
     217 + literals := make([]writerbase.Literal, len(literalNodes))
     218 + for i, literalNode := range literalNodes {
     219 + literals[i] = writer.Conjunction(
     220 + writer.Predicate("AST_NodeType", tempVariable, writer.Symbol(literalNode.nodeType)),
     221 + writer.Predicate("AST_NodeContent", tempVariable, writer.Symbol(literalNode.content)),
     222 + )
     223 + }
     224 + 
     225 + return writer.Conjunction(
     226 + writer.Predicate("AST_NodeField", nodeElement, tempVariable, writer.Symbol(fieldName)),
     227 + writer.Disjunction(literals...),
     228 + )
     229 +}
     230 + 
     231 +func (writer *patternWriter) tempVariable() writerbase.LiteralElement {
     232 + return writer.Identifier(fmt.Sprintf("tmp%d", writer.tempIdGenerator.Get()))
     233 +}
     234 + 
     235 +func (writer *patternWriter) getVariableFor(node *sitter.Node) *querytypes.Variable {
     236 + for _, variable := range writer.inputParams.Variables {
     237 + if node.Content(writer.input) == variable.DummyValue {
     238 + return &variable
     239 + }
     240 + }
     241 + 
     242 + return nil
     243 +}
     244 + 
  • ■ ■ ■ ■ ■ ■
    pkg/ast/languages/ruby/ruby.go
     1 +package ruby
     2 + 
     3 +import (
     4 + "context"
     5 + "fmt"
     6 + 
     7 + sitter "github.com/smacker/go-tree-sitter"
     8 + "github.com/smacker/go-tree-sitter/ruby"
     9 + 
     10 + "github.com/bearer/bearer/pkg/ast/languages/ruby/patterns"
     11 + "github.com/bearer/bearer/pkg/ast/sourcefacts"
     12 + "github.com/bearer/bearer/pkg/ast/walker"
     13 + "github.com/bearer/bearer/pkg/souffle/writer"
     14 + filewriter "github.com/bearer/bearer/pkg/souffle/writer/file"
     15 +)
     16 + 
     17 +type Language struct {
     18 + sitterLanguage *sitter.Language
     19 + walker *walker.Walker
     20 +}
     21 + 
     22 +func New() *Language {
     23 + sitterLanguage := ruby.GetLanguage()
     24 + 
     25 + return &Language{
     26 + sitterLanguage: sitterLanguage,
     27 + walker: walker.NewWalker(sitterLanguage),
     28 + }
     29 +}
     30 + 
     31 +func (language *Language) WriteSourceFacts(
     32 + fileId uint32,
     33 + input []byte,
     34 + writer writer.FactWriter,
     35 +) error {
     36 + rootNode, err := sitter.ParseCtx(context.TODO(), input, language.sitterLanguage)
     37 + if err != nil {
     38 + return fmt.Errorf("parse error: %w", err)
     39 + }
     40 + 
     41 + if err := sourcefacts.WriteFacts(
     42 + language.walker,
     43 + fileId,
     44 + input,
     45 + rootNode,
     46 + writer,
     47 + ); err != nil {
     48 + return fmt.Errorf("translation error: %w", err)
     49 + }
     50 + 
     51 + return nil
     52 +}
     53 + 
     54 +func (language *Language) WriteRule(
     55 + ruleName string,
     56 + input string,
     57 + writer *filewriter.Writer,
     58 +) error {
     59 + inputBytes := []byte(input)
     60 + 
     61 + rootNode, err := sitter.ParseCtx(context.TODO(), inputBytes, language.sitterLanguage)
     62 + if err != nil {
     63 + return fmt.Errorf("parse error: %w", err)
     64 + }
     65 + 
     66 + if err := patterns.CompileRule(
     67 + language.walker,
     68 + ruleName,
     69 + inputBytes,
     70 + rootNode,
     71 + writer,
     72 + ); err != nil {
     73 + return fmt.Errorf("error compiling rule: %w", err)
     74 + }
     75 + 
     76 + return nil
     77 +}
     78 + 
     79 +func (language *Language) Close() {
     80 + language.walker.Close()
     81 +}
     82 + 
  • ■ ■ ■ ■ ■ ■
    pkg/ast/sourcefacts/sourcefacts.go
     1 +package sourcefacts
     2 + 
     3 +import (
     4 + sitter "github.com/smacker/go-tree-sitter"
     5 + 
     6 + "github.com/bearer/bearer/pkg/ast/idgenerator"
     7 + "github.com/bearer/bearer/pkg/ast/languages/ruby/common"
     8 + "github.com/bearer/bearer/pkg/ast/walker"
     9 + writer "github.com/bearer/bearer/pkg/souffle/writer"
     10 + writerbase "github.com/bearer/bearer/pkg/souffle/writer/base"
     11 +)
     12 + 
     13 +type astWriter struct {
     14 + writer.FactWriter
     15 + fileId uint32
     16 + input []byte
     17 + nodeIdGenerator *nodeIdGenerator
     18 + parentNode writerbase.Element
     19 + childIndex uint32
     20 +}
     21 + 
     22 +type nodeIdGenerator struct {
     23 + ids map[*sitter.Node]uint32
     24 + idGenerator *idgenerator.Generator
     25 +}
     26 + 
     27 +func newNodeIdGenerator() *nodeIdGenerator {
     28 + return &nodeIdGenerator{
     29 + ids: make(map[*sitter.Node]uint32),
     30 + idGenerator: idgenerator.New(),
     31 + }
     32 +}
     33 + 
     34 +func (generator *nodeIdGenerator) Get(node *sitter.Node) uint32 {
     35 + if id, cached := generator.ids[node]; cached {
     36 + return id
     37 + }
     38 + 
     39 + id := generator.idGenerator.Get()
     40 + generator.ids[node] = id
     41 + return id
     42 +}
     43 + 
     44 +func WriteFacts(
     45 + walker *walker.Walker,
     46 + fileId uint32,
     47 + input []byte,
     48 + rootNode *sitter.Node,
     49 + writer writer.FactWriter,
     50 +) error {
     51 + w := &astWriter{
     52 + FactWriter: writer,
     53 + fileId: fileId,
     54 + input: input,
     55 + nodeIdGenerator: newNodeIdGenerator(),
     56 + }
     57 + 
     58 + return walker.Walk(rootNode, w.visitNode)
     59 +}
     60 + 
     61 +func (writer *astWriter) visitNode(node *sitter.Node, visitChildren func() error) error {
     62 + nodeElement := writer.node(node)
     63 + 
     64 + if node.Parent() != nil {
     65 + if fname := common.FieldName(node); fname != "" {
     66 + if err := writer.WriteFact("AST_NodeField", writer.node(node.Parent()), nodeElement, writer.Symbol(fname)); err != nil {
     67 + return err
     68 + }
     69 + } else {
     70 + if err := writer.WriteFact(
     71 + "AST_ParentChild",
     72 + writer.node(node.Parent()),
     73 + writer.Unsigned(writer.childIndex),
     74 + nodeElement,
     75 + ); err != nil {
     76 + return err
     77 + }
     78 + 
     79 + writer.childIndex++
     80 + }
     81 + }
     82 + 
     83 + if err := writer.WriteFact("AST_NodeType", nodeElement, writer.Symbol(node.Type())); err != nil {
     84 + return err
     85 + }
     86 + 
     87 + if common.MatchContent(node) {
     88 + if err := writer.WriteFact("AST_NodeContent", nodeElement, writer.Symbol(node.Content(writer.input))); err != nil {
     89 + return err
     90 + }
     91 + }
     92 + 
     93 + if err := writer.WriteFact(
     94 + "AST_NodeLocation",
     95 + nodeElement,
     96 + writer.Record(
     97 + writer.Unsigned(node.StartByte()),
     98 + writer.Unsigned(node.StartPoint().Row+1),
     99 + writer.Unsigned(node.StartPoint().Column+1),
     100 + writer.Unsigned(node.EndPoint().Row+1),
     101 + writer.Unsigned(node.EndPoint().Column+1),
     102 + ),
     103 + ); err != nil {
     104 + return err
     105 + }
     106 + 
     107 + oldChildIndex := writer.childIndex
     108 + writer.childIndex = 0
     109 + err := visitChildren()
     110 + writer.childIndex = oldChildIndex
     111 + 
     112 + return err
     113 +}
     114 + 
     115 +func (writer *astWriter) node(node *sitter.Node) writerbase.Element {
     116 + return writer.Record(
     117 + writer.Unsigned(writer.fileId),
     118 + writer.Unsigned(writer.nodeIdGenerator.Get(node)),
     119 + )
     120 +}
     121 + 
     122 +func nodeEqual(a, b *sitter.Node) bool {
     123 + if a == nil || b == nil {
     124 + return false
     125 + }
     126 + 
     127 + return a.Equal(b)
     128 +}
     129 + 
  • ■ ■ ■ ■ ■ ■
    pkg/ast/walker/walker.go
     1 +package walker
     2 + 
     3 +import (
     4 + sitter "github.com/smacker/go-tree-sitter"
     5 + "github.com/smacker/go-tree-sitter/ruby"
     6 +)
     7 + 
     8 +type Walker struct {
     9 + query *sitter.Query
     10 +}
     11 + 
     12 +type VisitFunction = func(node *sitter.Node, visitChildren func() error) error
     13 + 
     14 +type Cursor struct {
     15 + queryCursor *sitter.QueryCursor
     16 + peekCache *sitter.Node
     17 + onVisit VisitFunction
     18 +}
     19 + 
     20 +func NewWalker(language *sitter.Language) *Walker {
     21 + query, err := sitter.NewQuery([]byte("(_) @node"), ruby.GetLanguage())
     22 + if err != nil {
     23 + panic(err)
     24 + }
     25 + 
     26 + return &Walker{query: query}
     27 +}
     28 + 
     29 +func (walker *Walker) Walk(rootNode *sitter.Node, onVisit VisitFunction) error {
     30 + queryCursor := sitter.NewQueryCursor()
     31 + defer queryCursor.Close()
     32 + 
     33 + queryCursor.Exec(walker.query, rootNode)
     34 + 
     35 + cursor := &Cursor{queryCursor: queryCursor, onVisit: onVisit}
     36 + 
     37 + // Visit the root
     38 + return cursor.visit(cursor.peek())
     39 +}
     40 + 
     41 +func (walker *Walker) Close() {
     42 + walker.query.Close()
     43 +}
     44 + 
     45 +func (cursor *Cursor) visit(node *sitter.Node) error {
     46 + cursor.accept()
     47 + 
     48 + visitedChildren := false
     49 + 
     50 + if err := cursor.onVisit(node, func() error {
     51 + visitedChildren = true
     52 + return cursor.visitChildren(node)
     53 + }); err != nil {
     54 + return err
     55 + }
     56 + 
     57 + if !visitedChildren {
     58 + cursor.skipDescendants(node)
     59 + }
     60 + 
     61 + return nil
     62 +}
     63 + 
     64 +func (cursor *Cursor) visitChildren(node *sitter.Node) error {
     65 + for {
     66 + next := cursor.peek()
     67 + if next == nil || !node.Equal(next.Parent()) {
     68 + return nil
     69 + }
     70 + 
     71 + if err := cursor.visit(next); err != nil {
     72 + return err
     73 + }
     74 + }
     75 +}
     76 + 
     77 +func (cursor *Cursor) skipDescendants(node *sitter.Node) {
     78 + for {
     79 + if !cursor.isAncestorOfNext(node) {
     80 + return
     81 + }
     82 + 
     83 + cursor.accept()
     84 + }
     85 +}
     86 + 
     87 +func (cursor *Cursor) peek() *sitter.Node {
     88 + if cursor.peekCache != nil {
     89 + return cursor.peekCache
     90 + }
     91 + 
     92 + match, exists := cursor.queryCursor.NextMatch()
     93 + if !exists {
     94 + return nil
     95 + }
     96 + 
     97 + cursor.peekCache = match.Captures[0].Node
     98 + return cursor.peekCache
     99 +}
     100 + 
     101 +func (cursor *Cursor) accept() {
     102 + cursor.peekCache = nil
     103 +}
     104 + 
     105 +func (cursor *Cursor) isAncestorOfNext(ancestor *sitter.Node) bool {
     106 + node := cursor.peek()
     107 + if node == nil {
     108 + return false
     109 + }
     110 + 
     111 + for {
     112 + parent := node.Parent()
     113 + if parent == nil {
     114 + return false
     115 + }
     116 + 
     117 + if parent.Equal(ancestor) {
     118 + return true
     119 + }
     120 + 
     121 + node = parent
     122 + }
     123 +}
     124 + 
  • ■ ■ ■ ■ ■ ■
    pkg/souffle/query/query.go
     1 +package query
     2 + 
     3 +import (
     4 + "github.com/bearer/bearer/new/language/implementation"
     5 + builderinput "github.com/bearer/bearer/new/language/patternquery/builder/input"
     6 + "github.com/bearer/bearer/pkg/ast/languages/ruby/patterns"
     7 +)
     8 + 
     9 +type Query struct {
     10 +}
     11 + 
     12 +func Compile(langImplementation implementation.Implementation, ruleName, input string) (*Query, error) {
     13 + processedInput, inputParams, err := builderinput.Process(langImplementation, input)
     14 + if err != nil {
     15 + return nil, err
     16 + }
     17 + 
     18 + if err := patterns.CompileRule(walker, inputParams, ruleName, []byte(processedInput), rootNode, writer); err != nil {
     19 + return nil, err
     20 + }
     21 + 
     22 + return &Query{}, nil
     23 +}
     24 + 
  • ■ ■ ■ ■ ■ ■
    pkg/souffle/rules/generated.cpp
     1 +#define SOUFFLE_GENERATOR_VERSION "2.4-1-g15b114abf"
     2 +#include "souffle/CompiledSouffle.h"
     3 +#include "souffle/SignalHandler.h"
     4 +#include "souffle/SouffleInterface.h"
     5 +#include "souffle/datastructure/BTree.h"
     6 +#include "souffle/io/IOSystem.h"
     7 +#include <any>
     8 +namespace functors {
     9 +extern "C" {
     10 +}
     11 +} //namespace functors
     12 +namespace souffle::t_btree_ii__0_1__11 {
     13 +using namespace souffle;
     14 +struct Type {
     15 +static constexpr Relation::arity_type Arity = 2;
     16 +using t_tuple = Tuple<RamDomain, 2>;
     17 +struct t_comparator_0{
     18 + int operator()(const t_tuple& a, const t_tuple& b) const {
     19 + return (ramBitCast<RamSigned>(a[0]) < ramBitCast<RamSigned>(b[0])) ? -1 : (ramBitCast<RamSigned>(a[0]) > ramBitCast<RamSigned>(b[0])) ? 1 :((ramBitCast<RamSigned>(a[1]) < ramBitCast<RamSigned>(b[1])) ? -1 : (ramBitCast<RamSigned>(a[1]) > ramBitCast<RamSigned>(b[1])) ? 1 :(0));
     20 + }
     21 +bool less(const t_tuple& a, const t_tuple& b) const {
     22 + return (ramBitCast<RamSigned>(a[0]) < ramBitCast<RamSigned>(b[0]))|| ((ramBitCast<RamSigned>(a[0]) == ramBitCast<RamSigned>(b[0])) && ((ramBitCast<RamSigned>(a[1]) < ramBitCast<RamSigned>(b[1]))));
     23 + }
     24 +bool equal(const t_tuple& a, const t_tuple& b) const {
     25 +return (ramBitCast<RamSigned>(a[0]) == ramBitCast<RamSigned>(b[0]))&&(ramBitCast<RamSigned>(a[1]) == ramBitCast<RamSigned>(b[1]));
     26 + }
     27 +};
     28 +using t_ind_0 = btree_set<t_tuple,t_comparator_0>;
     29 +t_ind_0 ind_0;
     30 +using iterator = t_ind_0::iterator;
     31 +struct context {
     32 +t_ind_0::operation_hints hints_0_lower;
     33 +t_ind_0::operation_hints hints_0_upper;
     34 +};
     35 +context createContext() { return context(); }
     36 +bool insert(const t_tuple& t);
     37 +bool insert(const t_tuple& t, context& h);
     38 +bool insert(const RamDomain* ramDomain);
     39 +bool insert(RamDomain a0,RamDomain a1);
     40 +bool contains(const t_tuple& t, context& h) const;
     41 +bool contains(const t_tuple& t) const;
     42 +std::size_t size() const;
     43 +iterator find(const t_tuple& t, context& h) const;
     44 +iterator find(const t_tuple& t) const;
     45 +range<iterator> lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const;
     46 +range<iterator> lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */) const;
     47 +range<t_ind_0::iterator> lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper, context& h) const;
     48 +range<t_ind_0::iterator> lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper) const;
     49 +bool empty() const;
     50 +std::vector<range<iterator>> partition() const;
     51 +void purge();
     52 +iterator begin() const;
     53 +iterator end() const;
     54 +void printStatistics(std::ostream& o) const;
     55 +};
     56 +} // namespace souffle::t_btree_ii__0_1__11
     57 +namespace souffle::t_btree_ii__0_1__11 {
     58 +using namespace souffle;
     59 +using t_ind_0 = Type::t_ind_0;
     60 +using iterator = Type::iterator;
     61 +using context = Type::context;
     62 +bool Type::insert(const t_tuple& t) {
     63 +context h;
     64 +return insert(t, h);
     65 +}
     66 +bool Type::insert(const t_tuple& t, context& h) {
     67 +if (ind_0.insert(t, h.hints_0_lower)) {
     68 +return true;
     69 +} else return false;
     70 +}
     71 +bool Type::insert(const RamDomain* ramDomain) {
     72 +RamDomain data[2];
     73 +std::copy(ramDomain, ramDomain + 2, data);
     74 +const t_tuple& tuple = reinterpret_cast<const t_tuple&>(data);
     75 +context h;
     76 +return insert(tuple, h);
     77 +}
     78 +bool Type::insert(RamDomain a0,RamDomain a1) {
     79 +RamDomain data[2] = {a0,a1};
     80 +return insert(data);
     81 +}
     82 +bool Type::contains(const t_tuple& t, context& h) const {
     83 +return ind_0.contains(t, h.hints_0_lower);
     84 +}
     85 +bool Type::contains(const t_tuple& t) const {
     86 +context h;
     87 +return contains(t, h);
     88 +}
     89 +std::size_t Type::size() const {
     90 +return ind_0.size();
     91 +}
     92 +iterator Type::find(const t_tuple& t, context& h) const {
     93 +return ind_0.find(t, h.hints_0_lower);
     94 +}
     95 +iterator Type::find(const t_tuple& t) const {
     96 +context h;
     97 +return find(t, h);
     98 +}
     99 +range<iterator> Type::lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const {
     100 +return range<iterator>(ind_0.begin(),ind_0.end());
     101 +}
     102 +range<iterator> Type::lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */) const {
     103 +return range<iterator>(ind_0.begin(),ind_0.end());
     104 +}
     105 +range<t_ind_0::iterator> Type::lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper, context& h) const {
     106 +t_comparator_0 comparator;
     107 +int cmp = comparator(lower, upper);
     108 +if (cmp == 0) {
     109 + auto pos = ind_0.find(lower, h.hints_0_lower);
     110 + auto fin = ind_0.end();
     111 + if (pos != fin) {fin = pos; ++fin;}
     112 + return make_range(pos, fin);
     113 +}
     114 +if (cmp > 0) {
     115 + return make_range(ind_0.end(), ind_0.end());
     116 +}
     117 +return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper));
     118 +}
     119 +range<t_ind_0::iterator> Type::lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper) const {
     120 +context h;
     121 +return lowerUpperRange_11(lower,upper,h);
     122 +}
     123 +bool Type::empty() const {
     124 +return ind_0.empty();
     125 +}
     126 +std::vector<range<iterator>> Type::partition() const {
     127 +return ind_0.getChunks(400);
     128 +}
     129 +void Type::purge() {
     130 +ind_0.clear();
     131 +}
     132 +iterator Type::begin() const {
     133 +return ind_0.begin();
     134 +}
     135 +iterator Type::end() const {
     136 +return ind_0.end();
     137 +}
     138 +void Type::printStatistics(std::ostream& o) const {
     139 +o << " arity 2 direct b-tree index 0 lex-order [0,1]\n";
     140 +ind_0.printStats(o);
     141 +}
     142 +} // namespace souffle::t_btree_ii__0_1__11
     143 +namespace souffle::t_btree_iii__0_2_1__101__111 {
     144 +using namespace souffle;
     145 +struct Type {
     146 +static constexpr Relation::arity_type Arity = 3;
     147 +using t_tuple = Tuple<RamDomain, 3>;
     148 +struct t_comparator_0{
     149 + int operator()(const t_tuple& a, const t_tuple& b) const {
     150 + return (ramBitCast<RamSigned>(a[0]) < ramBitCast<RamSigned>(b[0])) ? -1 : (ramBitCast<RamSigned>(a[0]) > ramBitCast<RamSigned>(b[0])) ? 1 :((ramBitCast<RamSigned>(a[2]) < ramBitCast<RamSigned>(b[2])) ? -1 : (ramBitCast<RamSigned>(a[2]) > ramBitCast<RamSigned>(b[2])) ? 1 :((ramBitCast<RamSigned>(a[1]) < ramBitCast<RamSigned>(b[1])) ? -1 : (ramBitCast<RamSigned>(a[1]) > ramBitCast<RamSigned>(b[1])) ? 1 :(0)));
     151 + }
     152 +bool less(const t_tuple& a, const t_tuple& b) const {
     153 + return (ramBitCast<RamSigned>(a[0]) < ramBitCast<RamSigned>(b[0]))|| ((ramBitCast<RamSigned>(a[0]) == ramBitCast<RamSigned>(b[0])) && ((ramBitCast<RamSigned>(a[2]) < ramBitCast<RamSigned>(b[2]))|| ((ramBitCast<RamSigned>(a[2]) == ramBitCast<RamSigned>(b[2])) && ((ramBitCast<RamSigned>(a[1]) < ramBitCast<RamSigned>(b[1]))))));
     154 + }
     155 +bool equal(const t_tuple& a, const t_tuple& b) const {
     156 +return (ramBitCast<RamSigned>(a[0]) == ramBitCast<RamSigned>(b[0]))&&(ramBitCast<RamSigned>(a[2]) == ramBitCast<RamSigned>(b[2]))&&(ramBitCast<RamSigned>(a[1]) == ramBitCast<RamSigned>(b[1]));
     157 + }
     158 +};
     159 +using t_ind_0 = btree_set<t_tuple,t_comparator_0>;
     160 +t_ind_0 ind_0;
     161 +using iterator = t_ind_0::iterator;
     162 +struct context {
     163 +t_ind_0::operation_hints hints_0_lower;
     164 +t_ind_0::operation_hints hints_0_upper;
     165 +};
     166 +context createContext() { return context(); }
     167 +bool insert(const t_tuple& t);
     168 +bool insert(const t_tuple& t, context& h);
     169 +bool insert(const RamDomain* ramDomain);
     170 +bool insert(RamDomain a0,RamDomain a1,RamDomain a2);
     171 +bool contains(const t_tuple& t, context& h) const;
     172 +bool contains(const t_tuple& t) const;
     173 +std::size_t size() const;
     174 +iterator find(const t_tuple& t, context& h) const;
     175 +iterator find(const t_tuple& t) const;
     176 +range<iterator> lowerUpperRange_000(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const;
     177 +range<iterator> lowerUpperRange_000(const t_tuple& /* lower */, const t_tuple& /* upper */) const;
     178 +range<t_ind_0::iterator> lowerUpperRange_101(const t_tuple& lower, const t_tuple& upper, context& h) const;
     179 +range<t_ind_0::iterator> lowerUpperRange_101(const t_tuple& lower, const t_tuple& upper) const;
     180 +range<t_ind_0::iterator> lowerUpperRange_111(const t_tuple& lower, const t_tuple& upper, context& h) const;
     181 +range<t_ind_0::iterator> lowerUpperRange_111(const t_tuple& lower, const t_tuple& upper) const;
     182 +bool empty() const;
     183 +std::vector<range<iterator>> partition() const;
     184 +void purge();
     185 +iterator begin() const;
     186 +iterator end() const;
     187 +void printStatistics(std::ostream& o) const;
     188 +};
     189 +} // namespace souffle::t_btree_iii__0_2_1__101__111
     190 +namespace souffle::t_btree_iii__0_2_1__101__111 {
     191 +using namespace souffle;
     192 +using t_ind_0 = Type::t_ind_0;
     193 +using iterator = Type::iterator;
     194 +using context = Type::context;
     195 +bool Type::insert(const t_tuple& t) {
     196 +context h;
     197 +return insert(t, h);
     198 +}
     199 +bool Type::insert(const t_tuple& t, context& h) {
     200 +if (ind_0.insert(t, h.hints_0_lower)) {
     201 +return true;
     202 +} else return false;
     203 +}
     204 +bool Type::insert(const RamDomain* ramDomain) {
     205 +RamDomain data[3];
     206 +std::copy(ramDomain, ramDomain + 3, data);
     207 +const t_tuple& tuple = reinterpret_cast<const t_tuple&>(data);
     208 +context h;
     209 +return insert(tuple, h);
     210 +}
     211 +bool Type::insert(RamDomain a0,RamDomain a1,RamDomain a2) {
     212 +RamDomain data[3] = {a0,a1,a2};
     213 +return insert(data);
     214 +}
     215 +bool Type::contains(const t_tuple& t, context& h) const {
     216 +return ind_0.contains(t, h.hints_0_lower);
     217 +}
     218 +bool Type::contains(const t_tuple& t) const {
     219 +context h;
     220 +return contains(t, h);
     221 +}
     222 +std::size_t Type::size() const {
     223 +return ind_0.size();
     224 +}
     225 +iterator Type::find(const t_tuple& t, context& h) const {
     226 +return ind_0.find(t, h.hints_0_lower);
     227 +}
     228 +iterator Type::find(const t_tuple& t) const {
     229 +context h;
     230 +return find(t, h);
     231 +}
     232 +range<iterator> Type::lowerUpperRange_000(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const {
     233 +return range<iterator>(ind_0.begin(),ind_0.end());
     234 +}
     235 +range<iterator> Type::lowerUpperRange_000(const t_tuple& /* lower */, const t_tuple& /* upper */) const {
     236 +return range<iterator>(ind_0.begin(),ind_0.end());
     237 +}
     238 +range<t_ind_0::iterator> Type::lowerUpperRange_101(const t_tuple& lower, const t_tuple& upper, context& h) const {
     239 +t_comparator_0 comparator;
     240 +int cmp = comparator(lower, upper);
     241 +if (cmp > 0) {
     242 + return make_range(ind_0.end(), ind_0.end());
     243 +}
     244 +return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper));
     245 +}
     246 +range<t_ind_0::iterator> Type::lowerUpperRange_101(const t_tuple& lower, const t_tuple& upper) const {
     247 +context h;
     248 +return lowerUpperRange_101(lower,upper,h);
     249 +}
     250 +range<t_ind_0::iterator> Type::lowerUpperRange_111(const t_tuple& lower, const t_tuple& upper, context& h) const {
     251 +t_comparator_0 comparator;
     252 +int cmp = comparator(lower, upper);
     253 +if (cmp == 0) {
     254 + auto pos = ind_0.find(lower, h.hints_0_lower);
     255 + auto fin = ind_0.end();
     256 + if (pos != fin) {fin = pos; ++fin;}
     257 + return make_range(pos, fin);
     258 +}
     259 +if (cmp > 0) {
     260 + return make_range(ind_0.end(), ind_0.end());
     261 +}
     262 +return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper));
     263 +}
     264 +range<t_ind_0::iterator> Type::lowerUpperRange_111(const t_tuple& lower, const t_tuple& upper) const {
     265 +context h;
     266 +return lowerUpperRange_111(lower,upper,h);
     267 +}
     268 +bool Type::empty() const {
     269 +return ind_0.empty();
     270 +}
     271 +std::vector<range<iterator>> Type::partition() const {
     272 +return ind_0.getChunks(400);
     273 +}
     274 +void Type::purge() {
     275 +ind_0.clear();
     276 +}
     277 +iterator Type::begin() const {
     278 +return ind_0.begin();
     279 +}
     280 +iterator Type::end() const {
     281 +return ind_0.end();
     282 +}
     283 +void Type::printStatistics(std::ostream& o) const {
     284 +o << " arity 3 direct b-tree index 0 lex-order [0,2,1]\n";
     285 +ind_0.printStats(o);
     286 +}
     287 +} // namespace souffle::t_btree_iii__0_2_1__101__111
     288 +namespace souffle::t_btree_ii__0_1__11__10 {
     289 +using namespace souffle;
     290 +struct Type {
     291 +static constexpr Relation::arity_type Arity = 2;
     292 +using t_tuple = Tuple<RamDomain, 2>;
     293 +struct t_comparator_0{
     294 + int operator()(const t_tuple& a, const t_tuple& b) const {
     295 + return (ramBitCast<RamSigned>(a[0]) < ramBitCast<RamSigned>(b[0])) ? -1 : (ramBitCast<RamSigned>(a[0]) > ramBitCast<RamSigned>(b[0])) ? 1 :((ramBitCast<RamSigned>(a[1]) < ramBitCast<RamSigned>(b[1])) ? -1 : (ramBitCast<RamSigned>(a[1]) > ramBitCast<RamSigned>(b[1])) ? 1 :(0));
     296 + }
     297 +bool less(const t_tuple& a, const t_tuple& b) const {
     298 + return (ramBitCast<RamSigned>(a[0]) < ramBitCast<RamSigned>(b[0]))|| ((ramBitCast<RamSigned>(a[0]) == ramBitCast<RamSigned>(b[0])) && ((ramBitCast<RamSigned>(a[1]) < ramBitCast<RamSigned>(b[1]))));
     299 + }
     300 +bool equal(const t_tuple& a, const t_tuple& b) const {
     301 +return (ramBitCast<RamSigned>(a[0]) == ramBitCast<RamSigned>(b[0]))&&(ramBitCast<RamSigned>(a[1]) == ramBitCast<RamSigned>(b[1]));
     302 + }
     303 +};
     304 +using t_ind_0 = btree_set<t_tuple,t_comparator_0>;
     305 +t_ind_0 ind_0;
     306 +using iterator = t_ind_0::iterator;
     307 +struct context {
     308 +t_ind_0::operation_hints hints_0_lower;
     309 +t_ind_0::operation_hints hints_0_upper;
     310 +};
     311 +context createContext() { return context(); }
     312 +bool insert(const t_tuple& t);
     313 +bool insert(const t_tuple& t, context& h);
     314 +bool insert(const RamDomain* ramDomain);
     315 +bool insert(RamDomain a0,RamDomain a1);
     316 +bool contains(const t_tuple& t, context& h) const;
     317 +bool contains(const t_tuple& t) const;
     318 +std::size_t size() const;
     319 +iterator find(const t_tuple& t, context& h) const;
     320 +iterator find(const t_tuple& t) const;
     321 +range<iterator> lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const;
     322 +range<iterator> lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */) const;
     323 +range<t_ind_0::iterator> lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper, context& h) const;
     324 +range<t_ind_0::iterator> lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper) const;
     325 +range<t_ind_0::iterator> lowerUpperRange_10(const t_tuple& lower, const t_tuple& upper, context& h) const;
     326 +range<t_ind_0::iterator> lowerUpperRange_10(const t_tuple& lower, const t_tuple& upper) const;
     327 +bool empty() const;
     328 +std::vector<range<iterator>> partition() const;
     329 +void purge();
     330 +iterator begin() const;
     331 +iterator end() const;
     332 +void printStatistics(std::ostream& o) const;
     333 +};
     334 +} // namespace souffle::t_btree_ii__0_1__11__10
     335 +namespace souffle::t_btree_ii__0_1__11__10 {
     336 +using namespace souffle;
     337 +using t_ind_0 = Type::t_ind_0;
     338 +using iterator = Type::iterator;
     339 +using context = Type::context;
     340 +bool Type::insert(const t_tuple& t) {
     341 +context h;
     342 +return insert(t, h);
     343 +}
     344 +bool Type::insert(const t_tuple& t, context& h) {
     345 +if (ind_0.insert(t, h.hints_0_lower)) {
     346 +return true;
     347 +} else return false;
     348 +}
     349 +bool Type::insert(const RamDomain* ramDomain) {
     350 +RamDomain data[2];
     351 +std::copy(ramDomain, ramDomain + 2, data);
     352 +const t_tuple& tuple = reinterpret_cast<const t_tuple&>(data);
     353 +context h;
     354 +return insert(tuple, h);
     355 +}
     356 +bool Type::insert(RamDomain a0,RamDomain a1) {
     357 +RamDomain data[2] = {a0,a1};
     358 +return insert(data);
     359 +}
     360 +bool Type::contains(const t_tuple& t, context& h) const {
     361 +return ind_0.contains(t, h.hints_0_lower);
     362 +}
     363 +bool Type::contains(const t_tuple& t) const {
     364 +context h;
     365 +return contains(t, h);
     366 +}
     367 +std::size_t Type::size() const {
     368 +return ind_0.size();
     369 +}
     370 +iterator Type::find(const t_tuple& t, context& h) const {
     371 +return ind_0.find(t, h.hints_0_lower);
     372 +}
     373 +iterator Type::find(const t_tuple& t) const {
     374 +context h;
     375 +return find(t, h);
     376 +}
     377 +range<iterator> Type::lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const {
     378 +return range<iterator>(ind_0.begin(),ind_0.end());
     379 +}
     380 +range<iterator> Type::lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */) const {
     381 +return range<iterator>(ind_0.begin(),ind_0.end());
     382 +}
     383 +range<t_ind_0::iterator> Type::lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper, context& h) const {
     384 +t_comparator_0 comparator;
     385 +int cmp = comparator(lower, upper);
     386 +if (cmp == 0) {
     387 + auto pos = ind_0.find(lower, h.hints_0_lower);
     388 + auto fin = ind_0.end();
     389 + if (pos != fin) {fin = pos; ++fin;}
     390 + return make_range(pos, fin);
     391 +}
     392 +if (cmp > 0) {
     393 + return make_range(ind_0.end(), ind_0.end());
     394 +}
     395 +return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper));
     396 +}
     397 +range<t_ind_0::iterator> Type::lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper) const {
     398 +context h;
     399 +return lowerUpperRange_11(lower,upper,h);
     400 +}
     401 +range<t_ind_0::iterator> Type::lowerUpperRange_10(const t_tuple& lower, const t_tuple& upper, context& h) const {
     402 +t_comparator_0 comparator;
     403 +int cmp = comparator(lower, upper);
     404 +if (cmp > 0) {
     405 + return make_range(ind_0.end(), ind_0.end());
     406 +}
     407 +return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper));
     408 +}
     409 +range<t_ind_0::iterator> Type::lowerUpperRange_10(const t_tuple& lower, const t_tuple& upper) const {
     410 +context h;
     411 +return lowerUpperRange_10(lower,upper,h);
     412 +}
     413 +bool Type::empty() const {
     414 +return ind_0.empty();
     415 +}
     416 +std::vector<range<iterator>> Type::partition() const {
     417 +return ind_0.getChunks(400);
     418 +}
     419 +void Type::purge() {
     420 +ind_0.clear();
     421 +}
     422 +iterator Type::begin() const {
     423 +return ind_0.begin();
     424 +}
     425 +iterator Type::end() const {
     426 +return ind_0.end();
     427 +}
     428 +void Type::printStatistics(std::ostream& o) const {
     429 +o << " arity 2 direct b-tree index 0 lex-order [0,1]\n";
     430 +ind_0.printStats(o);
     431 +}
     432 +} // namespace souffle::t_btree_ii__0_1__11__10
     433 +namespace souffle::t_btree_ii__1_0__11__01 {
     434 +using namespace souffle;
     435 +struct Type {
     436 +static constexpr Relation::arity_type Arity = 2;
     437 +using t_tuple = Tuple<RamDomain, 2>;
     438 +struct t_comparator_0{
     439 + int operator()(const t_tuple& a, const t_tuple& b) const {
     440 + return (ramBitCast<RamSigned>(a[1]) < ramBitCast<RamSigned>(b[1])) ? -1 : (ramBitCast<RamSigned>(a[1]) > ramBitCast<RamSigned>(b[1])) ? 1 :((ramBitCast<RamSigned>(a[0]) < ramBitCast<RamSigned>(b[0])) ? -1 : (ramBitCast<RamSigned>(a[0]) > ramBitCast<RamSigned>(b[0])) ? 1 :(0));
     441 + }
     442 +bool less(const t_tuple& a, const t_tuple& b) const {
     443 + return (ramBitCast<RamSigned>(a[1]) < ramBitCast<RamSigned>(b[1]))|| ((ramBitCast<RamSigned>(a[1]) == ramBitCast<RamSigned>(b[1])) && ((ramBitCast<RamSigned>(a[0]) < ramBitCast<RamSigned>(b[0]))));
     444 + }
     445 +bool equal(const t_tuple& a, const t_tuple& b) const {
     446 +return (ramBitCast<RamSigned>(a[1]) == ramBitCast<RamSigned>(b[1]))&&(ramBitCast<RamSigned>(a[0]) == ramBitCast<RamSigned>(b[0]));
     447 + }
     448 +};
     449 +using t_ind_0 = btree_set<t_tuple,t_comparator_0>;
     450 +t_ind_0 ind_0;
     451 +using iterator = t_ind_0::iterator;
     452 +struct context {
     453 +t_ind_0::operation_hints hints_0_lower;
     454 +t_ind_0::operation_hints hints_0_upper;
     455 +};
     456 +context createContext() { return context(); }
     457 +bool insert(const t_tuple& t);
     458 +bool insert(const t_tuple& t, context& h);
     459 +bool insert(const RamDomain* ramDomain);
     460 +bool insert(RamDomain a0,RamDomain a1);
     461 +bool contains(const t_tuple& t, context& h) const;
     462 +bool contains(const t_tuple& t) const;
     463 +std::size_t size() const;
     464 +iterator find(const t_tuple& t, context& h) const;
     465 +iterator find(const t_tuple& t) const;
     466 +range<iterator> lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const;
     467 +range<iterator> lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */) const;
     468 +range<t_ind_0::iterator> lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper, context& h) const;
     469 +range<t_ind_0::iterator> lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper) const;
     470 +range<t_ind_0::iterator> lowerUpperRange_01(const t_tuple& lower, const t_tuple& upper, context& h) const;
     471 +range<t_ind_0::iterator> lowerUpperRange_01(const t_tuple& lower, const t_tuple& upper) const;
     472 +bool empty() const;
     473 +std::vector<range<iterator>> partition() const;
     474 +void purge();
     475 +iterator begin() const;
     476 +iterator end() const;
     477 +void printStatistics(std::ostream& o) const;
     478 +};
     479 +} // namespace souffle::t_btree_ii__1_0__11__01
     480 +namespace souffle::t_btree_ii__1_0__11__01 {
     481 +using namespace souffle;
     482 +using t_ind_0 = Type::t_ind_0;
     483 +using iterator = Type::iterator;
     484 +using context = Type::context;
     485 +bool Type::insert(const t_tuple& t) {
     486 +context h;
     487 +return insert(t, h);
     488 +}
     489 +bool Type::insert(const t_tuple& t, context& h) {
     490 +if (ind_0.insert(t, h.hints_0_lower)) {
     491 +return true;
     492 +} else return false;
     493 +}
     494 +bool Type::insert(const RamDomain* ramDomain) {
     495 +RamDomain data[2];
     496 +std::copy(ramDomain, ramDomain + 2, data);
     497 +const t_tuple& tuple = reinterpret_cast<const t_tuple&>(data);
     498 +context h;
     499 +return insert(tuple, h);
     500 +}
     501 +bool Type::insert(RamDomain a0,RamDomain a1) {
     502 +RamDomain data[2] = {a0,a1};
     503 +return insert(data);
     504 +}
     505 +bool Type::contains(const t_tuple& t, context& h) const {
     506 +return ind_0.contains(t, h.hints_0_lower);
     507 +}
     508 +bool Type::contains(const t_tuple& t) const {
     509 +context h;
     510 +return contains(t, h);
     511 +}
     512 +std::size_t Type::size() const {
     513 +return ind_0.size();
     514 +}
     515 +iterator Type::find(const t_tuple& t, context& h) const {
     516 +return ind_0.find(t, h.hints_0_lower);
     517 +}
     518 +iterator Type::find(const t_tuple& t) const {
     519 +context h;
     520 +return find(t, h);
     521 +}
     522 +range<iterator> Type::lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const {
     523 +return range<iterator>(ind_0.begin(),ind_0.end());
     524 +}
     525 +range<iterator> Type::lowerUpperRange_00(const t_tuple& /* lower */, const t_tuple& /* upper */) const {
     526 +return range<iterator>(ind_0.begin(),ind_0.end());
     527 +}
     528 +range<t_ind_0::iterator> Type::lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper, context& h) const {
     529 +t_comparator_0 comparator;
     530 +int cmp = comparator(lower, upper);
     531 +if (cmp == 0) {
     532 + auto pos = ind_0.find(lower, h.hints_0_lower);
     533 + auto fin = ind_0.end();
     534 + if (pos != fin) {fin = pos; ++fin;}
     535 + return make_range(pos, fin);
     536 +}
     537 +if (cmp > 0) {
     538 + return make_range(ind_0.end(), ind_0.end());
     539 +}
     540 +return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper));
     541 +}
     542 +range<t_ind_0::iterator> Type::lowerUpperRange_11(const t_tuple& lower, const t_tuple& upper) const {
     543 +context h;
     544 +return lowerUpperRange_11(lower,upper,h);
     545 +}
     546 +range<t_ind_0::iterator> Type::lowerUpperRange_01(const t_tuple& lower, const t_tuple& upper, context& h) const {
     547 +t_comparator_0 comparator;
     548 +int cmp = comparator(lower, upper);
     549 +if (cmp > 0) {
     550 + return make_range(ind_0.end(), ind_0.end());
     551 +}
     552 +return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper));
     553 +}
     554 +range<t_ind_0::iterator> Type::lowerUpperRange_01(const t_tuple& lower, const t_tuple& upper) const {
     555 +context h;
     556 +return lowerUpperRange_01(lower,upper,h);
     557 +}
     558 +bool Type::empty() const {
     559 +return ind_0.empty();
     560 +}
     561 +std::vector<range<iterator>> Type::partition() const {
     562 +return ind_0.getChunks(400);
     563 +}
     564 +void Type::purge() {
     565 +ind_0.clear();
     566 +}
     567 +iterator Type::begin() const {
     568 +return ind_0.begin();
     569 +}
     570 +iterator Type::end() const {
     571 +return ind_0.end();
     572 +}
     573 +void Type::printStatistics(std::ostream& o) const {
     574 +o << " arity 2 direct b-tree index 0 lex-order [1,0]\n";
     575 +ind_0.printStats(o);
     576 +}
     577 +} // namespace souffle::t_btree_ii__1_0__11__01
     578 +namespace souffle::t_btree_iui__0_1_2__110__111 {
     579 +using namespace souffle;
     580 +struct Type {
     581 +static constexpr Relation::arity_type Arity = 3;
     582 +using t_tuple = Tuple<RamDomain, 3>;
     583 +struct t_comparator_0{
     584 + int operator()(const t_tuple& a, const t_tuple& b) const {
     585 + return (ramBitCast<RamSigned>(a[0]) < ramBitCast<RamSigned>(b[0])) ? -1 : (ramBitCast<RamSigned>(a[0]) > ramBitCast<RamSigned>(b[0])) ? 1 :((ramBitCast<RamUnsigned>(a[1]) < ramBitCast<RamUnsigned>(b[1])) ? -1 : (ramBitCast<RamUnsigned>(a[1]) > ramBitCast<RamUnsigned>(b[1])) ? 1 :((ramBitCast<RamSigned>(a[2]) < ramBitCast<RamSigned>(b[2])) ? -1 : (ramBitCast<RamSigned>(a[2]) > ramBitCast<RamSigned>(b[2])) ? 1 :(0)));
     586 + }
     587 +bool less(const t_tuple& a, const t_tuple& b) const {
     588 + return (ramBitCast<RamSigned>(a[0]) < ramBitCast<RamSigned>(b[0]))|| ((ramBitCast<RamSigned>(a[0]) == ramBitCast<RamSigned>(b[0])) && ((ramBitCast<RamUnsigned>(a[1]) < ramBitCast<RamUnsigned>(b[1]))|| ((ramBitCast<RamUnsigned>(a[1]) == ramBitCast<RamUnsigned>(b[1])) && ((ramBitCast<RamSigned>(a[2]) < ramBitCast<RamSigned>(b[2]))))));
     589 + }
     590 +bool equal(const t_tuple& a, const t_tuple& b) const {
     591 +return (ramBitCast<RamSigned>(a[0]) == ramBitCast<RamSigned>(b[0]))&&(ramBitCast<RamUnsigned>(a[1]) == ramBitCast<RamUnsigned>(b[1]))&&(ramBitCast<RamSigned>(a[2]) == ramBitCast<RamSigned>(b[2]));
     592 + }
     593 +};
     594 +using t_ind_0 = btree_set<t_tuple,t_comparator_0>;
     595 +t_ind_0 ind_0;
     596 +using iterator = t_ind_0::iterator;
     597 +struct context {
     598 +t_ind_0::operation_hints hints_0_lower;
     599 +t_ind_0::operation_hints hints_0_upper;
     600 +};
     601 +context createContext() { return context(); }
     602 +bool insert(const t_tuple& t);
     603 +bool insert(const t_tuple& t, context& h);
     604 +bool insert(const RamDomain* ramDomain);
     605 +bool insert(RamDomain a0,RamDomain a1,RamDomain a2);
     606 +bool contains(const t_tuple& t, context& h) const;
     607 +bool contains(const t_tuple& t) const;
     608 +std::size_t size() const;
     609 +iterator find(const t_tuple& t, context& h) const;
     610 +iterator find(const t_tuple& t) const;
     611 +range<iterator> lowerUpperRange_000(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const;
     612 +range<iterator> lowerUpperRange_000(const t_tuple& /* lower */, const t_tuple& /* upper */) const;
     613 +range<t_ind_0::iterator> lowerUpperRange_110(const t_tuple& lower, const t_tuple& upper, context& h) const;
     614 +range<t_ind_0::iterator> lowerUpperRange_110(const t_tuple& lower, const t_tuple& upper) const;
     615 +range<t_ind_0::iterator> lowerUpperRange_111(const t_tuple& lower, const t_tuple& upper, context& h) const;
     616 +range<t_ind_0::iterator> lowerUpperRange_111(const t_tuple& lower, const t_tuple& upper) const;
     617 +bool empty() const;
     618 +std::vector<range<iterator>> partition() const;
     619 +void purge();
     620 +iterator begin() const;
     621 +iterator end() const;
     622 +void printStatistics(std::ostream& o) const;
     623 +};
     624 +} // namespace souffle::t_btree_iui__0_1_2__110__111
     625 +namespace souffle::t_btree_iui__0_1_2__110__111 {
     626 +using namespace souffle;
     627 +using t_ind_0 = Type::t_ind_0;
     628 +using iterator = Type::iterator;
     629 +using context = Type::context;
     630 +bool Type::insert(const t_tuple& t) {
     631 +context h;
     632 +return insert(t, h);
     633 +}
     634 +bool Type::insert(const t_tuple& t, context& h) {
     635 +if (ind_0.insert(t, h.hints_0_lower)) {
     636 +return true;
     637 +} else return false;
     638 +}
     639 +bool Type::insert(const RamDomain* ramDomain) {
     640 +RamDomain data[3];
     641 +std::copy(ramDomain, ramDomain + 3, data);
     642 +const t_tuple& tuple = reinterpret_cast<const t_tuple&>(data);
     643 +context h;
     644 +return insert(tuple, h);
     645 +}
     646 +bool Type::insert(RamDomain a0,RamDomain a1,RamDomain a2) {
     647 +RamDomain data[3] = {a0,a1,a2};
     648 +return insert(data);
     649 +}
     650 +bool Type::contains(const t_tuple& t, context& h) const {
     651 +return ind_0.contains(t, h.hints_0_lower);
     652 +}
     653 +bool Type::contains(const t_tuple& t) const {
     654 +context h;
     655 +return contains(t, h);
     656 +}
     657 +std::size_t Type::size() const {
     658 +return ind_0.size();
     659 +}
     660 +iterator Type::find(const t_tuple& t, context& h) const {
     661 +return ind_0.find(t, h.hints_0_lower);
     662 +}
     663 +iterator Type::find(const t_tuple& t) const {
     664 +context h;
     665 +return find(t, h);
     666 +}
     667 +range<iterator> Type::lowerUpperRange_000(const t_tuple& /* lower */, const t_tuple& /* upper */, context& /* h */) const {
     668 +return range<iterator>(ind_0.begin(),ind_0.end());
     669 +}
     670 +range<iterator> Type::lowerUpperRange_000(const t_tuple& /* lower */, const t_tuple& /* upper */) const {
     671 +return range<iterator>(ind_0.begin(),ind_0.end());
     672 +}
     673 +range<t_ind_0::iterator> Type::lowerUpperRange_110(const t_tuple& lower, const t_tuple& upper, context& h) const {
     674 +t_comparator_0 comparator;
     675 +int cmp = comparator(lower, upper);
     676 +if (cmp > 0) {
     677 + return make_range(ind_0.end(), ind_0.end());
     678 +}
     679 +return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper));
     680 +}
     681 +range<t_ind_0::iterator> Type::lowerUpperRange_110(const t_tuple& lower, const t_tuple& upper) const {
     682 +context h;
     683 +return lowerUpperRange_110(lower,upper,h);
     684 +}
     685 +range<t_ind_0::iterator> Type::lowerUpperRange_111(const t_tuple& lower, const t_tuple& upper, context& h) const {
     686 +t_comparator_0 comparator;
     687 +int cmp = comparator(lower, upper);
     688 +if (cmp == 0) {
     689 + auto pos = ind_0.find(lower, h.hints_0_lower);
     690 + auto fin = ind_0.end();
     691 + if (pos != fin) {fin = pos; ++fin;}
     692 + return make_range(pos, fin);
     693 +}
     694 +if (cmp > 0) {
     695 + return make_range(ind_0.end(), ind_0.end());
     696 +}
     697 +return make_range(ind_0.lower_bound(lower, h.hints_0_lower), ind_0.upper_bound(upper, h.hints_0_upper));
     698 +}
     699 +range<t_ind_0::iterator> Type::lowerUpperRange_111(const t_tuple& lower, const t_tuple& upper) const {
     700 +context h;
     701 +return lowerUpperRange_111(lower,upper,h);
     702 +}
     703 +bool Type::empty() const {
     704 +return ind_0.empty();
     705 +}
     706 +std::vector<range<iterator>> Type::partition() const {
     707 +return ind_0.getChunks(400);
     708 +}
     709 +void Type::purge() {
     710 +ind_0.clear();
     711 +}
     712 +iterator Type::begin() const {
     713 +return ind_0.begin();
     714 +}
     715 +iterator Type::end() const {
     716 +return ind_0.end();
     717 +}
     718 +void Type::printStatistics(std::ostream& o) const {
     719 +o << " arity 3 direct b-tree index 0 lex-order [0,1,2]\n";
     720 +ind_0.printStats(o);
     721 +}
     722 +} // namespace souffle::t_btree_iui__0_1_2__110__111
     723 +namespace souffle {
     724 +using namespace souffle;
     725 +class Stratum_AST_NodeContent_fd51b4bf60caba3f {
     726 +public:
     727 + Stratum_AST_NodeContent_fd51b4bf60caba3f(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_ii__0_1__11::Type& rel_AST_NodeContent_b2f3666572e60754);
     728 +void run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret);
     729 +private:
     730 +SymbolTable& symTable;
     731 +RecordTable& recordTable;
     732 +ConcurrentCache<std::string,std::regex>& regexCache;
     733 +bool& pruneImdtRels;
     734 +bool& performIO;
     735 +SignalHandler*& signalHandler;
     736 +std::atomic<std::size_t>& iter;
     737 +std::atomic<RamDomain>& ctr;
     738 +std::string& inputDirectory;
     739 +std::string& outputDirectory;
     740 +t_btree_ii__0_1__11::Type* rel_AST_NodeContent_b2f3666572e60754;
     741 +};
     742 +} // namespace souffle
     743 +namespace souffle {
     744 +using namespace souffle;
     745 + Stratum_AST_NodeContent_fd51b4bf60caba3f::Stratum_AST_NodeContent_fd51b4bf60caba3f(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_ii__0_1__11::Type& rel_AST_NodeContent_b2f3666572e60754):
     746 +symTable(symTable),
     747 +recordTable(recordTable),
     748 +regexCache(regexCache),
     749 +pruneImdtRels(pruneImdtRels),
     750 +performIO(performIO),
     751 +signalHandler(signalHandler),
     752 +iter(iter),
     753 +ctr(ctr),
     754 +inputDirectory(inputDirectory),
     755 +outputDirectory(outputDirectory),
     756 +rel_AST_NodeContent_b2f3666572e60754(&rel_AST_NodeContent_b2f3666572e60754){
     757 +}
     758 + 
     759 +void Stratum_AST_NodeContent_fd51b4bf60caba3f::run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret){
     760 +if (performIO) {
     761 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","node\tcontent"},{"auxArity","0"},{"fact-dir","."},{"name","AST_NodeContent"},{"operation","input"},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 2, \"params\": [\"node\", \"content\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 2, \"types\": [\"r:AST_Node\", \"s:AST_Content\"]}}"}});
     762 +if (!inputDirectory.empty()) {directiveMap["fact-dir"] = inputDirectory;}
     763 +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_AST_NodeContent_b2f3666572e60754);
     764 +} catch (std::exception& e) {std::cerr << "Error loading AST_NodeContent data: " << e.what() << '\n';
     765 +exit(1);
     766 +}
     767 +}
     768 +}
     769 + 
     770 +} // namespace souffle
     771 + 
     772 +namespace souffle {
     773 +using namespace souffle;
     774 +class Stratum_AST_NodeField_cc21295739297165 {
     775 +public:
     776 + Stratum_AST_NodeField_cc21295739297165(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_iii__0_2_1__101__111::Type& rel_AST_NodeField_ca02670731ce3c99);
     777 +void run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret);
     778 +private:
     779 +SymbolTable& symTable;
     780 +RecordTable& recordTable;
     781 +ConcurrentCache<std::string,std::regex>& regexCache;
     782 +bool& pruneImdtRels;
     783 +bool& performIO;
     784 +SignalHandler*& signalHandler;
     785 +std::atomic<std::size_t>& iter;
     786 +std::atomic<RamDomain>& ctr;
     787 +std::string& inputDirectory;
     788 +std::string& outputDirectory;
     789 +t_btree_iii__0_2_1__101__111::Type* rel_AST_NodeField_ca02670731ce3c99;
     790 +};
     791 +} // namespace souffle
     792 +namespace souffle {
     793 +using namespace souffle;
     794 + Stratum_AST_NodeField_cc21295739297165::Stratum_AST_NodeField_cc21295739297165(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_iii__0_2_1__101__111::Type& rel_AST_NodeField_ca02670731ce3c99):
     795 +symTable(symTable),
     796 +recordTable(recordTable),
     797 +regexCache(regexCache),
     798 +pruneImdtRels(pruneImdtRels),
     799 +performIO(performIO),
     800 +signalHandler(signalHandler),
     801 +iter(iter),
     802 +ctr(ctr),
     803 +inputDirectory(inputDirectory),
     804 +outputDirectory(outputDirectory),
     805 +rel_AST_NodeField_ca02670731ce3c99(&rel_AST_NodeField_ca02670731ce3c99){
     806 +}
     807 + 
     808 +void Stratum_AST_NodeField_cc21295739297165::run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret){
     809 +if (performIO) {
     810 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","parent\tchild\tfield"},{"auxArity","0"},{"fact-dir","."},{"name","AST_NodeField"},{"operation","input"},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 3, \"params\": [\"parent\", \"child\", \"field\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 3, \"types\": [\"r:AST_Node\", \"r:AST_Node\", \"s:AST_Field\"]}}"}});
     811 +if (!inputDirectory.empty()) {directiveMap["fact-dir"] = inputDirectory;}
     812 +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_AST_NodeField_ca02670731ce3c99);
     813 +} catch (std::exception& e) {std::cerr << "Error loading AST_NodeField data: " << e.what() << '\n';
     814 +exit(1);
     815 +}
     816 +}
     817 +}
     818 + 
     819 +} // namespace souffle
     820 + 
     821 +namespace souffle {
     822 +using namespace souffle;
     823 +class Stratum_AST_NodeLocation_89d765aa14237a09 {
     824 +public:
     825 + Stratum_AST_NodeLocation_89d765aa14237a09(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_ii__0_1__11__10::Type& rel_AST_NodeLocation_5f3f38ee7a82c12a);
     826 +void run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret);
     827 +private:
     828 +SymbolTable& symTable;
     829 +RecordTable& recordTable;
     830 +ConcurrentCache<std::string,std::regex>& regexCache;
     831 +bool& pruneImdtRels;
     832 +bool& performIO;
     833 +SignalHandler*& signalHandler;
     834 +std::atomic<std::size_t>& iter;
     835 +std::atomic<RamDomain>& ctr;
     836 +std::string& inputDirectory;
     837 +std::string& outputDirectory;
     838 +t_btree_ii__0_1__11__10::Type* rel_AST_NodeLocation_5f3f38ee7a82c12a;
     839 +};
     840 +} // namespace souffle
     841 +namespace souffle {
     842 +using namespace souffle;
     843 + Stratum_AST_NodeLocation_89d765aa14237a09::Stratum_AST_NodeLocation_89d765aa14237a09(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_ii__0_1__11__10::Type& rel_AST_NodeLocation_5f3f38ee7a82c12a):
     844 +symTable(symTable),
     845 +recordTable(recordTable),
     846 +regexCache(regexCache),
     847 +pruneImdtRels(pruneImdtRels),
     848 +performIO(performIO),
     849 +signalHandler(signalHandler),
     850 +iter(iter),
     851 +ctr(ctr),
     852 +inputDirectory(inputDirectory),
     853 +outputDirectory(outputDirectory),
     854 +rel_AST_NodeLocation_5f3f38ee7a82c12a(&rel_AST_NodeLocation_5f3f38ee7a82c12a){
     855 +}
     856 + 
     857 +void Stratum_AST_NodeLocation_89d765aa14237a09::run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret){
     858 +if (performIO) {
     859 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","node\tlocation"},{"auxArity","0"},{"fact-dir","."},{"name","AST_NodeLocation"},{"operation","input"},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 2, \"params\": [\"node\", \"location\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 2, \"types\": [\"r:AST_Node\", \"r:AST_Location\"]}}"}});
     860 +if (!inputDirectory.empty()) {directiveMap["fact-dir"] = inputDirectory;}
     861 +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_AST_NodeLocation_5f3f38ee7a82c12a);
     862 +} catch (std::exception& e) {std::cerr << "Error loading AST_NodeLocation data: " << e.what() << '\n';
     863 +exit(1);
     864 +}
     865 +}
     866 +}
     867 + 
     868 +} // namespace souffle
     869 + 
     870 +namespace souffle {
     871 +using namespace souffle;
     872 +class Stratum_AST_NodeType_400775685fb3e630 {
     873 +public:
     874 + Stratum_AST_NodeType_400775685fb3e630(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_ii__1_0__11__01::Type& rel_AST_NodeType_b38285ae9991409e);
     875 +void run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret);
     876 +private:
     877 +SymbolTable& symTable;
     878 +RecordTable& recordTable;
     879 +ConcurrentCache<std::string,std::regex>& regexCache;
     880 +bool& pruneImdtRels;
     881 +bool& performIO;
     882 +SignalHandler*& signalHandler;
     883 +std::atomic<std::size_t>& iter;
     884 +std::atomic<RamDomain>& ctr;
     885 +std::string& inputDirectory;
     886 +std::string& outputDirectory;
     887 +t_btree_ii__1_0__11__01::Type* rel_AST_NodeType_b38285ae9991409e;
     888 +};
     889 +} // namespace souffle
     890 +namespace souffle {
     891 +using namespace souffle;
     892 + Stratum_AST_NodeType_400775685fb3e630::Stratum_AST_NodeType_400775685fb3e630(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_ii__1_0__11__01::Type& rel_AST_NodeType_b38285ae9991409e):
     893 +symTable(symTable),
     894 +recordTable(recordTable),
     895 +regexCache(regexCache),
     896 +pruneImdtRels(pruneImdtRels),
     897 +performIO(performIO),
     898 +signalHandler(signalHandler),
     899 +iter(iter),
     900 +ctr(ctr),
     901 +inputDirectory(inputDirectory),
     902 +outputDirectory(outputDirectory),
     903 +rel_AST_NodeType_b38285ae9991409e(&rel_AST_NodeType_b38285ae9991409e){
     904 +}
     905 + 
     906 +void Stratum_AST_NodeType_400775685fb3e630::run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret){
     907 +if (performIO) {
     908 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","node\ttype"},{"auxArity","0"},{"fact-dir","."},{"name","AST_NodeType"},{"operation","input"},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 2, \"params\": [\"node\", \"type\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 2, \"types\": [\"r:AST_Node\", \"s:AST_Type\"]}}"}});
     909 +if (!inputDirectory.empty()) {directiveMap["fact-dir"] = inputDirectory;}
     910 +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_AST_NodeType_b38285ae9991409e);
     911 +} catch (std::exception& e) {std::cerr << "Error loading AST_NodeType data: " << e.what() << '\n';
     912 +exit(1);
     913 +}
     914 +}
     915 +}
     916 + 
     917 +} // namespace souffle
     918 + 
     919 +namespace souffle {
     920 +using namespace souffle;
     921 +class Stratum_AST_ParentChild_798cb83c96de8e4d {
     922 +public:
     923 + Stratum_AST_ParentChild_798cb83c96de8e4d(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_iui__0_1_2__110__111::Type& rel_AST_ParentChild_be6259205eb66578);
     924 +void run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret);
     925 +private:
     926 +SymbolTable& symTable;
     927 +RecordTable& recordTable;
     928 +ConcurrentCache<std::string,std::regex>& regexCache;
     929 +bool& pruneImdtRels;
     930 +bool& performIO;
     931 +SignalHandler*& signalHandler;
     932 +std::atomic<std::size_t>& iter;
     933 +std::atomic<RamDomain>& ctr;
     934 +std::string& inputDirectory;
     935 +std::string& outputDirectory;
     936 +t_btree_iui__0_1_2__110__111::Type* rel_AST_ParentChild_be6259205eb66578;
     937 +};
     938 +} // namespace souffle
     939 +namespace souffle {
     940 +using namespace souffle;
     941 + Stratum_AST_ParentChild_798cb83c96de8e4d::Stratum_AST_ParentChild_798cb83c96de8e4d(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_iui__0_1_2__110__111::Type& rel_AST_ParentChild_be6259205eb66578):
     942 +symTable(symTable),
     943 +recordTable(recordTable),
     944 +regexCache(regexCache),
     945 +pruneImdtRels(pruneImdtRels),
     946 +performIO(performIO),
     947 +signalHandler(signalHandler),
     948 +iter(iter),
     949 +ctr(ctr),
     950 +inputDirectory(inputDirectory),
     951 +outputDirectory(outputDirectory),
     952 +rel_AST_ParentChild_be6259205eb66578(&rel_AST_ParentChild_be6259205eb66578){
     953 +}
     954 + 
     955 +void Stratum_AST_ParentChild_798cb83c96de8e4d::run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret){
     956 +if (performIO) {
     957 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","parent\tindex\tchild"},{"auxArity","0"},{"fact-dir","."},{"name","AST_ParentChild"},{"operation","input"},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 3, \"params\": [\"parent\", \"index\", \"child\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 3, \"types\": [\"r:AST_Node\", \"u:unsigned\", \"r:AST_Node\"]}}"}});
     958 +if (!inputDirectory.empty()) {directiveMap["fact-dir"] = inputDirectory;}
     959 +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_AST_ParentChild_be6259205eb66578);
     960 +} catch (std::exception& e) {std::cerr << "Error loading AST_ParentChild data: " << e.what() << '\n';
     961 +exit(1);
     962 +}
     963 +}
     964 +}
     965 + 
     966 +} // namespace souffle
     967 + 
     968 +namespace souffle {
     969 +using namespace souffle;
     970 +class Stratum_Rule_0e6b7aa9ece342e5 {
     971 +public:
     972 + Stratum_Rule_0e6b7aa9ece342e5(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_ii__0_1__11::Type& rel_AST_NodeContent_b2f3666572e60754,t_btree_iii__0_2_1__101__111::Type& rel_AST_NodeField_ca02670731ce3c99,t_btree_ii__1_0__11__01::Type& rel_AST_NodeType_b38285ae9991409e,t_btree_iui__0_1_2__110__111::Type& rel_AST_ParentChild_be6259205eb66578,t_btree_ii__0_1__11::Type& rel_Rule_159a590c7b2c8d95);
     973 +void run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret);
     974 +private:
     975 +SymbolTable& symTable;
     976 +RecordTable& recordTable;
     977 +ConcurrentCache<std::string,std::regex>& regexCache;
     978 +bool& pruneImdtRels;
     979 +bool& performIO;
     980 +SignalHandler*& signalHandler;
     981 +std::atomic<std::size_t>& iter;
     982 +std::atomic<RamDomain>& ctr;
     983 +std::string& inputDirectory;
     984 +std::string& outputDirectory;
     985 +t_btree_ii__0_1__11::Type* rel_AST_NodeContent_b2f3666572e60754;
     986 +t_btree_iii__0_2_1__101__111::Type* rel_AST_NodeField_ca02670731ce3c99;
     987 +t_btree_ii__1_0__11__01::Type* rel_AST_NodeType_b38285ae9991409e;
     988 +t_btree_iui__0_1_2__110__111::Type* rel_AST_ParentChild_be6259205eb66578;
     989 +t_btree_ii__0_1__11::Type* rel_Rule_159a590c7b2c8d95;
     990 +};
     991 +} // namespace souffle
     992 +namespace souffle {
     993 +using namespace souffle;
     994 + Stratum_Rule_0e6b7aa9ece342e5::Stratum_Rule_0e6b7aa9ece342e5(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_ii__0_1__11::Type& rel_AST_NodeContent_b2f3666572e60754,t_btree_iii__0_2_1__101__111::Type& rel_AST_NodeField_ca02670731ce3c99,t_btree_ii__1_0__11__01::Type& rel_AST_NodeType_b38285ae9991409e,t_btree_iui__0_1_2__110__111::Type& rel_AST_ParentChild_be6259205eb66578,t_btree_ii__0_1__11::Type& rel_Rule_159a590c7b2c8d95):
     995 +symTable(symTable),
     996 +recordTable(recordTable),
     997 +regexCache(regexCache),
     998 +pruneImdtRels(pruneImdtRels),
     999 +performIO(performIO),
     1000 +signalHandler(signalHandler),
     1001 +iter(iter),
     1002 +ctr(ctr),
     1003 +inputDirectory(inputDirectory),
     1004 +outputDirectory(outputDirectory),
     1005 +rel_AST_NodeContent_b2f3666572e60754(&rel_AST_NodeContent_b2f3666572e60754),
     1006 +rel_AST_NodeField_ca02670731ce3c99(&rel_AST_NodeField_ca02670731ce3c99),
     1007 +rel_AST_NodeType_b38285ae9991409e(&rel_AST_NodeType_b38285ae9991409e),
     1008 +rel_AST_ParentChild_be6259205eb66578(&rel_AST_ParentChild_be6259205eb66578),
     1009 +rel_Rule_159a590c7b2c8d95(&rel_Rule_159a590c7b2c8d95){
     1010 +}
     1011 + 
     1012 +void Stratum_Rule_0e6b7aa9ece342e5::run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret){
     1013 +signalHandler->setMsg(R"_(Rule("test_rule",node1) :-
     1014 + AST_NodeType(node1,"call"),
     1015 + !AST_NodeField(node1,_,"block"),
     1016 + AST_NodeField(node1,node2,"receiver"),
     1017 + AST_NodeType(node2,"constant"),
     1018 + AST_NodeContent(node2,"Foo"),
     1019 + AST_NodeField(node1,node3,"method"),
     1020 + AST_NodeType(node3,"identifier"),
     1021 + AST_NodeContent(node3,"new"),
     1022 + AST_NodeField(node1,node4,"arguments"),
     1023 + AST_NodeType(node4,"argument_list"),
     1024 + AST_ParentChild(node4,0,node5),
     1025 + AST_NodeType(node5,"pair"),
     1026 + AST_NodeField(node5,tmp0,"key"),
     1027 + AST_NodeType(tmp0,"simple_symbol"),
     1028 + AST_NodeContent(tmp0,":b"),
     1029 + AST_NodeField(node5,node6,"value"),
     1030 + AST_NodeType(node6,"integer"),
     1031 + AST_NodeContent(node6,"1").
     1032 +in file rules.dl [1:1-1:714])_");
     1033 +if(!(rel_AST_NodeType_b38285ae9991409e->empty()) && !(rel_AST_NodeField_ca02670731ce3c99->empty()) && !(rel_AST_NodeContent_b2f3666572e60754->empty()) && !(rel_AST_ParentChild_be6259205eb66578->empty())) {
     1034 +[&](){
     1035 +CREATE_OP_CONTEXT(rel_AST_NodeContent_b2f3666572e60754_op_ctxt,rel_AST_NodeContent_b2f3666572e60754->createContext());
     1036 +CREATE_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt,rel_AST_NodeField_ca02670731ce3c99->createContext());
     1037 +CREATE_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt,rel_AST_NodeType_b38285ae9991409e->createContext());
     1038 +CREATE_OP_CONTEXT(rel_AST_ParentChild_be6259205eb66578_op_ctxt,rel_AST_ParentChild_be6259205eb66578->createContext());
     1039 +CREATE_OP_CONTEXT(rel_Rule_159a590c7b2c8d95_op_ctxt,rel_Rule_159a590c7b2c8d95->createContext());
     1040 +auto range = rel_AST_NodeType_b38285ae9991409e->lowerUpperRange_01(Tuple<RamDomain,2>{{ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(0))}},Tuple<RamDomain,2>{{ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(0))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt));
     1041 +for(const auto& env0 : range) {
     1042 +if( !(!rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(1))}},Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(1))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt)).empty())) {
     1043 +auto range = rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(2))}},Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(2))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt));
     1044 +for(const auto& env1 : range) {
     1045 +if( rel_AST_NodeContent_b2f3666572e60754->contains(Tuple<RamDomain,2>{{ramBitCast(env1[1]),ramBitCast(RamSigned(3))}},READ_OP_CONTEXT(rel_AST_NodeContent_b2f3666572e60754_op_ctxt)) && rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env1[1]),ramBitCast(RamSigned(4))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1046 +auto range = rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(5))}},Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(5))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt));
     1047 +for(const auto& env2 : range) {
     1048 +if( rel_AST_NodeContent_b2f3666572e60754->contains(Tuple<RamDomain,2>{{ramBitCast(env2[1]),ramBitCast(RamSigned(6))}},READ_OP_CONTEXT(rel_AST_NodeContent_b2f3666572e60754_op_ctxt)) && rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env2[1]),ramBitCast(RamSigned(7))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1049 +auto range = rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(8))}},Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(8))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt));
     1050 +for(const auto& env3 : range) {
     1051 +if( rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env3[1]),ramBitCast(RamSigned(9))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1052 +auto range = rel_AST_ParentChild_be6259205eb66578->lowerUpperRange_110(Tuple<RamDomain,3>{{ramBitCast(env3[1]), ramBitCast(RamUnsigned(0)), ramBitCast<RamDomain>(MIN_RAM_SIGNED)}},Tuple<RamDomain,3>{{ramBitCast(env3[1]), ramBitCast(RamUnsigned(0)), ramBitCast<RamDomain>(MAX_RAM_SIGNED)}},READ_OP_CONTEXT(rel_AST_ParentChild_be6259205eb66578_op_ctxt));
     1053 +for(const auto& env4 : range) {
     1054 +if( rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env4[2]),ramBitCast(RamSigned(10))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1055 +auto range = rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env4[2]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(11))}},Tuple<RamDomain,3>{{ramBitCast(env4[2]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(11))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt));
     1056 +for(const auto& env5 : range) {
     1057 +if( rel_AST_NodeContent_b2f3666572e60754->contains(Tuple<RamDomain,2>{{ramBitCast(env5[1]),ramBitCast(RamSigned(12))}},READ_OP_CONTEXT(rel_AST_NodeContent_b2f3666572e60754_op_ctxt)) && rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env5[1]),ramBitCast(RamSigned(13))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1058 +auto range = rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env4[2]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(14))}},Tuple<RamDomain,3>{{ramBitCast(env4[2]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(14))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt));
     1059 +for(const auto& env6 : range) {
     1060 +if( rel_AST_NodeContent_b2f3666572e60754->contains(Tuple<RamDomain,2>{{ramBitCast(env6[1]),ramBitCast(RamSigned(15))}},READ_OP_CONTEXT(rel_AST_NodeContent_b2f3666572e60754_op_ctxt)) && rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env6[1]),ramBitCast(RamSigned(16))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1061 +Tuple<RamDomain,2> tuple{{ramBitCast(RamSigned(17)),ramBitCast(env0[0])}};
     1062 +rel_Rule_159a590c7b2c8d95->insert(tuple,READ_OP_CONTEXT(rel_Rule_159a590c7b2c8d95_op_ctxt));
     1063 +}
     1064 +}
     1065 +}
     1066 +}
     1067 +}
     1068 +}
     1069 +}
     1070 +}
     1071 +}
     1072 +}
     1073 +}
     1074 +}
     1075 +}
     1076 +}
     1077 +}
     1078 +();}
     1079 +signalHandler->setMsg(R"_(Rule("test_rule",node1) :-
     1080 + AST_NodeType(node1,"call"),
     1081 + !AST_NodeField(node1,_,"block"),
     1082 + AST_NodeField(node1,node2,"receiver"),
     1083 + AST_NodeType(node2,"constant"),
     1084 + AST_NodeContent(node2,"Foo"),
     1085 + AST_NodeField(node1,node3,"method"),
     1086 + AST_NodeType(node3,"identifier"),
     1087 + AST_NodeContent(node3,"new"),
     1088 + AST_NodeField(node1,node4,"arguments"),
     1089 + AST_NodeType(node4,"argument_list"),
     1090 + AST_ParentChild(node4,0,node5),
     1091 + AST_NodeType(node5,"pair"),
     1092 + AST_NodeField(node5,tmp0,"key"),
     1093 + AST_NodeType(tmp0,"hash_key_symbol"),
     1094 + AST_NodeContent(tmp0,"b"),
     1095 + AST_NodeField(node5,node6,"value"),
     1096 + AST_NodeType(node6,"integer"),
     1097 + AST_NodeContent(node6,"1").
     1098 +in file rules.dl [1:1-1:714])_");
     1099 +if(!(rel_AST_NodeType_b38285ae9991409e->empty()) && !(rel_AST_NodeField_ca02670731ce3c99->empty()) && !(rel_AST_NodeContent_b2f3666572e60754->empty()) && !(rel_AST_ParentChild_be6259205eb66578->empty())) {
     1100 +[&](){
     1101 +CREATE_OP_CONTEXT(rel_AST_NodeContent_b2f3666572e60754_op_ctxt,rel_AST_NodeContent_b2f3666572e60754->createContext());
     1102 +CREATE_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt,rel_AST_NodeField_ca02670731ce3c99->createContext());
     1103 +CREATE_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt,rel_AST_NodeType_b38285ae9991409e->createContext());
     1104 +CREATE_OP_CONTEXT(rel_AST_ParentChild_be6259205eb66578_op_ctxt,rel_AST_ParentChild_be6259205eb66578->createContext());
     1105 +CREATE_OP_CONTEXT(rel_Rule_159a590c7b2c8d95_op_ctxt,rel_Rule_159a590c7b2c8d95->createContext());
     1106 +auto range = rel_AST_NodeType_b38285ae9991409e->lowerUpperRange_01(Tuple<RamDomain,2>{{ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(0))}},Tuple<RamDomain,2>{{ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(0))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt));
     1107 +for(const auto& env0 : range) {
     1108 +if( !(!rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(1))}},Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(1))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt)).empty())) {
     1109 +auto range = rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(2))}},Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(2))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt));
     1110 +for(const auto& env1 : range) {
     1111 +if( rel_AST_NodeContent_b2f3666572e60754->contains(Tuple<RamDomain,2>{{ramBitCast(env1[1]),ramBitCast(RamSigned(3))}},READ_OP_CONTEXT(rel_AST_NodeContent_b2f3666572e60754_op_ctxt)) && rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env1[1]),ramBitCast(RamSigned(4))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1112 +auto range = rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(5))}},Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(5))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt));
     1113 +for(const auto& env2 : range) {
     1114 +if( rel_AST_NodeContent_b2f3666572e60754->contains(Tuple<RamDomain,2>{{ramBitCast(env2[1]),ramBitCast(RamSigned(6))}},READ_OP_CONTEXT(rel_AST_NodeContent_b2f3666572e60754_op_ctxt)) && rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env2[1]),ramBitCast(RamSigned(7))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1115 +auto range = rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(8))}},Tuple<RamDomain,3>{{ramBitCast(env0[0]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(8))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt));
     1116 +for(const auto& env3 : range) {
     1117 +if( rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env3[1]),ramBitCast(RamSigned(9))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1118 +auto range = rel_AST_ParentChild_be6259205eb66578->lowerUpperRange_110(Tuple<RamDomain,3>{{ramBitCast(env3[1]), ramBitCast(RamUnsigned(0)), ramBitCast<RamDomain>(MIN_RAM_SIGNED)}},Tuple<RamDomain,3>{{ramBitCast(env3[1]), ramBitCast(RamUnsigned(0)), ramBitCast<RamDomain>(MAX_RAM_SIGNED)}},READ_OP_CONTEXT(rel_AST_ParentChild_be6259205eb66578_op_ctxt));
     1119 +for(const auto& env4 : range) {
     1120 +if( rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env4[2]),ramBitCast(RamSigned(10))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1121 +auto range = rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env4[2]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(11))}},Tuple<RamDomain,3>{{ramBitCast(env4[2]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(11))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt));
     1122 +for(const auto& env5 : range) {
     1123 +if( rel_AST_NodeContent_b2f3666572e60754->contains(Tuple<RamDomain,2>{{ramBitCast(env5[1]),ramBitCast(RamSigned(18))}},READ_OP_CONTEXT(rel_AST_NodeContent_b2f3666572e60754_op_ctxt)) && rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env5[1]),ramBitCast(RamSigned(19))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1124 +auto range = rel_AST_NodeField_ca02670731ce3c99->lowerUpperRange_101(Tuple<RamDomain,3>{{ramBitCast(env4[2]), ramBitCast<RamDomain>(MIN_RAM_SIGNED), ramBitCast(RamSigned(14))}},Tuple<RamDomain,3>{{ramBitCast(env4[2]), ramBitCast<RamDomain>(MAX_RAM_SIGNED), ramBitCast(RamSigned(14))}},READ_OP_CONTEXT(rel_AST_NodeField_ca02670731ce3c99_op_ctxt));
     1125 +for(const auto& env6 : range) {
     1126 +if( rel_AST_NodeContent_b2f3666572e60754->contains(Tuple<RamDomain,2>{{ramBitCast(env6[1]),ramBitCast(RamSigned(15))}},READ_OP_CONTEXT(rel_AST_NodeContent_b2f3666572e60754_op_ctxt)) && rel_AST_NodeType_b38285ae9991409e->contains(Tuple<RamDomain,2>{{ramBitCast(env6[1]),ramBitCast(RamSigned(16))}},READ_OP_CONTEXT(rel_AST_NodeType_b38285ae9991409e_op_ctxt))) {
     1127 +Tuple<RamDomain,2> tuple{{ramBitCast(RamSigned(17)),ramBitCast(env0[0])}};
     1128 +rel_Rule_159a590c7b2c8d95->insert(tuple,READ_OP_CONTEXT(rel_Rule_159a590c7b2c8d95_op_ctxt));
     1129 +}
     1130 +}
     1131 +}
     1132 +}
     1133 +}
     1134 +}
     1135 +}
     1136 +}
     1137 +}
     1138 +}
     1139 +}
     1140 +}
     1141 +}
     1142 +}
     1143 +}
     1144 +();}
     1145 +if (pruneImdtRels) rel_AST_NodeContent_b2f3666572e60754->purge();
     1146 +if (pruneImdtRels) rel_AST_NodeField_ca02670731ce3c99->purge();
     1147 +if (pruneImdtRels) rel_AST_NodeType_b38285ae9991409e->purge();
     1148 +if (pruneImdtRels) rel_AST_ParentChild_be6259205eb66578->purge();
     1149 +}
     1150 + 
     1151 +} // namespace souffle
     1152 + 
     1153 +namespace souffle {
     1154 +using namespace souffle;
     1155 +class Stratum_RuleMatch_4394a245605301ce {
     1156 +public:
     1157 + Stratum_RuleMatch_4394a245605301ce(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_ii__0_1__11__10::Type& rel_AST_NodeLocation_5f3f38ee7a82c12a,t_btree_ii__0_1__11::Type& rel_Rule_159a590c7b2c8d95,t_btree_ii__0_1__11::Type& rel_RuleMatch_8974a5cadf2d4779);
     1158 +void run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret);
     1159 +private:
     1160 +SymbolTable& symTable;
     1161 +RecordTable& recordTable;
     1162 +ConcurrentCache<std::string,std::regex>& regexCache;
     1163 +bool& pruneImdtRels;
     1164 +bool& performIO;
     1165 +SignalHandler*& signalHandler;
     1166 +std::atomic<std::size_t>& iter;
     1167 +std::atomic<RamDomain>& ctr;
     1168 +std::string& inputDirectory;
     1169 +std::string& outputDirectory;
     1170 +t_btree_ii__0_1__11__10::Type* rel_AST_NodeLocation_5f3f38ee7a82c12a;
     1171 +t_btree_ii__0_1__11::Type* rel_Rule_159a590c7b2c8d95;
     1172 +t_btree_ii__0_1__11::Type* rel_RuleMatch_8974a5cadf2d4779;
     1173 +};
     1174 +} // namespace souffle
     1175 +namespace souffle {
     1176 +using namespace souffle;
     1177 + Stratum_RuleMatch_4394a245605301ce::Stratum_RuleMatch_4394a245605301ce(SymbolTable& symTable,RecordTable& recordTable,ConcurrentCache<std::string,std::regex>& regexCache,bool& pruneImdtRels,bool& performIO,SignalHandler*& signalHandler,std::atomic<std::size_t>& iter,std::atomic<RamDomain>& ctr,std::string& inputDirectory,std::string& outputDirectory,t_btree_ii__0_1__11__10::Type& rel_AST_NodeLocation_5f3f38ee7a82c12a,t_btree_ii__0_1__11::Type& rel_Rule_159a590c7b2c8d95,t_btree_ii__0_1__11::Type& rel_RuleMatch_8974a5cadf2d4779):
     1178 +symTable(symTable),
     1179 +recordTable(recordTable),
     1180 +regexCache(regexCache),
     1181 +pruneImdtRels(pruneImdtRels),
     1182 +performIO(performIO),
     1183 +signalHandler(signalHandler),
     1184 +iter(iter),
     1185 +ctr(ctr),
     1186 +inputDirectory(inputDirectory),
     1187 +outputDirectory(outputDirectory),
     1188 +rel_AST_NodeLocation_5f3f38ee7a82c12a(&rel_AST_NodeLocation_5f3f38ee7a82c12a),
     1189 +rel_Rule_159a590c7b2c8d95(&rel_Rule_159a590c7b2c8d95),
     1190 +rel_RuleMatch_8974a5cadf2d4779(&rel_RuleMatch_8974a5cadf2d4779){
     1191 +}
     1192 + 
     1193 +void Stratum_RuleMatch_4394a245605301ce::run([[maybe_unused]] const std::vector<RamDomain>& args,[[maybe_unused]] std::vector<RamDomain>& ret){
     1194 +signalHandler->setMsg(R"_(RuleMatch(name,location) :-
     1195 + Rule(name,node),
     1196 + AST_NodeLocation(node,location).
     1197 +in file ruby.dl [8:1-8:81])_");
     1198 +if(!(rel_Rule_159a590c7b2c8d95->empty()) && !(rel_AST_NodeLocation_5f3f38ee7a82c12a->empty())) {
     1199 +[&](){
     1200 +CREATE_OP_CONTEXT(rel_AST_NodeLocation_5f3f38ee7a82c12a_op_ctxt,rel_AST_NodeLocation_5f3f38ee7a82c12a->createContext());
     1201 +CREATE_OP_CONTEXT(rel_Rule_159a590c7b2c8d95_op_ctxt,rel_Rule_159a590c7b2c8d95->createContext());
     1202 +CREATE_OP_CONTEXT(rel_RuleMatch_8974a5cadf2d4779_op_ctxt,rel_RuleMatch_8974a5cadf2d4779->createContext());
     1203 +for(const auto& env0 : *rel_Rule_159a590c7b2c8d95) {
     1204 +auto range = rel_AST_NodeLocation_5f3f38ee7a82c12a->lowerUpperRange_10(Tuple<RamDomain,2>{{ramBitCast(env0[1]), ramBitCast<RamDomain>(MIN_RAM_SIGNED)}},Tuple<RamDomain,2>{{ramBitCast(env0[1]), ramBitCast<RamDomain>(MAX_RAM_SIGNED)}},READ_OP_CONTEXT(rel_AST_NodeLocation_5f3f38ee7a82c12a_op_ctxt));
     1205 +for(const auto& env1 : range) {
     1206 +Tuple<RamDomain,2> tuple{{ramBitCast(env0[0]),ramBitCast(env1[1])}};
     1207 +rel_RuleMatch_8974a5cadf2d4779->insert(tuple,READ_OP_CONTEXT(rel_RuleMatch_8974a5cadf2d4779_op_ctxt));
     1208 +}
     1209 +}
     1210 +}
     1211 +();}
     1212 +if (performIO) {
     1213 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","name\tlocation"},{"auxArity","0"},{"name","RuleMatch"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 2, \"params\": [\"name\", \"location\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 2, \"types\": [\"s:RuleName\", \"r:AST_Location\"]}}"}});
     1214 +if (outputDirectory == "-"){directiveMap["IO"] = "stdout"; directiveMap["headers"] = "true";}
     1215 +else if (!outputDirectory.empty()) {directiveMap["output-dir"] = outputDirectory;}
     1216 +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_RuleMatch_8974a5cadf2d4779);
     1217 +} catch (std::exception& e) {std::cerr << e.what();exit(1);}
     1218 +}
     1219 +if (pruneImdtRels) rel_AST_NodeLocation_5f3f38ee7a82c12a->purge();
     1220 +if (pruneImdtRels) rel_Rule_159a590c7b2c8d95->purge();
     1221 +}
     1222 + 
     1223 +} // namespace souffle
     1224 + 
     1225 +namespace souffle {
     1226 +using namespace souffle;
     1227 +class Sf_souffle: public SouffleProgram {
     1228 +public:
     1229 + Sf_souffle();
     1230 + ~Sf_souffle();
     1231 +void run();
     1232 +void runAll(std::string inputDirectoryArg = "",std::string outputDirectoryArg = "",bool performIOArg = true,bool pruneImdtRelsArg = true);
     1233 +void printAll([[maybe_unused]] std::string outputDirectoryArg = "");
     1234 +void loadAll([[maybe_unused]] std::string inputDirectoryArg = "");
     1235 +void dumpInputs();
     1236 +void dumpOutputs();
     1237 +SymbolTable& getSymbolTable();
     1238 +RecordTable& getRecordTable();
     1239 +void setNumThreads(std::size_t numThreadsValue);
     1240 +void executeSubroutine(std::string name,const std::vector<RamDomain>& args,std::vector<RamDomain>& ret);
     1241 +private:
     1242 +void runFunction(std::string inputDirectoryArg,std::string outputDirectoryArg,bool performIOArg,bool pruneImdtRelsArg);
     1243 +SymbolTableImpl symTable;
     1244 +SpecializedRecordTable<0> recordTable;
     1245 +ConcurrentCache<std::string,std::regex> regexCache;
     1246 +Own<t_btree_ii__0_1__11::Type> rel_AST_NodeContent_b2f3666572e60754;
     1247 +souffle::RelationWrapper<t_btree_ii__0_1__11::Type> wrapper_rel_AST_NodeContent_b2f3666572e60754;
     1248 +Own<t_btree_iii__0_2_1__101__111::Type> rel_AST_NodeField_ca02670731ce3c99;
     1249 +souffle::RelationWrapper<t_btree_iii__0_2_1__101__111::Type> wrapper_rel_AST_NodeField_ca02670731ce3c99;
     1250 +Own<t_btree_ii__0_1__11__10::Type> rel_AST_NodeLocation_5f3f38ee7a82c12a;
     1251 +souffle::RelationWrapper<t_btree_ii__0_1__11__10::Type> wrapper_rel_AST_NodeLocation_5f3f38ee7a82c12a;
     1252 +Own<t_btree_ii__1_0__11__01::Type> rel_AST_NodeType_b38285ae9991409e;
     1253 +souffle::RelationWrapper<t_btree_ii__1_0__11__01::Type> wrapper_rel_AST_NodeType_b38285ae9991409e;
     1254 +Own<t_btree_iui__0_1_2__110__111::Type> rel_AST_ParentChild_be6259205eb66578;
     1255 +souffle::RelationWrapper<t_btree_iui__0_1_2__110__111::Type> wrapper_rel_AST_ParentChild_be6259205eb66578;
     1256 +Own<t_btree_ii__0_1__11::Type> rel_Rule_159a590c7b2c8d95;
     1257 +souffle::RelationWrapper<t_btree_ii__0_1__11::Type> wrapper_rel_Rule_159a590c7b2c8d95;
     1258 +Own<t_btree_ii__0_1__11::Type> rel_RuleMatch_8974a5cadf2d4779;
     1259 +souffle::RelationWrapper<t_btree_ii__0_1__11::Type> wrapper_rel_RuleMatch_8974a5cadf2d4779;
     1260 +Stratum_AST_NodeContent_fd51b4bf60caba3f stratum_AST_NodeContent_f29a0e907561c50c;
     1261 +Stratum_AST_NodeField_cc21295739297165 stratum_AST_NodeField_b63714d335ba8b2e;
     1262 +Stratum_AST_NodeLocation_89d765aa14237a09 stratum_AST_NodeLocation_b120359576603175;
     1263 +Stratum_AST_NodeType_400775685fb3e630 stratum_AST_NodeType_f0647903c04c5ec5;
     1264 +Stratum_AST_ParentChild_798cb83c96de8e4d stratum_AST_ParentChild_381ffe0668807a9c;
     1265 +Stratum_Rule_0e6b7aa9ece342e5 stratum_Rule_b7f309df7d140ebc;
     1266 +Stratum_RuleMatch_4394a245605301ce stratum_RuleMatch_a3becf205b4cd965;
     1267 +std::string inputDirectory;
     1268 +std::string outputDirectory;
     1269 +SignalHandler* signalHandler{SignalHandler::instance()};
     1270 +std::atomic<RamDomain> ctr{};
     1271 +std::atomic<std::size_t> iter{};
     1272 +};
     1273 +} // namespace souffle
     1274 +namespace souffle {
     1275 +using namespace souffle;
     1276 + Sf_souffle::Sf_souffle():
     1277 +symTable({
     1278 + R"_(call)_",
     1279 + R"_(block)_",
     1280 + R"_(receiver)_",
     1281 + R"_(Foo)_",
     1282 + R"_(constant)_",
     1283 + R"_(method)_",
     1284 + R"_(new)_",
     1285 + R"_(identifier)_",
     1286 + R"_(arguments)_",
     1287 + R"_(argument_list)_",
     1288 + R"_(pair)_",
     1289 + R"_(key)_",
     1290 + R"_(:b)_",
     1291 + R"_(simple_symbol)_",
     1292 + R"_(value)_",
     1293 + R"_(1)_",
     1294 + R"_(integer)_",
     1295 + R"_(test_rule)_",
     1296 + R"_(b)_",
     1297 + R"_(hash_key_symbol)_",
     1298 +}),
     1299 +recordTable(),
     1300 +regexCache(),
     1301 +rel_AST_NodeContent_b2f3666572e60754(mk<t_btree_ii__0_1__11::Type>()),
     1302 +wrapper_rel_AST_NodeContent_b2f3666572e60754(0, *rel_AST_NodeContent_b2f3666572e60754, *this, "AST_NodeContent", std::array<const char *,2>{{"r:AST_Node","s:AST_Content"}}, std::array<const char *,2>{{"node","content"}}, 0),
     1303 +rel_AST_NodeField_ca02670731ce3c99(mk<t_btree_iii__0_2_1__101__111::Type>()),
     1304 +wrapper_rel_AST_NodeField_ca02670731ce3c99(1, *rel_AST_NodeField_ca02670731ce3c99, *this, "AST_NodeField", std::array<const char *,3>{{"r:AST_Node","r:AST_Node","s:AST_Field"}}, std::array<const char *,3>{{"parent","child","field"}}, 0),
     1305 +rel_AST_NodeLocation_5f3f38ee7a82c12a(mk<t_btree_ii__0_1__11__10::Type>()),
     1306 +wrapper_rel_AST_NodeLocation_5f3f38ee7a82c12a(2, *rel_AST_NodeLocation_5f3f38ee7a82c12a, *this, "AST_NodeLocation", std::array<const char *,2>{{"r:AST_Node","r:AST_Location"}}, std::array<const char *,2>{{"node","location"}}, 0),
     1307 +rel_AST_NodeType_b38285ae9991409e(mk<t_btree_ii__1_0__11__01::Type>()),
     1308 +wrapper_rel_AST_NodeType_b38285ae9991409e(3, *rel_AST_NodeType_b38285ae9991409e, *this, "AST_NodeType", std::array<const char *,2>{{"r:AST_Node","s:AST_Type"}}, std::array<const char *,2>{{"node","type"}}, 0),
     1309 +rel_AST_ParentChild_be6259205eb66578(mk<t_btree_iui__0_1_2__110__111::Type>()),
     1310 +wrapper_rel_AST_ParentChild_be6259205eb66578(4, *rel_AST_ParentChild_be6259205eb66578, *this, "AST_ParentChild", std::array<const char *,3>{{"r:AST_Node","u:unsigned","r:AST_Node"}}, std::array<const char *,3>{{"parent","index","child"}}, 0),
     1311 +rel_Rule_159a590c7b2c8d95(mk<t_btree_ii__0_1__11::Type>()),
     1312 +wrapper_rel_Rule_159a590c7b2c8d95(5, *rel_Rule_159a590c7b2c8d95, *this, "Rule", std::array<const char *,2>{{"s:RuleName","r:AST_Node"}}, std::array<const char *,2>{{"rule","node"}}, 0),
     1313 +rel_RuleMatch_8974a5cadf2d4779(mk<t_btree_ii__0_1__11::Type>()),
     1314 +wrapper_rel_RuleMatch_8974a5cadf2d4779(6, *rel_RuleMatch_8974a5cadf2d4779, *this, "RuleMatch", std::array<const char *,2>{{"s:RuleName","r:AST_Location"}}, std::array<const char *,2>{{"name","location"}}, 0),
     1315 +stratum_AST_NodeContent_f29a0e907561c50c(symTable,recordTable,regexCache,pruneImdtRels,performIO,signalHandler,iter,ctr,inputDirectory,outputDirectory,*rel_AST_NodeContent_b2f3666572e60754),
     1316 +stratum_AST_NodeField_b63714d335ba8b2e(symTable,recordTable,regexCache,pruneImdtRels,performIO,signalHandler,iter,ctr,inputDirectory,outputDirectory,*rel_AST_NodeField_ca02670731ce3c99),
     1317 +stratum_AST_NodeLocation_b120359576603175(symTable,recordTable,regexCache,pruneImdtRels,performIO,signalHandler,iter,ctr,inputDirectory,outputDirectory,*rel_AST_NodeLocation_5f3f38ee7a82c12a),
     1318 +stratum_AST_NodeType_f0647903c04c5ec5(symTable,recordTable,regexCache,pruneImdtRels,performIO,signalHandler,iter,ctr,inputDirectory,outputDirectory,*rel_AST_NodeType_b38285ae9991409e),
     1319 +stratum_AST_ParentChild_381ffe0668807a9c(symTable,recordTable,regexCache,pruneImdtRels,performIO,signalHandler,iter,ctr,inputDirectory,outputDirectory,*rel_AST_ParentChild_be6259205eb66578),
     1320 +stratum_Rule_b7f309df7d140ebc(symTable,recordTable,regexCache,pruneImdtRels,performIO,signalHandler,iter,ctr,inputDirectory,outputDirectory,*rel_AST_NodeContent_b2f3666572e60754,*rel_AST_NodeField_ca02670731ce3c99,*rel_AST_NodeType_b38285ae9991409e,*rel_AST_ParentChild_be6259205eb66578,*rel_Rule_159a590c7b2c8d95),
     1321 +stratum_RuleMatch_a3becf205b4cd965(symTable,recordTable,regexCache,pruneImdtRels,performIO,signalHandler,iter,ctr,inputDirectory,outputDirectory,*rel_AST_NodeLocation_5f3f38ee7a82c12a,*rel_Rule_159a590c7b2c8d95,*rel_RuleMatch_8974a5cadf2d4779){
     1322 +addRelation("AST_NodeContent", wrapper_rel_AST_NodeContent_b2f3666572e60754, true, false);
     1323 +addRelation("AST_NodeField", wrapper_rel_AST_NodeField_ca02670731ce3c99, true, false);
     1324 +addRelation("AST_NodeLocation", wrapper_rel_AST_NodeLocation_5f3f38ee7a82c12a, true, false);
     1325 +addRelation("AST_NodeType", wrapper_rel_AST_NodeType_b38285ae9991409e, true, false);
     1326 +addRelation("AST_ParentChild", wrapper_rel_AST_ParentChild_be6259205eb66578, true, false);
     1327 +addRelation("Rule", wrapper_rel_Rule_159a590c7b2c8d95, false, false);
     1328 +addRelation("RuleMatch", wrapper_rel_RuleMatch_8974a5cadf2d4779, false, true);
     1329 +}
     1330 + 
     1331 + Sf_souffle::~Sf_souffle(){
     1332 +}
     1333 + 
     1334 +void Sf_souffle::runFunction(std::string inputDirectoryArg,std::string outputDirectoryArg,bool performIOArg,bool pruneImdtRelsArg){
     1335 + 
     1336 + this->inputDirectory = std::move(inputDirectoryArg);
     1337 + this->outputDirectory = std::move(outputDirectoryArg);
     1338 + this->performIO = performIOArg;
     1339 + this->pruneImdtRels = pruneImdtRelsArg;
     1340 + 
     1341 + // set default threads (in embedded mode)
     1342 + // if this is not set, and omp is used, the default omp setting of number of cores is used.
     1343 +#if defined(_OPENMP)
     1344 + if (0 < getNumThreads()) { omp_set_num_threads(static_cast<int>(getNumThreads())); }
     1345 +#endif
     1346 + 
     1347 + signalHandler->set();
     1348 +// -- query evaluation --
     1349 +{
     1350 + std::vector<RamDomain> args, ret;
     1351 +stratum_AST_NodeContent_f29a0e907561c50c.run(args, ret);
     1352 +}
     1353 +{
     1354 + std::vector<RamDomain> args, ret;
     1355 +stratum_AST_NodeField_b63714d335ba8b2e.run(args, ret);
     1356 +}
     1357 +{
     1358 + std::vector<RamDomain> args, ret;
     1359 +stratum_AST_NodeLocation_b120359576603175.run(args, ret);
     1360 +}
     1361 +{
     1362 + std::vector<RamDomain> args, ret;
     1363 +stratum_AST_NodeType_f0647903c04c5ec5.run(args, ret);
     1364 +}
     1365 +{
     1366 + std::vector<RamDomain> args, ret;
     1367 +stratum_AST_ParentChild_381ffe0668807a9c.run(args, ret);
     1368 +}
     1369 +{
     1370 + std::vector<RamDomain> args, ret;
     1371 +stratum_Rule_b7f309df7d140ebc.run(args, ret);
     1372 +}
     1373 +{
     1374 + std::vector<RamDomain> args, ret;
     1375 +stratum_RuleMatch_a3becf205b4cd965.run(args, ret);
     1376 +}
     1377 + 
     1378 +// -- relation hint statistics --
     1379 +signalHandler->reset();
     1380 +}
     1381 + 
     1382 +void Sf_souffle::run(){
     1383 +runFunction("", "", false, false);
     1384 +}
     1385 + 
     1386 +void Sf_souffle::runAll(std::string inputDirectoryArg,std::string outputDirectoryArg,bool performIOArg,bool pruneImdtRelsArg){
     1387 +runFunction(inputDirectoryArg, outputDirectoryArg, performIOArg, pruneImdtRelsArg);
     1388 +}
     1389 + 
     1390 +void Sf_souffle::printAll([[maybe_unused]] std::string outputDirectoryArg){
     1391 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","name\tlocation"},{"auxArity","0"},{"name","RuleMatch"},{"operation","output"},{"output-dir","."},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 2, \"params\": [\"name\", \"location\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 2, \"types\": [\"s:RuleName\", \"r:AST_Location\"]}}"}});
     1392 +if (!outputDirectoryArg.empty()) {directiveMap["output-dir"] = outputDirectoryArg;}
     1393 +IOSystem::getInstance().getWriter(directiveMap, symTable, recordTable)->writeAll(*rel_RuleMatch_8974a5cadf2d4779);
     1394 +} catch (std::exception& e) {std::cerr << e.what();exit(1);}
     1395 +}
     1396 + 
     1397 +void Sf_souffle::loadAll([[maybe_unused]] std::string inputDirectoryArg){
     1398 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","node\tcontent"},{"auxArity","0"},{"fact-dir","."},{"name","AST_NodeContent"},{"operation","input"},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 2, \"params\": [\"node\", \"content\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 2, \"types\": [\"r:AST_Node\", \"s:AST_Content\"]}}"}});
     1399 +if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;}
     1400 +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_AST_NodeContent_b2f3666572e60754);
     1401 +} catch (std::exception& e) {std::cerr << "Error loading AST_NodeContent data: " << e.what() << '\n';
     1402 +exit(1);
     1403 +}
     1404 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","parent\tindex\tchild"},{"auxArity","0"},{"fact-dir","."},{"name","AST_ParentChild"},{"operation","input"},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 3, \"params\": [\"parent\", \"index\", \"child\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 3, \"types\": [\"r:AST_Node\", \"u:unsigned\", \"r:AST_Node\"]}}"}});
     1405 +if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;}
     1406 +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_AST_ParentChild_be6259205eb66578);
     1407 +} catch (std::exception& e) {std::cerr << "Error loading AST_ParentChild data: " << e.what() << '\n';
     1408 +exit(1);
     1409 +}
     1410 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","node\ttype"},{"auxArity","0"},{"fact-dir","."},{"name","AST_NodeType"},{"operation","input"},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 2, \"params\": [\"node\", \"type\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 2, \"types\": [\"r:AST_Node\", \"s:AST_Type\"]}}"}});
     1411 +if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;}
     1412 +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_AST_NodeType_b38285ae9991409e);
     1413 +} catch (std::exception& e) {std::cerr << "Error loading AST_NodeType data: " << e.what() << '\n';
     1414 +exit(1);
     1415 +}
     1416 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","node\tlocation"},{"auxArity","0"},{"fact-dir","."},{"name","AST_NodeLocation"},{"operation","input"},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 2, \"params\": [\"node\", \"location\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 2, \"types\": [\"r:AST_Node\", \"r:AST_Location\"]}}"}});
     1417 +if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;}
     1418 +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_AST_NodeLocation_5f3f38ee7a82c12a);
     1419 +} catch (std::exception& e) {std::cerr << "Error loading AST_NodeLocation data: " << e.what() << '\n';
     1420 +exit(1);
     1421 +}
     1422 +try {std::map<std::string, std::string> directiveMap({{"IO","file"},{"attributeNames","parent\tchild\tfield"},{"auxArity","0"},{"fact-dir","."},{"name","AST_NodeField"},{"operation","input"},{"params","{\"records\": {\"AST_Location\": {\"arity\": 5, \"params\": [\"startByte\", \"startLine\", \"startColumn\", \"endLine\", \"endColumn\"]}, \"AST_Node\": {\"arity\": 2, \"params\": [\"file\", \"nodeId\"]}}, \"relation\": {\"arity\": 3, \"params\": [\"parent\", \"child\", \"field\"]}}"},{"types","{\"ADTs\": {}, \"records\": {\"r:AST_Location\": {\"arity\": 5, \"types\": [\"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\", \"i:AST_FilePosition\"]}, \"r:AST_Node\": {\"arity\": 2, \"types\": [\"i:AST_FileId\", \"i:AST_NodeId\"]}}, \"relation\": {\"arity\": 3, \"types\": [\"r:AST_Node\", \"r:AST_Node\", \"s:AST_Field\"]}}"}});
     1423 +if (!inputDirectoryArg.empty()) {directiveMap["fact-dir"] = inputDirectoryArg;}
     1424 +IOSystem::getInstance().getReader(directiveMap, symTable, recordTable)->readAll(*rel_AST_NodeField_ca02670731ce3c99);
     1425 +} catch (std::exception& e) {std::cerr << "Error loading AST_NodeField data: " << e.what() << '\n';
     1426 +exit(1);
     1427 +}
     1428 +}
     1429 + 
     1430 +void Sf_souffle::dumpInputs(){
     1431 +try {std::map<std::string, std::string> rwOperation;
     1432 +rwOperation["IO"] = "stdout";
     1433 +rwOperation["name"] = "AST_NodeContent";
     1434 +rwOperation["types"] = "{\"relation\": {\"arity\": 2, \"auxArity\": 0, \"types\": [\"r:AST_Node\", \"s:AST_Content\"]}}";
     1435 +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_AST_NodeContent_b2f3666572e60754);
     1436 +} catch (std::exception& e) {std::cerr << e.what();exit(1);}
     1437 +try {std::map<std::string, std::string> rwOperation;
     1438 +rwOperation["IO"] = "stdout";
     1439 +rwOperation["name"] = "AST_ParentChild";
     1440 +rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"r:AST_Node\", \"u:unsigned\", \"r:AST_Node\"]}}";
     1441 +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_AST_ParentChild_be6259205eb66578);
     1442 +} catch (std::exception& e) {std::cerr << e.what();exit(1);}
     1443 +try {std::map<std::string, std::string> rwOperation;
     1444 +rwOperation["IO"] = "stdout";
     1445 +rwOperation["name"] = "AST_NodeType";
     1446 +rwOperation["types"] = "{\"relation\": {\"arity\": 2, \"auxArity\": 0, \"types\": [\"r:AST_Node\", \"s:AST_Type\"]}}";
     1447 +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_AST_NodeType_b38285ae9991409e);
     1448 +} catch (std::exception& e) {std::cerr << e.what();exit(1);}
     1449 +try {std::map<std::string, std::string> rwOperation;
     1450 +rwOperation["IO"] = "stdout";
     1451 +rwOperation["name"] = "AST_NodeLocation";
     1452 +rwOperation["types"] = "{\"relation\": {\"arity\": 2, \"auxArity\": 0, \"types\": [\"r:AST_Node\", \"r:AST_Location\"]}}";
     1453 +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_AST_NodeLocation_5f3f38ee7a82c12a);
     1454 +} catch (std::exception& e) {std::cerr << e.what();exit(1);}
     1455 +try {std::map<std::string, std::string> rwOperation;
     1456 +rwOperation["IO"] = "stdout";
     1457 +rwOperation["name"] = "AST_NodeField";
     1458 +rwOperation["types"] = "{\"relation\": {\"arity\": 3, \"auxArity\": 0, \"types\": [\"r:AST_Node\", \"r:AST_Node\", \"s:AST_Field\"]}}";
     1459 +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_AST_NodeField_ca02670731ce3c99);
     1460 +} catch (std::exception& e) {std::cerr << e.what();exit(1);}
     1461 +}
     1462 + 
     1463 +void Sf_souffle::dumpOutputs(){
     1464 +try {std::map<std::string, std::string> rwOperation;
     1465 +rwOperation["IO"] = "stdout";
     1466 +rwOperation["name"] = "RuleMatch";
     1467 +rwOperation["types"] = "{\"relation\": {\"arity\": 2, \"auxArity\": 0, \"types\": [\"s:RuleName\", \"r:AST_Location\"]}}";
     1468 +IOSystem::getInstance().getWriter(rwOperation, symTable, recordTable)->writeAll(*rel_RuleMatch_8974a5cadf2d4779);
     1469 +} catch (std::exception& e) {std::cerr << e.what();exit(1);}
     1470 +}
     1471 + 
     1472 +SymbolTable& Sf_souffle::getSymbolTable(){
     1473 +return symTable;
     1474 +}
     1475 + 
     1476 +RecordTable& Sf_souffle::getRecordTable(){
     1477 +return recordTable;
     1478 +}
     1479 + 
     1480 +void Sf_souffle::setNumThreads(std::size_t numThreadsValue){
     1481 +SouffleProgram::setNumThreads(numThreadsValue);
     1482 +symTable.setNumLanes(getNumThreads());
     1483 +recordTable.setNumLanes(getNumThreads());
     1484 +regexCache.setNumLanes(getNumThreads());
     1485 +}
     1486 + 
     1487 +void Sf_souffle::executeSubroutine(std::string name,const std::vector<RamDomain>& args,std::vector<RamDomain>& ret){
     1488 +if (name == "AST_NodeContent") {
     1489 +stratum_AST_NodeContent_f29a0e907561c50c.run(args, ret);
     1490 +return;}
     1491 +if (name == "AST_NodeField") {
     1492 +stratum_AST_NodeField_b63714d335ba8b2e.run(args, ret);
     1493 +return;}
     1494 +if (name == "AST_NodeLocation") {
     1495 +stratum_AST_NodeLocation_b120359576603175.run(args, ret);
     1496 +return;}
     1497 +if (name == "AST_NodeType") {
     1498 +stratum_AST_NodeType_f0647903c04c5ec5.run(args, ret);
     1499 +return;}
     1500 +if (name == "AST_ParentChild") {
     1501 +stratum_AST_ParentChild_381ffe0668807a9c.run(args, ret);
     1502 +return;}
     1503 +if (name == "Rule") {
     1504 +stratum_Rule_b7f309df7d140ebc.run(args, ret);
     1505 +return;}
     1506 +if (name == "RuleMatch") {
     1507 +stratum_RuleMatch_a3becf205b4cd965.run(args, ret);
     1508 +return;}
     1509 +fatal(("unknown subroutine " + name).c_str());
     1510 +}
     1511 + 
     1512 +} // namespace souffle
     1513 +namespace souffle {
     1514 +SouffleProgram *newInstance_souffle(){return new souffle::Sf_souffle;}
     1515 +SymbolTable *getST_souffle(SouffleProgram *p){return &reinterpret_cast<souffle::Sf_souffle*>(p)->getSymbolTable();}
     1516 +} // namespace souffle
     1517 + 
     1518 +#ifndef __EMBEDDED_SOUFFLE__
     1519 +#include "souffle/CompiledOptions.h"
     1520 +int main(int argc, char** argv)
     1521 +{
     1522 +try{
     1523 +souffle::CmdOptions opt(R"(souffle/ruby.dl)",
     1524 +R"()",
     1525 +R"()",
     1526 +false,
     1527 +R"()",
     1528 +1);
     1529 +if (!opt.parse(argc,argv)) return 1;
     1530 +souffle::Sf_souffle obj;
     1531 +#if defined(_OPENMP)
     1532 +obj.setNumThreads(opt.getNumJobs());
     1533 + 
     1534 +#endif
     1535 +obj.runAll(opt.getInputFileDir(), opt.getOutputFileDir());
     1536 +return 0;
     1537 +} catch(std::exception &e) { souffle::SignalHandler::instance()->error(e.what());}
     1538 +}
     1539 +#endif
     1540 + 
     1541 +namespace souffle {
     1542 +using namespace souffle;
     1543 +class factory_Sf_souffle: souffle::ProgramFactory {
     1544 +public:
     1545 +souffle::SouffleProgram* newInstance();
     1546 + factory_Sf_souffle();
     1547 +private:
     1548 +};
     1549 +} // namespace souffle
     1550 +namespace souffle {
     1551 +using namespace souffle;
     1552 +souffle::SouffleProgram* factory_Sf_souffle::newInstance(){
     1553 +return new souffle::Sf_souffle();
     1554 +}
     1555 + 
     1556 + factory_Sf_souffle::factory_Sf_souffle():
     1557 +souffle::ProgramFactory("souffle"){
     1558 +}
     1559 + 
     1560 +} // namespace souffle
     1561 +namespace souffle {
     1562 + 
     1563 +#ifdef __EMBEDDED_SOUFFLE__
     1564 +extern "C" {
     1565 +souffle::factory_Sf_souffle __factory_Sf_souffle_instance;
     1566 +}
     1567 +#endif
     1568 +} // namespace souffle
     1569 + 
     1570 + 
  • ■ ■ ■ ■ ■
    pkg/souffle/rules/rules.go
     1 +package rules
     2 + 
     3 +// #cgo CXXFLAGS: -std=c++17 -D__EMBEDDED_SOUFFLE__
     4 +import "C"
     5 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/set/set.go
     1 +package set
     2 + 
     3 +type Set[T comparable] map[T]struct{}
     4 + 
     5 +func New[T comparable]() Set[T] {
     6 + return make(Set[T])
     7 +}
     8 + 
     9 +func (set Set[T]) Add(item T) {
     10 + set[item] = struct{}{}
     11 +}
     12 + 
     13 +func (set Set[T]) Has(item T) bool {
     14 + _, exists := set[item]
     15 + return exists
     16 +}
     17 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/binding/binding.cpp
     1 +#include "binding.h"
     2 +#include "souffle/SouffleInterface.h"
     3 + 
     4 +extern "C"
     5 +{
     6 + SouffleProgram souffle_program_factory_new_instance(const char *name)
     7 + {
     8 + return souffle::ProgramFactory::newInstance(name);
     9 + }
     10 +}
     11 + 
     12 +typedef struct
     13 +{
     14 + SouffleSymbolTable symbolTable;
     15 + int32_t *elements;
     16 + size_t arity;
     17 + bool owned;
     18 +} InternalRecordTuple;
     19 + 
     20 +extern "C"
     21 +{
     22 + SouffleRecordTuple souffle_program_new_record_tuple(const SouffleProgram program, size_t arity)
     23 + {
     24 + InternalRecordTuple *tuple = new InternalRecordTuple;
     25 + 
     26 + tuple->symbolTable = &((souffle::SouffleProgram *)program)->getSymbolTable();
     27 + tuple->arity = arity;
     28 + tuple->elements = (int32_t *)malloc(arity * sizeof(int32_t));
     29 + tuple->owned = true;
     30 + 
     31 + return tuple;
     32 + }
     33 + 
     34 + SouffleRelation souffle_program_get_relation(const SouffleProgram program, const char *name)
     35 + {
     36 + return ((souffle::SouffleProgram *)program)->getRelation(name);
     37 + }
     38 + 
     39 + int32_t souffle_program_pack_record(const SouffleProgram program, const SouffleRecordTuple tuple)
     40 + {
     41 + souffle::RecordTable &recordTable = ((souffle::SouffleProgram *)program)->getRecordTable();
     42 + InternalRecordTuple *internalTuple = (InternalRecordTuple *)tuple;
     43 + 
     44 + return recordTable.pack(internalTuple->elements, internalTuple->arity);
     45 + }
     46 + 
     47 + SouffleRecordTuple souffle_program_unpack_record(const SouffleProgram program, int32_t index, size_t arity)
     48 + {
     49 + souffle::SouffleProgram *souffleProgram = (souffle::SouffleProgram *)program;
     50 + 
     51 + InternalRecordTuple *tuple = new InternalRecordTuple;
     52 + tuple->symbolTable = &souffleProgram->getSymbolTable();
     53 + tuple->arity = arity;
     54 + tuple->elements = (int32_t *)souffleProgram->getRecordTable().unpack(index, arity);
     55 + tuple->owned = false;
     56 + 
     57 + return tuple;
     58 + }
     59 + 
     60 + void souffle_program_run(const SouffleProgram program)
     61 + {
     62 + ((souffle::SouffleProgram *)program)->run();
     63 + }
     64 + 
     65 + void souffle_program_free(SouffleProgram program)
     66 + {
     67 + delete (souffle::SouffleProgram *)program;
     68 + }
     69 +}
     70 + 
     71 +extern "C"
     72 +{
     73 + const char *souffle_record_tuple_read_symbol(const SouffleRecordTuple tuple, size_t index)
     74 + {
     75 + InternalRecordTuple *internalTuple = (InternalRecordTuple *)tuple;
     76 + souffle::SymbolTable &symbolTable = (souffle::SymbolTable &)internalTuple->symbolTable;
     77 + 
     78 + return symbolTable.decode(index).c_str();
     79 + }
     80 + 
     81 + uint32_t souffle_record_tuple_read_unsigned(const SouffleRecordTuple tuple, size_t index)
     82 + {
     83 + InternalRecordTuple *internalTuple = (InternalRecordTuple *)tuple;
     84 + 
     85 + return souffle::ramBitCast<souffle::RamUnsigned>(internalTuple->elements[index]);
     86 + }
     87 + 
     88 + int32_t souffle_record_tuple_read_integer(const SouffleRecordTuple tuple, size_t index)
     89 + {
     90 + return ((InternalRecordTuple *)tuple)->elements[index];
     91 + }
     92 + 
     93 + void souffle_record_tuple_write_symbol(const SouffleRecordTuple tuple, size_t index, const char *value)
     94 + {
     95 + InternalRecordTuple *internalTuple = (InternalRecordTuple *)tuple;
     96 + souffle::SymbolTable &symbolTable = (souffle::SymbolTable &)internalTuple->symbolTable;
     97 + 
     98 + internalTuple->elements[index] = symbolTable.encode(value);
     99 + }
     100 + 
     101 + void souffle_record_tuple_write_unsigned(const SouffleRecordTuple tuple, size_t index, uint32_t value)
     102 + {
     103 + ((InternalRecordTuple *)tuple)->elements[index] = souffle::ramBitCast(value);
     104 + }
     105 + 
     106 + void souffle_record_tuple_write_integer(const SouffleRecordTuple tuple, size_t index, int32_t value)
     107 + {
     108 + ((InternalRecordTuple *)tuple)->elements[index] = value;
     109 + }
     110 + 
     111 + void souffle_record_tuple_free(SouffleRecordTuple tuple)
     112 + {
     113 + InternalRecordTuple *internalTuple = (InternalRecordTuple *)tuple;
     114 + 
     115 + if (internalTuple->owned) {
     116 + free(internalTuple->elements);
     117 + }
     118 + 
     119 + free((void *)tuple);
     120 + }
     121 +}
     122 + 
     123 +typedef struct
     124 +{
     125 + souffle::Relation::iterator current;
     126 + souffle::Relation::iterator end;
     127 +} InternalRelationIterator;
     128 + 
     129 +extern "C"
     130 +{
     131 + SouffleTuple souffle_relation_new_tuple(const SouffleRelation relation)
     132 + {
     133 + return new souffle::tuple((souffle::Relation *)relation);
     134 + }
     135 + 
     136 + SouffleRelationIterator souffle_relation_new_iterator(const SouffleRelation relation)
     137 + {
     138 + souffle::Relation *souffleRelation = (souffle::Relation *)relation;
     139 + 
     140 + return new InternalRelationIterator{souffleRelation->begin(), souffleRelation->end()};
     141 + }
     142 + 
     143 + void souffle_relation_insert(const SouffleRelation relation, const SouffleTuple tuple)
     144 + {
     145 + ((souffle::Relation *)relation)->insert(*(souffle::tuple *)tuple);
     146 + }
     147 + 
     148 + size_t souffle_relation_size(const SouffleRelation relation)
     149 + {
     150 + return ((souffle::Relation *)relation)->size();
     151 + }
     152 + 
     153 + size_t souffle_relation_arity(const SouffleRelation relation)
     154 + {
     155 + return ((souffle::Relation *)relation)->getArity();
     156 + }
     157 + 
     158 + const char *souffle_relation_attr_type(const SouffleRelation relation, size_t index)
     159 + {
     160 + return ((souffle::Relation *)relation)->getAttrType(index);
     161 + }
     162 +}
     163 + 
     164 +extern "C"
     165 +{
     166 + char *souffle_tuple_read_symbol(const SouffleTuple tuple)
     167 + {
     168 + std::string value;
     169 + (*(souffle::tuple *)tuple) >> value;
     170 + 
     171 + const size_t bufferSize = value.size() + 1; // including null byte
     172 + char *buffer = (char *)malloc(bufferSize * sizeof(char));
     173 + memcpy(buffer, value.c_str(), bufferSize);
     174 + 
     175 + return buffer;
     176 + }
     177 + 
     178 + uint32_t souffle_tuple_read_unsigned(const SouffleTuple tuple)
     179 + {
     180 + uint32_t value;
     181 + (*(souffle::tuple *)tuple) >> value;
     182 + 
     183 + return value;
     184 + }
     185 + 
     186 + int32_t souffle_tuple_read_integer(const SouffleTuple tuple)
     187 + {
     188 + int32_t value;
     189 + (*(souffle::tuple *)tuple) >> value;
     190 + 
     191 + return value;
     192 + }
     193 + 
     194 + void souffle_tuple_write_symbol(const SouffleTuple tuple, const char *value)
     195 + {
     196 + std::string stringValue(value);
     197 + (*(souffle::tuple *)tuple) << stringValue;
     198 + }
     199 + 
     200 + void souffle_tuple_write_unsigned(const SouffleTuple tuple, uint32_t value)
     201 + {
     202 + (*(souffle::tuple *)tuple) << value;
     203 + }
     204 + 
     205 + void souffle_tuple_write_integer(const SouffleTuple tuple, int32_t value)
     206 + {
     207 + (*(souffle::tuple *)tuple) << value;
     208 + }
     209 + 
     210 + void souffle_tuple_free(SouffleTuple tuple)
     211 + {
     212 + delete (souffle::tuple *)tuple;
     213 + }
     214 +}
     215 + 
     216 +extern "C"
     217 +{
     218 + bool souffle_relation_iterator_has_next(const SouffleRelationIterator iterator)
     219 + {
     220 + InternalRelationIterator *internalIterator = (InternalRelationIterator *)iterator;
     221 + 
     222 + return internalIterator->current != internalIterator->end;
     223 + }
     224 + 
     225 + SouffleTuple souffle_relation_iterator_get_next(const SouffleRelationIterator iterator)
     226 + {
     227 + InternalRelationIterator *internalIterator = (InternalRelationIterator *)iterator;
     228 + 
     229 + SouffleTuple result = &*internalIterator->current;
     230 + internalIterator->current++;
     231 + 
     232 + return result;
     233 + }
     234 + 
     235 + void souffle_relation_iterator_free(SouffleRelationIterator iterator)
     236 + {
     237 + InternalRelationIterator *internalIterator = (InternalRelationIterator *)iterator;
     238 + 
     239 + delete internalIterator;
     240 + }
     241 +}
     242 + 
     243 +extern "C"
     244 +{
     245 + void c_free(void *c)
     246 + {
     247 + free(c);
     248 + }
     249 +}
     250 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/binding/binding.go
     1 +package binding
     2 + 
     3 +// #cgo CXXFLAGS: -std=c++17
     4 +// #include "binding.h"
     5 +import "C"
     6 +import (
     7 + "fmt"
     8 + "runtime"
     9 + "unsafe"
     10 +)
     11 + 
     12 +type Program struct {
     13 + c C.SouffleProgram
     14 +}
     15 + 
     16 +type Relation struct {
     17 + c C.SouffleRelation
     18 +}
     19 + 
     20 +type RelationIterator struct {
     21 + c C.SouffleRelationIterator
     22 + relation *Relation
     23 +}
     24 + 
     25 +type Tuple struct {
     26 + c C.SouffleTuple
     27 + relation *Relation
     28 + owned bool
     29 +}
     30 + 
     31 +type RecordTuple struct {
     32 + c C.SouffleRecordTuple
     33 +}
     34 + 
     35 +// A large number but low enough to be supported on all arch's
     36 +const maxCArrayIndex = 1<<30 - 1
     37 + 
     38 +func NewProgram(name string) (*Program, error) {
     39 + cName := C.CString(name)
     40 + defer C.free(unsafe.Pointer(cName))
     41 + 
     42 + cProgram := C.souffle_program_factory_new_instance(cName)
     43 + if cProgram == nil {
     44 + return nil, fmt.Errorf("%s program not found", name)
     45 + }
     46 + 
     47 + program := &Program{c: cProgram}
     48 + runtime.SetFinalizer(program, func(finalizedProgram *Program) {
     49 + finalizedProgram.Close()
     50 + })
     51 + 
     52 + return program, nil
     53 +}
     54 + 
     55 +func (program *Program) Relation(name string) (*Relation, error) {
     56 + cName := C.CString(name)
     57 + defer C.free(unsafe.Pointer(cName))
     58 + 
     59 + cRelation := C.souffle_program_get_relation(program.c, cName)
     60 + if cRelation == nil {
     61 + return nil, fmt.Errorf("%s relation not found", name)
     62 + }
     63 + 
     64 + return &Relation{c: cRelation}, nil
     65 +}
     66 + 
     67 +func (program *Program) PackRecord(tuple *RecordTuple) int32 {
     68 + return int32(C.souffle_program_pack_record(program.c, tuple.c))
     69 +}
     70 + 
     71 +func (program *Program) UnpackRecord(index int32, arity int) (tuple *RecordTuple) {
     72 + cTuple := C.souffle_program_unpack_record(program.c, C.int32_t(index), C.size_t(arity))
     73 + 
     74 + return &RecordTuple{c: cTuple}
     75 +}
     76 + 
     77 +func (program *Program) NewRecordTuple(arity int) *RecordTuple {
     78 + cTuple := C.souffle_program_new_record_tuple(program.c, C.size_t(arity))
     79 + 
     80 + tuple := &RecordTuple{c: cTuple}
     81 + runtime.SetFinalizer(tuple, func(finalizedTuple *RecordTuple) {
     82 + finalizedTuple.Close()
     83 + })
     84 + 
     85 + return tuple
     86 +}
     87 + 
     88 +func (program *Program) Run() {
     89 + C.souffle_program_run(program.c)
     90 +}
     91 + 
     92 +func (program *Program) Close() {
     93 + runtime.SetFinalizer(program, nil)
     94 + C.souffle_program_free(program.c)
     95 +}
     96 + 
     97 +func (relation *Relation) NewIterator() *RelationIterator {
     98 + cIterator := C.souffle_relation_new_iterator(relation.c)
     99 + 
     100 + iterator := &RelationIterator{c: cIterator, relation: relation}
     101 + runtime.SetFinalizer(iterator, func(finalizedIterator *RelationIterator) {
     102 + finalizedIterator.Close()
     103 + })
     104 + 
     105 + return iterator
     106 +}
     107 + 
     108 +func (relation *Relation) NewTuple() *Tuple {
     109 + cTuple := C.souffle_relation_new_tuple(relation.c)
     110 + 
     111 + tuple := &Tuple{c: cTuple, relation: relation, owned: true}
     112 + runtime.SetFinalizer(tuple, func(finalizedTuple *Tuple) {
     113 + finalizedTuple.Close()
     114 + })
     115 + 
     116 + return tuple
     117 +}
     118 + 
     119 +func (relation *Relation) Insert(tuple *Tuple) {
     120 + C.souffle_relation_insert(relation.c, tuple.c)
     121 +}
     122 + 
     123 +func (relation *Relation) Size() int {
     124 + return int(C.souffle_relation_size(relation.c))
     125 +}
     126 + 
     127 +func (relation *Relation) Arity() int {
     128 + return int(C.souffle_relation_arity(relation.c))
     129 +}
     130 + 
     131 +func (relation *Relation) AttrType(index int) string {
     132 + cValue := C.souffle_relation_attr_type(relation.c, C.size_t(index))
     133 + return C.GoString(cValue)
     134 +}
     135 + 
     136 +func (iterator *RelationIterator) HasNext() bool {
     137 + return bool(C.souffle_relation_iterator_has_next(iterator.c))
     138 +}
     139 + 
     140 +func (iterator *RelationIterator) GetNext() *Tuple {
     141 + cTuple := C.souffle_relation_iterator_get_next(iterator.c)
     142 + 
     143 + return &Tuple{c: cTuple, relation: iterator.relation, owned: false}
     144 +}
     145 + 
     146 +func (iterator *RelationIterator) Close() {
     147 + C.souffle_relation_iterator_free(iterator.c)
     148 +}
     149 + 
     150 +func (tuple *Tuple) ReadSymbol() string {
     151 + cValue := C.souffle_tuple_read_symbol(tuple.c)
     152 + defer C.free(unsafe.Pointer(cValue))
     153 + 
     154 + return C.GoString(cValue)
     155 +}
     156 + 
     157 +func (tuple *Tuple) ReadUnsigned() uint32 {
     158 + return uint32(C.souffle_tuple_read_unsigned(tuple.c))
     159 +}
     160 + 
     161 +func (tuple *Tuple) ReadInteger() int32 {
     162 + return int32(C.souffle_tuple_read_integer(tuple.c))
     163 +}
     164 + 
     165 +func (tuple *Tuple) WriteSymbol(value string) {
     166 + cValue := C.CString(value)
     167 + defer C.free(unsafe.Pointer(cValue))
     168 + 
     169 + C.souffle_tuple_write_symbol(tuple.c, cValue)
     170 +}
     171 + 
     172 +func (tuple *Tuple) WriteUnsigned(value uint32) {
     173 + C.souffle_tuple_write_unsigned(tuple.c, C.uint32_t(value))
     174 +}
     175 + 
     176 +func (tuple *Tuple) WriteInteger(value int32) {
     177 + C.souffle_tuple_write_integer(tuple.c, C.int32_t(value))
     178 +}
     179 + 
     180 +func (tuple *Tuple) Relation() *Relation {
     181 + return tuple.relation
     182 +}
     183 + 
     184 +func (tuple *Tuple) Close() {
     185 + if tuple.owned {
     186 + runtime.SetFinalizer(tuple, nil)
     187 + C.souffle_tuple_free(tuple.c)
     188 + }
     189 +}
     190 + 
     191 +func (tuple *RecordTuple) ReadSymbol(index int) string {
     192 + return C.GoString(C.souffle_record_tuple_read_symbol(tuple.c, C.size_t(index)))
     193 +}
     194 + 
     195 +func (tuple *RecordTuple) ReadUnsigned(index int) uint32 {
     196 + return uint32(C.souffle_record_tuple_read_unsigned(tuple.c, C.size_t(index)))
     197 +}
     198 + 
     199 +func (tuple *RecordTuple) ReadInteger(index int) int32 {
     200 + return int32(C.souffle_record_tuple_read_integer(tuple.c, C.size_t(index)))
     201 +}
     202 + 
     203 +func (tuple *RecordTuple) WriteSymbol(index int, value string) {
     204 + cValue := C.CString(value)
     205 + defer C.free(unsafe.Pointer(cValue))
     206 + 
     207 + C.souffle_record_tuple_write_symbol(tuple.c, C.size_t(index), cValue)
     208 +}
     209 + 
     210 +func (tuple *RecordTuple) WriteUnsigned(index int, value uint32) {
     211 + C.souffle_record_tuple_write_unsigned(tuple.c, C.size_t(index), C.uint32_t(value))
     212 +}
     213 + 
     214 +func (tuple *RecordTuple) WriteInteger(index int, value int32) {
     215 + C.souffle_record_tuple_write_integer(tuple.c, C.size_t(index), C.int32_t(value))
     216 +}
     217 + 
     218 +func (tuple *RecordTuple) Close() {
     219 + runtime.SetFinalizer(tuple, nil)
     220 + C.souffle_record_tuple_free(tuple.c)
     221 +}
     222 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/binding/binding.h
     1 +#include <stdbool.h>
     2 +#include <stddef.h>
     3 +#include <stdint.h>
     4 +#include <stdlib.h>
     5 + 
     6 +typedef void *SouffleProgram;
     7 +typedef void *SouffleRelation;
     8 +typedef void *SouffleTuple;
     9 +typedef void *SouffleSymbolTable;
     10 +typedef void *SouffleRelationIterator;
     11 +typedef void *SouffleRecordTuple;
     12 + 
     13 +#ifdef __cplusplus
     14 +extern "C"
     15 +{
     16 +#endif
     17 + SouffleProgram souffle_program_factory_new_instance(const char *name);
     18 + 
     19 + SouffleRecordTuple souffle_program_new_record_tuple(const SouffleProgram program, size_t arity);
     20 + SouffleRelation souffle_program_get_relation(const SouffleProgram program, const char *name);
     21 + int32_t souffle_program_pack_record(const SouffleProgram program, const SouffleRecordTuple tuple);
     22 + SouffleRecordTuple souffle_program_unpack_record(const SouffleProgram program, int32_t index, size_t arity);
     23 + void souffle_program_run(const SouffleProgram program);
     24 + void souffle_program_free(SouffleProgram program);
     25 + 
     26 + SouffleTuple souffle_relation_new_tuple(const SouffleRelation relation);
     27 + SouffleRelationIterator souffle_relation_new_iterator(const SouffleRelation relation);
     28 + void souffle_relation_insert(const SouffleRelation relation, const SouffleTuple tuple);
     29 + size_t souffle_relation_size(const SouffleRelation relation);
     30 + size_t souffle_relation_arity(const SouffleRelation relation);
     31 + const char *souffle_relation_attr_type(const SouffleRelation relation, size_t index);
     32 + 
     33 + char *souffle_tuple_read_symbol(const SouffleTuple tuple);
     34 + uint32_t souffle_tuple_read_unsigned(const SouffleTuple tuple);
     35 + int32_t souffle_tuple_read_integer(const SouffleTuple tuple);
     36 + void souffle_tuple_write_symbol(const SouffleTuple tuple, const char *value);
     37 + void souffle_tuple_write_unsigned(const SouffleTuple tuple, uint32_t value);
     38 + void souffle_tuple_write_integer(const SouffleTuple tuple, int32_t value);
     39 + void souffle_tuple_free(SouffleTuple tuple);
     40 + 
     41 + const char *souffle_record_tuple_read_symbol(const SouffleRecordTuple tuple, size_t index);
     42 + uint32_t souffle_record_tuple_read_unsigned(const SouffleRecordTuple tuple, size_t index);
     43 + int32_t souffle_record_tuple_read_integer(const SouffleRecordTuple tuple, size_t index);
     44 + void souffle_record_tuple_write_symbol(const SouffleRecordTuple tuple, size_t index, const char *value);
     45 + void souffle_record_tuple_write_unsigned(const SouffleRecordTuple tuple, size_t index, uint32_t value);
     46 + void souffle_record_tuple_write_integer(const SouffleRecordTuple tuple, size_t index, int32_t value);
     47 + void souffle_record_tuple_free(SouffleRecordTuple tuple);
     48 + 
     49 + bool souffle_relation_iterator_has_next(const SouffleRelationIterator iterator);
     50 + SouffleTuple souffle_relation_iterator_get_next(const SouffleRelationIterator iterator);
     51 + void souffle_relation_iterator_free(SouffleRelationIterator iterator);
     52 +#ifdef __cplusplus
     53 +}
     54 +#endif
     55 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/compiler/compiler.go
     1 +package compiler
     2 + 
     3 +// func Compile(inputFilename, outputFilename string) error {
     4 +// cmd := exec.Command("souffle", "-g", outputFilename, inputFilename)
     5 +// if err := cmd.Run(); err != nil {
     6 +// return fmt.Errorf("souffle compilation error: %w", err)
     7 +// }
     8 + 
     9 +// return nil
     10 +// }
     11 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/souffle.go
     1 +package souffle
     2 + 
     3 +import (
     4 + "fmt"
     5 + "reflect"
     6 + 
     7 + _ "github.com/bearer/bearer/pkg/souffle/rules" // FIXME: this should be up in main or something
     8 + "github.com/bearer/bearer/pkg/util/souffle/binding"
     9 +)
     10 + 
     11 +type Souffle struct {
     12 + program *binding.Program
     13 +}
     14 + 
     15 +func New(programName string) (*Souffle, error) {
     16 + program, err := binding.NewProgram(programName)
     17 + if err != nil {
     18 + return nil, err
     19 + }
     20 + 
     21 + return &Souffle{program: program}, nil
     22 +}
     23 + 
     24 +func (souffle *Souffle) Marshal(relation *binding.Relation, value any) (*binding.Tuple, error) {
     25 + fields, err := getFields(reflect.TypeOf(value))
     26 + if err != nil {
     27 + return nil, err
     28 + }
     29 + 
     30 + if relation.Arity() != len(fields) {
     31 + return nil, fmt.Errorf("mismatch in arity (relation=%d, struct=%d)", relation.Arity(), len(fields))
     32 + }
     33 + 
     34 + typeValue := reflect.ValueOf(value)
     35 + tuple := relation.NewTuple()
     36 + 
     37 + for _, field := range fields {
     38 + fieldValue := typeValue.FieldByIndex(field.Index)
     39 + 
     40 + switch field.Type.Kind() {
     41 + case reflect.String:
     42 + tuple.WriteSymbol(fieldValue.String())
     43 + case reflect.Uint32:
     44 + tuple.WriteUnsigned(uint32(fieldValue.Uint()))
     45 + case reflect.Int32:
     46 + tuple.WriteInteger(int32(fieldValue.Int()))
     47 + case reflect.Struct:
     48 + index, err := souffle.encodeRecord(fieldValue)
     49 + if err != nil {
     50 + return nil, fmt.Errorf("encoding error for field %s: %w", field.Name, err)
     51 + }
     52 + 
     53 + tuple.WriteInteger(index)
     54 + default:
     55 + return nil, fmt.Errorf("kind %s not supported for field %s", field.Type.Kind(), field.Name)
     56 + }
     57 + }
     58 + 
     59 + return tuple, nil
     60 +}
     61 + 
     62 +func (souffle *Souffle) Unmarshal(destination any, tuple *binding.Tuple) error {
     63 + typ := reflect.TypeOf(destination)
     64 + if typ.Kind() != reflect.Pointer {
     65 + return fmt.Errorf("type %s not a pointer but %s", typ.Name(), typ.Kind())
     66 + }
     67 + 
     68 + fields, err := getFields(typ.Elem())
     69 + if err != nil {
     70 + return err
     71 + }
     72 + 
     73 + if tuple.Relation().Arity() != len(fields) {
     74 + return fmt.Errorf("mismatch in arity (tuple=%d, struct=%d)", tuple.Relation().Arity(), len(fields))
     75 + }
     76 + 
     77 + typeValue := reflect.Indirect(reflect.ValueOf(destination))
     78 + 
     79 + for _, field := range fields {
     80 + 
     81 + fieldValue := typeValue.FieldByIndex(field.Index)
     82 + 
     83 + switch field.Type.Kind() {
     84 + case reflect.String:
     85 + fieldValue.SetString(tuple.ReadSymbol())
     86 + case reflect.Uint32:
     87 + fieldValue.SetUint(uint64(tuple.ReadUnsigned()))
     88 + case reflect.Int32:
     89 + fieldValue.SetInt(int64(tuple.ReadInteger()))
     90 + case reflect.Struct:
     91 + err := souffle.decodeRecord(field.Type, fieldValue.Addr(), tuple.ReadInteger())
     92 + if err != nil {
     93 + return fmt.Errorf("decoding error for field %s: %w", field.Name, err)
     94 + }
     95 + default:
     96 + return fmt.Errorf("kind %s not supported (field %s)", field.Type.Kind(), field.Name)
     97 + }
     98 + }
     99 + 
     100 + return nil
     101 +}
     102 + 
     103 +func (souffle *Souffle) encodeRecord(value reflect.Value) (int32, error) {
     104 + fields, err := getFields(value.Type())
     105 + if err != nil {
     106 + return 0, err
     107 + }
     108 + 
     109 + // TODO: Is there some way to check the arity?
     110 + 
     111 + recordTuple := souffle.program.NewRecordTuple(len(fields))
     112 + defer recordTuple.Close()
     113 + 
     114 + for i, field := range fields {
     115 + fieldValue := value.FieldByIndex(field.Index)
     116 + 
     117 + switch field.Type.Kind() {
     118 + case reflect.String:
     119 + recordTuple.WriteSymbol(i, fieldValue.String())
     120 + case reflect.Uint32:
     121 + recordTuple.WriteUnsigned(i, uint32(fieldValue.Uint()))
     122 + case reflect.Int32:
     123 + recordTuple.WriteInteger(i, int32(fieldValue.Int()))
     124 + case reflect.Struct:
     125 + index, err := souffle.encodeRecord(fieldValue)
     126 + if err != nil {
     127 + return 0, fmt.Errorf("encoding error for field %s: %w", field.Name, err)
     128 + }
     129 + 
     130 + recordTuple.WriteInteger(i, index)
     131 + default:
     132 + return 0, fmt.Errorf("kind %s not supported for field %s", field.Type.Kind(), field.Name)
     133 + }
     134 + }
     135 + 
     136 + return souffle.program.PackRecord(recordTuple), nil
     137 +}
     138 + 
     139 +func (souffle *Souffle) decodeRecord(typ reflect.Type, destination reflect.Value, index int32) error {
     140 + fields, err := getFields(typ)
     141 + if err != nil {
     142 + return err
     143 + }
     144 + 
     145 + // TODO: Is there some way to check the arity?
     146 + 
     147 + recordTuple := souffle.program.UnpackRecord(index, len(fields))
     148 + defer recordTuple.Close()
     149 + 
     150 + value := reflect.Indirect(destination)
     151 + 
     152 + for i, field := range fields {
     153 + fieldValue := value.FieldByIndex(field.Index)
     154 + 
     155 + switch field.Type.Kind() {
     156 + case reflect.String:
     157 + fieldValue.SetString(recordTuple.ReadSymbol(i))
     158 + case reflect.Uint32:
     159 + fieldValue.SetUint(uint64(recordTuple.ReadUnsigned(i)))
     160 + case reflect.Int32:
     161 + fieldValue.SetInt(int64(recordTuple.ReadInteger(i)))
     162 + case reflect.Struct:
     163 + err := souffle.decodeRecord(field.Type, fieldValue.Addr(), recordTuple.ReadInteger(i))
     164 + if err != nil {
     165 + return fmt.Errorf("decoding error for field %s: %w", field.Name, err)
     166 + }
     167 + default:
     168 + return fmt.Errorf("kind %s not supported for field %s", field.Type.Kind(), field.Name)
     169 + }
     170 + }
     171 + 
     172 + return nil
     173 +}
     174 + 
     175 +func getFields(typ reflect.Type) ([]reflect.StructField, error) {
     176 + if typ.Kind() != reflect.Struct {
     177 + return nil, fmt.Errorf("type %s not a struct but %s", typ.Name(), typ.Kind())
     178 + }
     179 + 
     180 + var fields []reflect.StructField
     181 + 
     182 + for i := 0; i < typ.NumField(); i++ {
     183 + field := typ.Field(i)
     184 + tag := field.Tag.Get("souffle")
     185 + 
     186 + if field.IsExported() && tag != "-" {
     187 + fields = append(fields, field)
     188 + }
     189 + }
     190 + 
     191 + return fields, nil
     192 +}
     193 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/writer/base/base.go
     1 +package base
     2 + 
     3 +type Base struct{}
     4 + 
     5 +func (writer *Base) Symbol(value string) Symbol {
     6 + return Symbol(value)
     7 +}
     8 + 
     9 +func (writer *Base) Unsigned(value uint32) Unsigned {
     10 + return Unsigned(value)
     11 +}
     12 + 
     13 +func (writer *Base) Record(elements ...Element) Record {
     14 + return Record(elements)
     15 +}
     16 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/writer/base/element.go
     1 +package base
     2 + 
     3 +import (
     4 + "fmt"
     5 + "strconv"
     6 + "strings"
     7 +)
     8 + 
     9 +type Symbol string
     10 +type Unsigned uint32
     11 +type Record []Element
     12 + 
     13 +type Element interface {
     14 + String() string
     15 + sealedElement()
     16 +}
     17 + 
     18 +func (Symbol) sealedElement() {}
     19 +func (Unsigned) sealedElement() {}
     20 +func (Record) sealedElement() {}
     21 + 
     22 +func (unsigned Unsigned) String() string {
     23 + return fmt.Sprintf("%d", unsigned)
     24 +}
     25 + 
     26 +func (symbol Symbol) String() string {
     27 + return strconv.Quote(string(symbol))
     28 +}
     29 + 
     30 +func (record Record) String() string {
     31 + elementsStrings := make([]string, len(record))
     32 + for i, recordElement := range record {
     33 + elementsStrings[i] = ElementString(recordElement)
     34 + }
     35 + 
     36 + return fmt.Sprintf("[%s]", strings.Join(elementsStrings, ", "))
     37 +}
     38 + 
     39 +func ElementString(element interface{ String() string }) string {
     40 + if element == nil {
     41 + return "nil"
     42 + }
     43 + 
     44 + return element.String()
     45 +}
     46 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/writer/base/literal.go
     1 +package base
     2 + 
     3 +import (
     4 + "fmt"
     5 + "strings"
     6 +)
     7 + 
     8 +type Any struct{}
     9 +type Identifier string
     10 + 
     11 +type Conjunction []Literal
     12 +type Disjunction []Literal
     13 + 
     14 +type Predicate struct {
     15 + Name string
     16 + Elements []LiteralElement
     17 +}
     18 + 
     19 +type NegativePredicate Predicate
     20 + 
     21 +type Literal interface {
     22 + String() string
     23 + sealedLiteral()
     24 +}
     25 + 
     26 +func (Conjunction) sealedLiteral() {}
     27 +func (Disjunction) sealedLiteral() {}
     28 +func (Predicate) sealedLiteral() {}
     29 +func (NegativePredicate) sealedLiteral() {}
     30 + 
     31 +type LiteralElement interface {
     32 + String() string
     33 + sealedLiteralElement()
     34 +}
     35 + 
     36 +// func (Record) sealedLiteralElement() {} // needs LiteralRecord
     37 +func (Symbol) sealedLiteralElement() {}
     38 +func (Unsigned) sealedLiteralElement() {}
     39 +func (Any) sealedLiteralElement() {}
     40 +func (Identifier) sealedLiteralElement() {}
     41 +func (Predicate) sealedLiteralElement() {}
     42 + 
     43 +func (any Any) String() string {
     44 + return "_"
     45 +}
     46 + 
     47 +func (identifier Identifier) String() string {
     48 + return string(identifier)
     49 +}
     50 + 
     51 +func (conjunction Conjunction) String() string {
     52 + literals := make([]string, len(conjunction))
     53 + for i, literal := range conjunction {
     54 + literals[i] = literal.String()
     55 + }
     56 + 
     57 + return strings.Join(literals, ", ")
     58 +}
     59 + 
     60 +func (disjunction Disjunction) String() string {
     61 + literals := make([]string, len(disjunction))
     62 + for i, literal := range disjunction {
     63 + literals[i] = literal.String()
     64 + }
     65 + 
     66 + return fmt.Sprintf("(%s)", strings.Join(literals, "; "))
     67 +}
     68 + 
     69 +func (predicate Predicate) String() string {
     70 + builder := strings.Builder{}
     71 + 
     72 + builder.WriteString(predicate.Name)
     73 + builder.WriteString("(")
     74 + 
     75 + for i, element := range predicate.Elements {
     76 + if i != 0 {
     77 + builder.WriteString(", ")
     78 + }
     79 + 
     80 + builder.WriteString(ElementString(element))
     81 + }
     82 + 
     83 + builder.WriteString(")")
     84 + 
     85 + return builder.String()
     86 +}
     87 + 
     88 +func (predicate NegativePredicate) String() string {
     89 + return "!" + Predicate(predicate).String()
     90 +}
     91 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/writer/file/file.go
     1 +package file
     2 + 
     3 +import (
     4 + "io"
     5 + "strings"
     6 + 
     7 + "github.com/bearer/bearer/pkg/util/souffle/writer/base"
     8 +)
     9 + 
     10 +type Writer struct {
     11 + base.Base
     12 + output io.StringWriter
     13 +}
     14 + 
     15 +func New(output io.StringWriter) *Writer {
     16 + return &Writer{output: output}
     17 +}
     18 + 
     19 +func (writer *Writer) Any() base.Any {
     20 + return base.Any{}
     21 +}
     22 + 
     23 +func (writer *Writer) Identifier(value string) base.Identifier {
     24 + return base.Identifier(value)
     25 +}
     26 + 
     27 +func (writer *Writer) Conjunction(literals ...base.Literal) base.Conjunction {
     28 + return base.Conjunction(literals)
     29 +}
     30 + 
     31 +func (writer *Writer) Disjunction(literals ...base.Literal) base.Disjunction {
     32 + return base.Disjunction(literals)
     33 +}
     34 + 
     35 +func (writer *Writer) Predicate(name string, elements ...base.LiteralElement) base.Predicate {
     36 + return base.Predicate{Name: name, Elements: elements}
     37 +}
     38 + 
     39 +func (writer *Writer) NegativePredicate(name string, elements ...base.LiteralElement) base.NegativePredicate {
     40 + return base.NegativePredicate(base.Predicate{Name: name, Elements: elements})
     41 +}
     42 + 
     43 +func (writer *Writer) WriteRule(head base.Predicate, body ...base.Literal) error {
     44 + builder := strings.Builder{}
     45 + 
     46 + builder.WriteString(head.String())
     47 + builder.WriteString(" :- ")
     48 + builder.WriteString(writer.Conjunction(body...).String())
     49 + builder.WriteString(".\n")
     50 + 
     51 + return writer.write(builder.String())
     52 +}
     53 + 
     54 +func (writer *Writer) WriteFact(relation string, elements ...base.Element) error {
     55 + builder := strings.Builder{}
     56 + 
     57 + builder.WriteString(relation)
     58 + builder.WriteString("(")
     59 + 
     60 + for i, element := range elements {
     61 + if i != 0 {
     62 + builder.WriteString(", ")
     63 + }
     64 + 
     65 + builder.WriteString(base.ElementString(element))
     66 + }
     67 + 
     68 + builder.WriteString(").\n")
     69 + 
     70 + return writer.write(builder.String())
     71 +}
     72 + 
     73 +func (writer *Writer) write(value string) error {
     74 + _, err := writer.output.WriteString(value)
     75 + 
     76 + return err
     77 +}
     78 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/writer/relation/relation.go
     1 +package relationwriter
     2 + 
     3 +import (
     4 + "github.com/bearer/bearer/pkg/souffle/binding"
     5 + "github.com/bearer/bearer/pkg/util/souffle/writer/base"
     6 +)
     7 + 
     8 +type Writer struct {
     9 + base.Base
     10 + program *binding.Program
     11 +}
     12 + 
     13 +func New(program *binding.Program) *Writer {
     14 + return &Writer{program: program}
     15 +}
     16 + 
     17 +func (writer *Writer) WriteFact(relationName string, elements ...base.Element) error {
     18 + relation, err := writer.program.Relation(relationName)
     19 + if err != nil {
     20 + return err
     21 + }
     22 + 
     23 + tuple := relation.NewTuple()
     24 + defer tuple.Close()
     25 + 
     26 + for _, element := range elements {
     27 + writer.writeElement(tuple, element)
     28 + }
     29 + 
     30 + relation.Insert(tuple)
     31 + 
     32 + return nil
     33 +}
     34 + 
     35 +func (writer *Writer) writeElement(tuple *binding.Tuple, element base.Element) {
     36 + switch value := element.(type) {
     37 + case base.Symbol:
     38 + tuple.WriteSymbol(string(value))
     39 + case base.Unsigned:
     40 + tuple.WriteUnsigned(uint32(value))
     41 + case base.Record:
     42 + tuple.WriteInteger(writer.packRecord(value))
     43 + default:
     44 + panic("unexpected element type")
     45 + }
     46 +}
     47 + 
     48 +func (writer *Writer) packRecord(record base.Record) int32 {
     49 + recordTuple := writer.program.NewRecordTuple(len(record))
     50 + defer recordTuple.Close()
     51 + 
     52 + for i, element := range record {
     53 + switch value := element.(type) {
     54 + case base.Symbol:
     55 + recordTuple.WriteSymbol(i, string(value))
     56 + case base.Unsigned:
     57 + recordTuple.WriteUnsigned(i, uint32(value))
     58 + case base.Record:
     59 + recordTuple.WriteInteger(i, writer.packRecord(record))
     60 + default:
     61 + panic("unexpected element type")
     62 + }
     63 + }
     64 + 
     65 + return writer.program.PackRecord(recordTuple)
     66 +}
     67 + 
  • ■ ■ ■ ■ ■ ■
    pkg/util/souffle/writer/writer.go
     1 +package writer
     2 + 
     3 +import "github.com/bearer/bearer/pkg/souffle/writer/base"
     4 + 
     5 +type FactWriter interface {
     6 + Symbol(value string) base.Symbol
     7 + Unsigned(value uint32) base.Unsigned
     8 + Record(elements ...base.Element) base.Record
     9 + WriteFact(relation string, elements ...base.Element) error
     10 +}
     11 + 
  • ■ ■ ■ ■ ■ ■
    souffle/ast.dl
     1 +.type AST_FileId <: number
     2 +.type AST_Filename <: symbol
     3 +.type AST_FilePosition <: number
     4 + 
     5 +.type AST_NodeId <: number
     6 +.type AST_Node = [file: AST_FileId, nodeId: AST_NodeId]
     7 + 
     8 +.type AST_Type <: symbol
     9 +.type AST_Field <: symbol
     10 +.type AST_Content <: symbol
     11 + 
     12 +.type AST_Location = [
     13 + startByte: AST_FilePosition,
     14 + startLine: AST_FilePosition,
     15 + startColumn: AST_FilePosition,
     16 + endLine: AST_FilePosition,
     17 + endColumn: AST_FilePosition
     18 +]
     19 + 
     20 +.decl AST_File(file: AST_FileId, filename: AST_Filename)
     21 +.input AST_File
     22 + 
     23 +.decl AST_NodeType(node: AST_Node, type: AST_Type)
     24 +.input AST_NodeType
     25 +.decl AST_NodeContent(node: AST_Node, content: AST_Content)
     26 +.input AST_NodeContent
     27 + 
     28 +.decl AST_NodeField(parent: AST_Node, child: AST_Node, field: AST_Field)
     29 +.input AST_NodeField
     30 +.decl AST_ParentChild(parent: AST_Node, index: unsigned, child: AST_Node)
     31 +.input AST_ParentChild
     32 + 
     33 +.decl AST_NodeLocation(node: AST_Node, location: AST_Location)
     34 +.input AST_NodeLocation
     35 + 
  • ■ ■ ■ ■ ■ ■
    souffle/rules.dl
     1 +#include "./ast.dl"
     2 + 
     3 +.type RuleName <: symbol
     4 + 
     5 +.decl Rule(rule: RuleName, node: AST_Node)
     6 + 
     7 +.decl RuleMatch(name: RuleName, location: AST_Location)
     8 +RuleMatch(name, location) :- Rule(name, node), AST_NodeLocation(node, location).
     9 +.output RuleMatch
     10 + 
     11 + 
     12 +#include "./generated/rules.dl"
     13 + 
Please wait...
Page is in error, reload to recover