Module: Taipo::Parser

Defined in:
lib/taipo/parser.rb,
lib/taipo/parser/stack.rb,
lib/taipo/parser/validater.rb,
lib/taipo/parser/syntax_state.rb

Overview

A parser of Taipo type definitions

Since:

  • 1.0.0

Defined Under Namespace

Modules: Validater Classes: Stack, SyntaxState

Class Method Summary collapse

Class Method Details

.escape?(c, states) ⇒ Boolean, Hash<Symbol,Boolean>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check whether the character should be skipped

This method determines whether a particular character c should be skipped based on states. It also updates states.

Parameters:

  • c (String)

    the character to check

  • states (Hash<Symbol,Boolean>)

    a state machine

Returns:

  • (Boolean, Hash<Symbol,Boolean>)

    the result and the updated state machine

Since:

  • 1.4.0



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/taipo/parser.rb', line 88

def self.escape?(c, states)
  if states[:esc]
    states[:esc] = false
    return skip, states
  end

  skip = true

  case c
  when "'"
    states[:ss] = !states[:ss] unless states[:re] || states[:ds]
  when '"'
    states[:ds] = !states[:ds] unless states[:re] || states[:ss]
  when '/'
    states[:re] = !states[:re] unless states[:ss] || states[:ds]
  when '\\'
    states[:esc] = true
  else
    skip = false
  end

 return skip, states
end

.parse(str) ⇒ Taipo:TypeElements

Return a Taipo::TypeElements object based on str

Parameters:

  • str (String)

    a type definition

Returns:

  • (Taipo:TypeElements)

    the result

Raises:

  • (::TypeError)

    if str is not a String

  • (Taipo::SyntaxError)

    if str is not a valid type definition

Since:

  • 1.0.0



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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/taipo/parser.rb', line 30

def self.parse(str)
  Taipo::Parser::Validater.validate str

  stack = Taipo::Parser::Stack.new
  i = 0
  subject = :implied
  chars = str.chars
  content = ''

  while (i < chars.size)
    reset = true

    case chars[i]
    when ' '
      i += 1
      next
    when '|'
      stack = process_sum stack, name: content
      subject = :implied
    when '<'
      stack = process_collection :open, stack, name: content
      subject = :implied
    when '>'
      stack = process_collection :close, stack, name: content
      subject = :made
    when ','
      stack = process_component stack, name: content
      subject = :implied
    when '('
      stack = process_subject stack, name: content, subject: subject
      stack, i = process_constraints stack, chars: chars, index: i+1
    else
      reset = false
      subject = :unmade
    end

    content = (reset) ? '' : content + chars[i]
    i += 1
  end

  stack = process_end stack, name: content

  stack.result
end

.parse_constraint(str) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Note:

