Class: MPS::Engines::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/mps/engines/mps.rb

Defined Under Namespace

Classes: Unknown

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Parser

Returns a new instance of Parser.



15
16
17
18
19
20
21
22
23
24
# File 'lib/mps/engines/mps.rb', line 15

def initialize(config)
  @config = config
  @element_classes = ::MPS::Elements.constants
    .map    { |k| ::MPS::Elements.const_get(k) }
    .select { |x| x.class == Class }
  @interpolator_classes = ::MPS::Interpolators.constants
    .map    { |k| ::MPS::Interpolators.const_get(k) }
    .select { |x| x.class == Class }
  @logger = @config.logger
end

Instance Attribute Details

#element_classesObject (readonly)

Returns the value of attribute element_classes.



12
13
14
# File 'lib/mps/engines/mps.rb', line 12

def element_classes
  @element_classes
end

#interpolator_classesObject (readonly)

Returns the value of attribute interpolator_classes.



13
14
15
# File 'lib/mps/engines/mps.rb', line 13

def interpolator_classes
  @interpolator_classes
end

#loggerObject (readonly)

Returns the value of attribute logger.



11
12
13
# File 'lib/mps/engines/mps.rb', line 11

def logger
  @logger
end

Class Method Details

.look_ahead_pos(str_scanner, regex_la) ⇒ Object

Peeks ahead in str_scanner for regex_la without consuming input. Returns the position of the match, or string size if no match.



33
34
35
36
37
38
# File 'lib/mps/engines/mps.rb', line 33

def self.look_ahead_pos(str_scanner, regex_la)
  return str_scanner.string.size unless str_scanner.scan_until(regex_la)
  pos = str_scanner.pos
  str_scanner.unscan
  pos
end

.matched_element_class(str, element_classes) ⇒ Object

Returns the element class whose SIGNATURE_REGEX matches str, or nil.



27
28
29
# File 'lib/mps/engines/mps.rb', line 27

def self.matched_element_class(str, element_classes)
  element_classes.find { |ec| str =~ ec::SIGNATURE_REGEX }
end

.parse_mps_file_to_elements_hash(mps_file_path, element_classes) ⇒ Object Also known as: parse_mps_file_to_elments_hash

Parses mps_file_path into a flat hash of ref-path => element instances.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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
# File 'lib/mps/engines/mps.rb', line 41

def self.parse_mps_file_to_elements_hash(mps_file_path, element_classes)
  content  = File.read(mps_file_path)
  wrapped  = "@#{::MPS::Elements::MPS::SIGNATURE_STAMP}[]{\n#{content}\n}"
  base_ref = ::MPS::Constants::MPS_FILE_NAME_CLIPPER
               .call(File.basename(mps_file_path)).to_i

  open_re  = ::MPS::Constants::AT_REGEXP
  close_re = ::MPS::Constants::END_CURLY_REGEXP

  elements = {}
  stack    = []
  pos      = 0

  while pos < wrapped.size
    open_m  = open_re.match(wrapped, pos)
    close_m = close_re.match(wrapped, pos)

    break if open_m.nil? && close_m.nil?

    use_open = open_m && (close_m.nil? || open_m.begin(0) < close_m.begin(0))

    if use_open
      ref_path = if stack.empty?
        [base_ref]
      else
        parent = stack.last
        parent[:child_counter] += 1
        parent[:ref_path] + [parent[:child_counter]]
      end

      stack.push(
        sign:          open_m[:element_sign],
        args:          open_m[:args],
        body_start:    open_m.end(0),
        child_counter: 0,
        ref_path:      ref_path
      )
      pos = open_m.end(0)
    else
      break if stack.empty?

      frame    = stack.pop
      body_str = wrapped[frame[:body_start]...close_m.begin(0)]
      ref_key  = frame[:ref_path].join(".")
      ec       = matched_element_class(frame[:sign], element_classes)

      elements[ref_key] = if ec
        ec.new(args: frame[:args], refs: frame[:ref_path], body_str: body_str)
      else
        Unknown.new(frame[:sign], frame[:args], frame[:ref_path], body_str)
      end

      pos = close_m.end(0)
    end
  end

  elements
end