Class: Karel::SyntaxChecker

Inherits:
Object
  • Object
show all
Defined in:
lib/karel/syntax_checker.rb

Overview

A very basic and very hacky syntax checker. This won’t ensure the program runs and is pretty lame overall, but it more or less gets the job done

Instance Method Summary collapse

Constructor Details

#initializeSyntaxChecker

Returns a new instance of SyntaxChecker.



7
8
9
10
11
12
13
# File 'lib/karel/syntax_checker.rb', line 7

def initialize
  @builtins = []
  Commands.public_instance_methods.each do |method|
    @builtins << method if method =~ /^[A-Z_]*$/
  end
  @control = [ 'WHILE', 'IF', 'ELSE', 'ITERATE' ]
end

Instance Method Details

#errorsObject



84
# File 'lib/karel/syntax_checker.rb', line 84

def errors; @errors; end

#valid?(code) ⇒ Boolean

Returns:

  • (Boolean)


15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
74
75
76
77
78
79
80
81
82
# File 'lib/karel/syntax_checker.rb', line 15

def valid?(code)
  line_number = 1
  @errors = {}
  in_world = false
  defines = []
  code.split(/\n/).each do |line|
    line_number += 1
    trimmed = line.strip.gsub(/\(\)/,'').strip
    if in_world
      if trimmed =~ /^END\s*$/
        in_world = false
      else
        if trimmed =~ /^[ KWB]*$/
          # ok
        else
          @errors[line_number] = "Bad world definition: #{trimmed}"
        end
      end
    elsif (trimmed =~ /^WORLD\s+<<END$/)
      in_world = true
    else
      next if trimmed =~/^\s*$/
      next if trimmed =~/^\s*#.*$/
      if trimmed =~ /^DEFINE\s*\(\s*["'](.[^"']*)["']\s*\)\s*\{\s*$/
        define = $1
        if define =~ /^[A-Z_]*$/
          defines << define
        else
          @errors[line_number] = "Bad DEFINE symbol #{define}"
        end
      else
        to_the_bone = trimmed.gsub(/[^A-Z_].*$/,'')
        if @control.include? to_the_bone
          if trimmed =~ /^#{to_the_bone}\s*\((.*)\)\s*\{\s*$/
            condition = $1
            if to_the_bone == 'ITERATE'
              if condition =~ /^\s*[0-9]\.TIMES\s*$/
                # ok
              else
                @errors[line_number] = "Bad #{to_the_bone} condition: #{condition}"
              end
            else
              if (trimmed =~ /^ELSE/) 
                @errors[line_number] = "Bad #{to_the_bone} statement: #{trimmed}"
              end
              if condition =~ /^[a-z_]+$/
                # ok
              else
                @errors[line_number] = "Bad #{to_the_bone} condition: #{condition}"
              end
            end
          else
            if trimmed =~ /^ELSE\s*\{\s*$/
              # ok
            else
              @errors[line_number] = "Bad #{to_the_bone} statement: #{trimmed}"
            end
          end
        elsif trimmed =~ /^\s*\}\s*$/
          # ignore
        else
          @errors[line_number] = "Unknown symbol #{trimmed}" unless (@builtins.include? trimmed) || (defines.include? trimmed)
        end
      end
    end
  end
  @errors.empty?
end