Class: Pione::Lang::StructuralContext

Inherits:
Context
  • Object
show all
Defined in:
lib/pione/lang/context.rb

Overview

StructuralContext is a basic context for all contexts.

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Context

#eval!

Constructor Details

#initialize(*args) ⇒ StructuralContext

Initialize and validate the context.

Raises:

  • (ArgumentError)


37
38
39
40
41
# File 'lib/pione/lang/context.rb', line 37

def initialize(*args)
  super(*args)
  raise ArgumentError.new(args) unless elements
  validate(acceptances)
end

Class Method Details

.accept(elt) ⇒ Object

Trun the element to be accepted in the context.



18
19
20
21
22
23
24
25
# File 'lib/pione/lang/context.rb', line 18

def accept(elt)
  acceptances << elt

  # define the accessor by snakecase
  define_method(elt.to_s.snake_case) do
    elements.select{|e| e.kind_of?(elt)}
  end
end

.acceptancesObject

Return all accepted declaration types in the context.



13
14
15
# File 'lib/pione/lang/context.rb', line 13

def acceptances
  @acceptances ||= []
end

.inherited(subclass) ⇒ Object



27
28
29
30
# File 'lib/pione/lang/context.rb', line 27

def inherited(subclass)
  acceptances.each {|acceptance| subclass.accept acceptance}
  members.each {|member_name| subclass.member(member_name, default: default_values[member_name])}
end

Instance Method Details

#+(other) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/pione/lang/context.rb', line 101

def +(other)
  if self.class == other.class
    set(elements: elements + other.elements)
  else
    raise ContextError.new(other, self)
  end
end

#eval(env) ⇒ Object

Evaluete each element in the context. Pione permit declarations to be in arbitray order, so the strategy of evaluation is try and error.



62
63
64
# File 'lib/pione/lang/context.rb', line 62

def eval(env)
  try_to_eval(env, elements)
end

#posObject

Return the position of first element in the context.



95
96
97
98
99
# File 'lib/pione/lang/context.rb', line 95

def pos
  if elements.size > 0
    elements.first.pos
  end
end

#try_to_eval(env, elts) ⇒ Object

Make trial loop for evaluation.



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
# File 'lib/pione/lang/context.rb', line 67

def try_to_eval(env, elts)
  return if elts.empty?

  exception = nil
  next_elts = []

  # trial
  elts.each do |elt|
    begin
      elt.eval(env).tap {|res| next_elts << res if res.is_a?(Context)}
    rescue UnboundError => e
      exception = e
      next_elts << elt
    end
  end if elts

  # stop endless loop
  if elts == next_elts
    raise exception
  end

  # go next trial
  unless next_elts.empty?
    return try_to_eval(env, next_elts)
  end
end

#validate(acceptances) ⇒ Object

Validate that the element type is accepted or not. This validation applies same criteria to conditional branches recursively.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/pione/lang/context.rb', line 45

def validate(acceptances)
  elements.each do |elt|
    # check the type
    accepted = acceptances.any? {|type| type == :all or elt.kind_of?(type)}

    # raise a context error if the type is not accepted
    raise ContextError.new(elt, self) if not(accepted)

    # check for inner branches recursively
    if elt.kind_of?(ConditionalBranch)
      elt.validate(acceptances)
    end
  end
end