Class: Ibex::IR::Validator::LexerDocument

Inherits:
Base
  • Object
show all
Defined in:
lib/ibex/ir/validator/lexer.rb,
sig/ibex/ir/validator/lexer.rbs

Overview

Structural validation for the independently versioned Lexer IR.

Constant Summary collapse

ROOT_REQUIRED =

Returns:

  • (Array[String])
%w[
  ibex_ir schema_version initial_state states rules warnings source_provenance
].freeze
RULE_REQUIRED =

Signature:

  • Array[String]

Returns:

  • (Array[String])
%w[
  id state kind token pattern pattern_kind options action loc
].freeze

Constants inherited from Base

Base::POSITION

Instance Method Summary collapse

Methods inherited from Base

#array, #boolean, #child_path, #enum, #field, #integer, #invalid, #literal, #location, #metadata, #nonempty_string, #nonnegative_integer, #nullable_string, #object, #positive_integer, #record, #string

Constructor Details

#initialize(data, path: "$") ⇒ LexerDocument

Returns a new instance of LexerDocument.

RBS:

  • (Hash[String, untyped] data, ?path: String) -> void

Parameters:

  • data (Hash[String, untyped])
  • path: (String) (defaults to: "$")


16
17
18
19
20
# File 'lib/ibex/ir/validator/lexer.rb', line 16

def initialize(data, path: "$")
  super()
  @data = data
  @path = path
end

Instance Method Details

#validateself

RBS:

  • () -> self

Returns:

  • (self)


23
24
25
26
27
28
29
30
31
32
33
# File 'lib/ibex/ir/validator/lexer.rb', line 23

def validate
  record(@data, @path, ROOT_REQUIRED)
  literal(@data["ibex_ir"], "#{@path}.ibex_ir", "lexer")
  literal(@data["schema_version"], "#{@path}.schema_version", LEXER_SCHEMA_VERSION)
  literal(@data["initial_state"], "#{@path}.initial_state", "INITIAL")
  validate_states
  validate_rules
  validate_warnings
  validate_source_provenance
  self
end

#validate_pattern(rule, path, options) ⇒ void

This method returns an undefined value.

RBS:

  • (Hash[String, untyped] rule, String path, String options) -> void

Parameters:

  • rule (Hash[String, untyped])
  • path (String)
  • options (String)


74
75
76
77
78
79
80
81
82
83
# File 'lib/ibex/ir/validator/lexer.rb', line 74

def validate_pattern(rule, path, options)
  flags = 0
  flags |= Regexp::IGNORECASE if options.include?("i")
  flags |= Regexp::MULTILINE if options.include?("m")
  flags |= Regexp::EXTENDED if options.include?("x")
  regexp = Regexp.new("\\A(?:#{rule.fetch('pattern')})", flags)
  invalid("#{path}.pattern", "must not match an empty string") if regexp.match?("")
rescue RegexpError => e
  invalid("#{path}.pattern", "is not a valid regular expression: #{e.message}")
end

#validate_rulesvoid

This method returns an undefined value.

RBS:

  • () -> void



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/ibex/ir/validator/lexer.rb', line 51

def validate_rules # rubocop:disable Metrics/AbcSize
  array(@data["rules"], "#{@path}.rules").each_with_index do |value, index|
    path = "#{@path}.rules[#{index}]"
    rule = record(value, path, RULE_REQUIRED)
    literal(rule["id"], "#{path}.id", index)
    state = nonempty_string(rule["state"], "#{path}.state")
    invalid("#{path}.state", "references missing state #{state.inspect}") unless @states[state]
    kind = enum(rule["kind"], "#{path}.kind", %w[token skip on])
    nullable_string(rule["token"], "#{path}.token")
    invalid("#{path}.token", "is required for token rules") if kind == "token" && rule["token"].nil?
    invalid("#{path}.token", "must be null for #{kind} rules") if kind != "token" && rule["token"]
    nonempty_string(rule["pattern"], "#{path}.pattern")
    enum(rule["pattern_kind"], "#{path}.pattern_kind", %w[regexp literal])
    options = string(rule["options"], "#{path}.options")
    invalid("#{path}.options", "may contain only i, m, and x") unless options.match?(/\A[imx]*\z/)
    validate_pattern(rule, path, options)
    nullable_string(rule["action"], "#{path}.action")
    invalid("#{path}.action", "is required for on rules") if kind == "on" && rule["action"].nil?
    location(rule["loc"], "#{path}.loc", nullable: false)
  end
end

#validate_source_provenancevoid

This method returns an undefined value.

RBS:

  • () -> void



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/ibex/ir/validator/lexer.rb', line 97

def validate_source_provenance
  value = @data["source_provenance"]
  return if value.nil?

  record(value, "#{@path}.source_provenance", %w[file root byte_span])
  nullable_string(value["file"], "#{@path}.source_provenance.file")
  nullable_string(value["root"], "#{@path}.source_provenance.root")
  return if value["byte_span"].nil?

  span = record(value["byte_span"], "#{@path}.source_provenance.byte_span", %w[start end])
  nonnegative_integer(span["start"], "#{@path}.source_provenance.byte_span.start")
  nonnegative_integer(span["end"], "#{@path}.source_provenance.byte_span.end")
end

#validate_statesvoid

This method returns an undefined value.

RBS:

  • () -> void



38
39
40
41
42
43
44
45
46
47
48
# File 'lib/ibex/ir/validator/lexer.rb', line 38

def validate_states
  seen = {} #: Hash[String, bool]
  values = array(@data["states"], "#{@path}.states")
  invalid("#{@path}.states", "must start with INITIAL") unless values.first == "INITIAL"
  values.each_with_index do |value, index|
    name = nonempty_string(value, "#{@path}.states[#{index}]")
    invalid("#{@path}.states[#{index}]", "duplicates state #{name.inspect}") if seen[name]
    seen[name] = true
  end
  @states = seen
end

#validate_warningsvoid

This method returns an undefined value.

RBS:

  • () -> void



86
87
88
89
90
91
92
93
94
# File 'lib/ibex/ir/validator/lexer.rb', line 86

def validate_warnings
  array(@data["warnings"], "#{@path}.warnings").each_with_index do |value, index|
    path = "#{@path}.warnings[#{index}]"
    warning = record(value, path, %w[type rule loc])
    literal(warning["type"], "#{path}.type", "redos")
    nonnegative_integer(warning["rule"], "#{path}.rule")
    location(warning["loc"], "#{path}.loc", nullable: false)
  end
end