Module: Puppet::Pops::Parser::EppSupport

Included in:
Lexer2
Defined in:
lib/puppet/pops/parser/epp_support.rb

Defined Under Namespace

Classes: EppScanner

Constant Summary collapse

TOKEN_RENDER_STRING =
[:RENDER_STRING, nil, 0]
TOKEN_RENDER_EXPR =
[:RENDER_EXPR, nil, 0]

Instance Method Summary collapse

Instance Method Details

#fullscan_eppObject

Scans all of the content and returns it in an array Note that the terminating [false, false] token is included in the result.


15
16
17
18
19
# File 'lib/puppet/pops/parser/epp_support.rb', line 15

def fullscan_epp
  result = []
  scan_epp {|token, value| result.push([token, value]) }
  result
end

#interpolate_epp(skip_leading = false) ⇒ Object


60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
107
108
# File 'lib/puppet/pops/parser/epp_support.rb', line 60

def interpolate_epp(skip_leading=false)
  scn = @scanner
  ctx = @lexing_context
  eppscanner = EppScanner.new(scn)
  before = scn.pos

  s = eppscanner.scan(skip_leading)

  case eppscanner.mode
  when :text
    # Should be at end of scan, or something is terribly wrong
    unless @scanner.eos?
      lex_error(Issues::EPP_INTERNAL_ERROR, :error => 'template scanner returns text mode and is not and end of input')
    end
    if s
      # s may be nil if scanned text ends with an epp tag (i.e. no trailing text).
      enqueue_completed([:RENDER_STRING, s, scn.pos - before], before)
    end
    ctx[:epp_open_position] = nil
    # do nothing else, scanner is at the end

  when :error
    lex_error(eppscanner.issue)

  when :epp
    # It is meaningless to render empty string segments, and it is harmful to do this at
    # the start of the scan as it prevents specification of parameters with <%- ($x, $y) -%>
    #
    if s && s.length > 0
      enqueue_completed([:RENDER_STRING, s, scn.pos - before], before)
    end
    # switch epp_mode to general (embedded) pp logic (non rendered result)
    ctx[:epp_mode] = :epp
    ctx[:epp_open_position] = scn.pos

  when :expr
    # It is meaningless to render an empty string segment
    if s && s.length > 0
      enqueue_completed([:RENDER_STRING, s, scn.pos - before], before)
    end
    enqueue_completed(TOKEN_RENDER_EXPR, before)
    # switch mode to "epp expr interpolation"
    ctx[:epp_mode] = :expr
    ctx[:epp_open_position] = scn.pos
  else
    lex_error(Issues::EPP_INTERNAL_ERROR, :error => "Unknown mode #{eppscanner.mode} returned by template scanner")
  end
  nil
end

#scan_epp {|[false, false]| ... } ⇒ Object

A block must be passed to scan. It will be called with two arguments, a symbol for the token, and an instance of LexerSupport::TokenValue PERFORMANCE NOTE: The TokenValue is designed to reduce the amount of garbage / temporary data and to only convert the lexer's internal tokens on demand. It is slightly more costly to create an instance of a class defined in Ruby than an Array or Hash, but the gain is much bigger since transformation logic is avoided for many of its members (most are never used (e.g. line/pos information which is only of value in general for error messages, and for some expressions (which the lexer does not know about).

Yields:

  • ([false, false])

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/puppet/pops/parser/epp_support.rb', line 29

def scan_epp
  # PERFORMANCE note: it is faster to access local variables than instance variables.
  # This makes a small but notable difference since instance member access is avoided for
  # every token in the lexed content.
  #
  scn   = @scanner
  ctx   = @lexing_context
  queue = @token_queue

  lex_error(Issues::EPP_INTERNAL_ERROR, :error => 'No string or file given to lexer to process.') unless scn

  ctx[:epp_mode] = :text
  enqueue_completed([:EPP_START, nil, 0], 0)

  interpolate_epp

  # This is the lexer's main loop
  until queue.empty? && scn.eos? do
    token = queue.shift || lex_token
    if token
      yield [ ctx[:after] = token[0], token[1] ]
    end
  end
  if ctx[:epp_open_position]
    lex_error(Issues::EPP_UNBALANCED_TAG, {}, ctx[:epp_position])
  end

  # Signals end of input
  yield [false, false]
end