If the constraint is in the form of an instance method (eg. #foo) this method uses TypeElement::Constraint::METHOD as the name returned.

Parse the constraint expressed as a string

Parameters:

  • str (String)

    the constraint expressed as a string

Returns:

  • (String, String)

    the name and the value

Since:

  • 1.4.0



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/taipo/parser.rb', line 124

def self.parse_constraint(str)
  str.strip!
  in_name = nil
  name = ''
  content = ''
  str.each_char do |c|
    if c == '#' && in_name.nil?
      name = Taipo::TypeElement::Constraint::METHOD
      in_name = false
    elsif c == ':' && in_name.nil?
      name = 'val'
      content = content + c
      in_name = false
    elsif c == ':' && in_name
      name = content
      content = ''
      in_name = false
    else
      content = content + c
      in_name = true if in_name.nil?
    end
  end
  value = content.strip
  return name, value
end

.process_collection(direction, stack, name:) ⇒ Taipo::Parser::Stack

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Process a collection

This method either adds or updates a collection on stack depending on direction. If direction is :open, this adds a TypeElement to stack representing the class of the collection. If direction is :close, this adds a TypeElement to stack representing the class of the final component of the collection.

Parameters:

  • direction (Symbol)

    Either :open or :close depending on whether this has been called because the parser reached a < character or a > character

  • stack (Taipo::Parser::Stack)

    the stack

  • name (String)

    the name of the class of the TypeElement to add to stack

Returns:

Since:

  • 1.4.0



169
170
171
172
173
174
175
176
177
178
179
# File 'lib/taipo/parser.rb', line 169

def self.process_collection(direction, stack, name:)
  case direction
  when :open
    stack = process_name stack, name: name
    stack.add_children
  when :close
    stack = process_name stack, name: name unless name.empty?
    children = stack.remove_children
    stack.update_element :children=, children
  end
end

.process_component(stack, name:) ⇒ Taipo::Parser::Stack

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Process a component

This method adds a TypeElement to stack representing a component of a collection.

Parameters:

Returns:

Since:

  • 1.4.0



194
195
196
197
# File 'lib/taipo/parser.rb', line 194

def self.process_component(stack, name:)
  stack = process_name stack, name: name
  stack.add_child
end

.process_constraint(stack, raw:) ⇒ Taipo::Parser::Stack

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Process a constraint

This method adds a TypeElement::Constraint to the last element in stack.

Parameters:

Returns:

Since:

  • 1.4.0



211
212
213
214
# File 'lib/taipo/parser.rb', line 211

def self.process_constraint(stack, raw:)
  n, v = parse_constraint raw
  stack.add_constraint Taipo::TypeElement::Constraint.new(name: n, value: v)
end

.process_constraints(stack, chars:, index:) ⇒ Taipo::Parser::Stack, Integer

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Process a series of constraints

This method adds a TypeElement::Constraints to the last element in stack. Because it parses chars, it also returns an updated index.

Parameters:

  • stack (Taipo::Parser::Stack)

    the stack

  • chars (Array<String>)

    a character array

  • index (Integer)

    the index of chars at which to begin parsing

Returns:

Since:

  • 1.4.0



230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/taipo/parser.rb', line 230

def self.process_constraints(stack, chars:, index:)
  stack.add_constraints

  inside = { ss: false, ds: false, re: false, esc: false }
  content = ''

  while (index < chars.size)
    skip, inside = escape?(chars[index], inside)
    if skip
      content = content + chars[index]
      index += 1
      next
    end

    case chars[index]
    when ')'
      stack = process_constraint stack, raw: content
      break
    when ','
      stack = process_constraint stack, raw: content
      content = ''
    else
      content = content + chars[index]
    end

    index += 1
  end

  constraints = stack.remove_constraints
  stack.update_element :constraints=, constraints

  return stack, index
end

.process_end(stack, name:) ⇒ Taipo::Parser::Stack

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Process the end of the type definition

The design of parse means that at the end of the loop, an element may remain to be added. This method add any remaining element to stack.

Parameters:

Returns:

Since:

  • 1.4.0



278
279
280
281
282
# File 'lib/taipo/parser.rb', line 278

def self.process_end(stack, name:)
  return stack if name.empty?

  process_name stack, name: name
end

.process_name(stack, name:) ⇒ Taipo::Parser::Stack

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Note:

Taipo allows certain bare constraints to be written in type definitions. If name is a bare constraint (either an instance method or a symbol), this method adds a TypeElement representing the Object class with the relevant constraint.

Process the name of a TypeElement

This method adds a TypeElement to stack with the name name.

Parameters:

Returns:

Since:

  • 1.4.0



301
302
303
304
305
306
307
308
309
310
# File 'lib/taipo/parser.rb', line 301

def self.process_name(stack, name:)
  if name.bare_constraint?
    chars = "(#{name})".chars
    stack = process_subject stack, name: '', subject: :implied
    stack, i = process_constraints stack, chars: chars, index: 1
    stack
  else
    stack.add_element name: name
  end
end

.process_subject(stack, name:, subject:) ⇒ Taipo::Parser::Stack

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Process the subject of a series of constraints

Taipo allows for a type definition to specify a series of constraints that constrain the particular type (the subject). This method adds a TypeElement to stack depending on the value of subject.

Parameters:

  • stack (Taipo::Parser::Stack)

    the stack

  • name (String)

    the name of the class of the TypeElement to add to stack

  • subject (Symbol)

    whether the subject is :made, :unmade or :implied

Returns:

Since:

  • 1.4.0



327
328
329
330
331
332
333
334
335
336
# File 'lib/taipo/parser.rb', line 327

def self.process_subject(stack, name:, subject:)
  case subject
  when :made
    stack
  when :unmade
    process_name stack, name: name
  when :implied
    process_name stack, name: 'Object'
  end
end

.process_sum(stack, name:) ⇒ Taipo::Parser::Stack

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Process a sum of types

This method adds a TypeElement to stack representing the former of the types in the sum.

Parameters:

Returns:

Since:

  • 1.4.0



351
352
353
354
355
# File 'lib/taipo/parser.rb', line 351

def self.process_sum(stack, name:)
  return stack if name.empty?

  process_name stack, name: name
end