reject programs that use symbols that have not been defined or imported
[voodoo-lang.git] / lib / voodoo / generators / dummy_generator.rb
blobc2516761ff6f4f4e55a68d5b79f7c93af491df2d
1 require 'set'
2 require 'voodoo/symbol_tracker'
4 module Voodoo
5   # Generator that does not generate code.
6   class DummyGenerator
7     def initialize *params
8       @locals = Set.new
9       @symbol_tracker = SymbolTracker.new
10     end
12     def add section, *code
13       analyze code
14     end
16     # Returns a set of symbols that have been used, but not defined.
17     def undefined_symbols
18       @symbol_tracker.used_but_undefined_symbols
19     end
21     def write *args
22     end
24     private
26     def analyze statements
27       statements.each { |code| analyze_statement code }
28     end
30     def analyze_statement code
31       case code[0]
32       when :block
33         old_locals = @locals
34         @locals = Set.new @locals
35         begin
36           analyze code[1..-1]
37         ensure
38           @locals = old_locals
39         end
40       when :export
41         use *code[1..-1]
42       when :function
43         old_locals = @locals
44         @locals = Set.new @locals
45         @locals.merge code[1]
46         begin
47           analyze code[2..-1]
48         ensure
49           @locals = old_locals
50         end
51       when :import
52         define *code[1..-1]
53       when :label
54         define code[1]
55       when :let
56         define code[1]
57         analyze_expr code[2..-1]
58       when :return
59         analyze_expr code[1..-1]
60       when :set
61         analyze_values [code[1]]
62         analyze_expr code[2..-1]
63       else
64         if code[0].to_s[0...2] == "if"
65           analyze_values code[1]
66           analyze code[2]
67           analyze code[3] if code.length > 3
68         else
69           analyze_values code[1..-1]
70         end
71       end
72     end
74     def analyze_expr code
75       if code.length == 1
76         analyze_values code
77       else
78         analyze_values code[1..-1]
79       end
80     end
82     def analyze_values values
83       values.each do |x|
84         if x.kind_of? Symbol
85           use x
86         elsif x.respond_to?(:[]) && x[0] == :'@'
87           analyze_values x[1]
88         end
89       end
90     end
92     def define *symbols
93       @symbol_tracker.define *symbols
94     end
96     def use *symbols
97       syms = Set.new symbols
98       nonlocals = syms - @locals
99       @symbol_tracker.use *nonlocals
100     end
101   end