Class: Yadriggy::Checker

Inherits:
Object
  • Object
show all
Includes:
Yadriggy
Defined in:
lib/yadriggy/checker.rb

Overview

AST checker. It visits the AST nodes and does various checks like type checking.

Direct Known Subclasses

Yadriggy::C::CodeGen, PrettyPrinter, TypeChecker

Constant Summary

Constants included from Yadriggy

DynType, Undef, VERSION, Void

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Yadriggy

debug, debug=, define_syntax, reify

Constructor Details

#initializeChecker

Initializes the object.



78
79
80
81
82
83
84
85
# File 'lib/yadriggy/checker.rb', line 78

def initialize
  self.class.check_init_class
  @error = nil
  @check_list = []
  @current_ast = nil
  @current_env = nil
  @rule_declarator = nil
end

Class Method Details

.all_rulesArray<Hash>

Returns all the rules defined so far.

Returns:

  • (Array<Hash>)

    all the rules defined so far.



35
36
37
# File 'lib/yadriggy/checker.rb', line 35

def self.all_rules
  [@rules, @rule_declarators]
end

.check_init_classObject

Initializes this class if necessary.



29
30
31
# File 'lib/yadriggy/checker.rb', line 29

def self.check_init_class
  init_class if @rules.nil?
end

.find_rule_entry(ast) ⇒ Pair<Proc,Class>

internal-use only. Don’t call this.

Returns:

  • (Pair<Proc,Class>)

    a rule and the class declaring it, or nil.



55
56
57
# File 'lib/yadriggy/checker.rb', line 55

def self.find_rule_entry(ast)
  find_rule_entry2(ast.class, ast.usertype)
end

.rule(node_type) { ... } ⇒ void

This method returns an undefined value.

Defines the rule for a node type.

Parameters:

  • node_type (Class)

    the type of the AST node.

Yields:

  • The block is executed for the node with ‘node_type`.



21
22
23
24
25
# File 'lib/yadriggy/checker.rb', line 21

def self.rule(node_type, &proc)
  init_class if @rules.nil?
  @rules[node_type] = proc
  @rule_declarators[node_type] = self
end

Instance Method Details

#apply_typing_rule(rule, an_ast, ast_tenv) ⇒ Object

internal use only



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/yadriggy/checker.rb', line 141

def apply_typing_rule(rule, an_ast, ast_tenv)
  if rule.nil?
    error_found!(an_ast, "no typing rule for #{an_ast.class}")
  else
    old_ast = @current_ast
    old_tenv = @current_env
    old_declarator = @rule_declarator
    @current_ast = an_ast
    @current_env = ast_tenv unless ast_tenv.nil?
    @rule_declarator = rule[1]
    t = instance_exec(&rule[0])
    @rule_declarator = old_declarator
    @current_env = old_tenv
    @current_ast = old_ast
    return t
  end
end

#astASTnode

Returns the current abstract syntax tree.

Returns:

  • (ASTnode)

    the current abstract syntax tree.



177
178
179
# File 'lib/yadriggy/checker.rb', line 177

def ast
  @current_ast
end

#ast_envObject

Returns the current environment.

Returns:

  • (Object)

    the current environment.



182
183
184
# File 'lib/yadriggy/checker.rb', line 182

def ast_env
  @current_env
end

#check(an_ast, ast_env = nil) ⇒ Object

Applies rules to the given AST.

It assumes that ast is processed by Syntax and it has usertype method. An exception is thrown when the checking fails. ast may be nil.

The environment given to this method can be accessed in the rules through ast_env(). It is optional and can be any object. The initial one is made by make_base_env().

Returns:

  • (Object)


130
131
132
133
134
135
136
137
# File 'lib/yadriggy/checker.rb', line 130

def check(an_ast, ast_env=nil)
  if an_ast.nil?
    nil
  else
    rule = self.class.find_rule_entry(an_ast)
    apply_typing_rule(rule, an_ast, ast_env)
  end
end

#check_all(an_ast) ⇒ Object

Applies rules to the given AST. It returns the result of the rule-application or throws a CheckError. This is the entry point of the checker. It may also check the other ASTs invoked in the given AST.

Parameters:

Returns:

  • (Object)


101
102
103
104
105
106
107
108
109
110
111
# File 'lib/yadriggy/checker.rb', line 101

def check_all(an_ast)
  return nil if an_ast.nil?
  an_ast = an_ast.tree if an_ast.is_a?(ASTree)
  t = check(an_ast, make_base_env(an_ast.get_context_class))
  until (checked = @check_list.pop).nil?
    @current_ast = checked[0]
    @current_env = checked[1]
    checked[2].call
  end
  t
end

#check_later { ... } ⇒ void

This method returns an undefined value.

Later invokes the block, which performs checking. The method immediately returns. This is used for avoiding infinite regression during the checking.

Yields:

  • The block is later executed for checking.



191
192
193
194
195
# File 'lib/yadriggy/checker.rb', line 191

def check_later(&proc)
  cur_ast = @current_ast
  cur_env = @current_env
  @check_list << [cur_ast, cur_env, proc]
end

#errorString

returns nil.

Returns:

  • (String)

    an error message when the last invocation of check()



89
90
91
# File 'lib/yadriggy/checker.rb', line 89

def error
  @error || ''
end

#error_found!(an_ast, msg = '') ⇒ Object

Raises:



198
199
200
201
202
203
204
205
206
207
# File 'lib/yadriggy/checker.rb', line 198

def error_found!(an_ast, msg='')
  loc  = if an_ast.is_a?(ASTnode)
           an_ast.source_location_string
         else
           ''
         end
  @error = "#{loc} DSL #{error_group} error. #{msg}"
  binding.pry if Yadriggy.debug > 1
  raise CheckError.new(@error)
end

#error_groupObject



210
211
212
# File 'lib/yadriggy/checker.rb', line 210

def error_group
  ''
end

#make_base_env(klass) ⇒ Object

Makes a new base environment with the given context class.

Parameters:

  • klass (Module)

    the context class.



115
116
117
# File 'lib/yadriggy/checker.rb', line 115

def make_base_env(klass)
  klass
end

#proceed(an_ast, envi = nil) ⇒ Type

Applies the rule supplied by the superclass.

Parameters:

  • an_ast (ASTnode)

    an AST.

  • envi (Object) (defaults to: nil)

    an environment object.

Returns:

  • (Type)

    the type of the given AST.



163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/yadriggy/checker.rb', line 163

def proceed(an_ast, envi=nil)
  rule = if @rule_declarator&.superclass == Object
           nil
         else
           @rule_declarator&.superclass.find_rule_entry(an_ast)
         end
  if rule.nil?
    error_found!(an_ast, 'no more rule. we cannot proceed')
  else
    apply_typing_rule(rule, an_ast, envi)
  end
end