Class: Ibex::Runtime::CST::NodeCache

Inherits:
Object
  • Object
show all
Defined in:
lib/ibex/runtime/cst/green/cache.rb

Overview

Session-owned hash-consing cache for immutable Green elements.

Constant Summary collapse

DEFAULT_NODE_ARITY_LIMIT =

: Integer

3
DEFAULT_NODE_DESCENDANT_LIMIT =

: Integer

32
EMPTY_TRIVIA =

: Array

empty_trivia.freeze

Instance Method Summary collapse

Constructor Details

#initialize(enabled: true, node_arity_limit: DEFAULT_NODE_ARITY_LIMIT, node_descendant_limit: DEFAULT_NODE_DESCENDANT_LIMIT) ⇒ NodeCache

Returns a new instance of NodeCache.

Raises:

  • (ArgumentError)


24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/ibex/runtime/cst/green/cache.rb', line 24

def initialize(
  enabled: true, node_arity_limit: DEFAULT_NODE_ARITY_LIMIT,
  node_descendant_limit: DEFAULT_NODE_DESCENDANT_LIMIT
)
  raise ArgumentError, "node_arity_limit must be non-negative" if node_arity_limit.negative?
  raise ArgumentError, "node_descendant_limit must be positive" unless node_descendant_limit.positive?

  @enabled = enabled
  @node_arity_limit = node_arity_limit
  @node_descendant_limit = node_descendant_limit
  @trivia = {}
  @tokens = {}
  @nodes = {}
end

Instance Method Details

#clearObject



119
120
121
122
123
# File 'lib/ibex/runtime/cst/green/cache.rb', line 119

def clear
  @trivia.clear
  @tokens.clear
  @nodes.clear
end

#intern_node(node) ⇒ Object



109
110
111
112
113
114
115
116
# File 'lib/ibex/runtime/cst/green/cache.rb', line 109

def intern_node(node)
  return node unless @enabled
  return node if node.children.length > @node_arity_limit
  return node if node.descendant_count > @node_descendant_limit
  return node unless node.flags.nobits?(Flags::HAS_ANNOTATION)

  @nodes[node] ||= node
end

#intern_token(token) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/ibex/runtime/cst/green/cache.rb', line 60

def intern_token(token)
  return token unless @enabled
  return token unless token.flags.nobits?(Flags::HAS_ANNOTATION)

  signature = token_signature(
    token.kind, token.text, token.leading, token.trailing, token.flags, token.expected_kind
  )
  bucket = @tokens[signature]
  existing = find_token(
    bucket, token.kind, token.text, token.leading, token.trailing, token.flags, token.expected_kind
  )
  return existing if existing

  (@tokens[signature] ||= []) << token
  token
end

#intern_token_fields(kind:, text:, leading: EMPTY_TRIVIA, trailing: EMPTY_TRIVIA, flags: 0, expected_kind: nil) ⇒ Object

Intern a token before constructing it, avoiding discarded duplicate immutable values.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/ibex/runtime/cst/green/cache.rb', line 80

def intern_token_fields(
  kind:, text:, leading: EMPTY_TRIVIA, trailing: EMPTY_TRIVIA, flags: 0, expected_kind: nil
)
  unless @enabled && flags.nobits?(Flags::HAS_ANNOTATION)
    return GreenToken.new(
      kind: kind, text: text, leading: leading, trailing: trailing,
      flags: flags, expected_kind: expected_kind
    )
  end

  comparable_text = if text.encoding == Encoding::BINARY || text.ascii_only?
                      text
                    else
                      text.b.freeze
                    end
  signature = token_signature(kind, comparable_text, leading, trailing, flags, expected_kind)
  bucket = @tokens[signature]
  existing = find_token(bucket, kind, comparable_text, leading, trailing, flags, expected_kind)
  return existing if existing

  token = GreenToken.new(
    kind: kind, text: comparable_text, leading: leading, trailing: trailing,
    flags: flags, expected_kind: expected_kind
  )
  (@tokens[signature] ||= []) << token
  token
end

#intern_trivia_fields(kind:, text:) ⇒ Object

Intern trivia before constructing it, using byte-equivalent text within this session.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/ibex/runtime/cst/green/cache.rb', line 41

def intern_trivia_fields(kind:, text:)
  return GreenTrivia.new(kind: kind, text: text) unless @enabled

  comparable_text = if text.encoding == Encoding::BINARY || text.ascii_only?
                      text
                    else
                      text.b.freeze
                    end
  signature = kind.hash ^ comparable_text.hash
  bucket = @trivia[signature]
  existing = bucket&.find { |trivia| trivia.kind == kind && trivia.text == comparable_text }
  return existing if existing

  trivia = GreenTrivia.new(kind: kind, text: comparable_text)
  (@trivia[signature] ||= []) << trivia
  trivia
end