reject programs that use symbols that have not been defined or imported
[voodoo-lang.git] / lib / voodoo / compiler.rb
blob75bbf8f895933e39e3d495e59407f361ac263511
1 require 'voodoo/parser'
3 module Voodoo
4   # Voodoo compiler driver.
5   # The compiler driver reads input from a parser (see
6   # Voodoo::Parser), feeds it to a code generator (see
7   # Voodoo::CommonCodeGenerator), and writes the generated code.
8   #
9   # An example of its usage can be found on the main page for the
10   # Voodoo module.
11   class Compiler
12     class Error < StandardError
13       def initialize errors
14         @errors = errors
15       end
17       attr_reader :errors
19       def message
20         msg = ""
21         @errors.each {|e| msg << e.message << "\n"}
22         msg
23       end
24     end
26     # Initializes a compiler.
27     #
28     # Parameters:
29     # [parser] the parser to be used (see Voodoo::Parser)
30     # [code_generator] the code generator to be used
31     #                  (see Voodoo::CommonCodeGenerator)
32     # [output] an IO object. The generated code will be written to it
33     def initialize parser, code_generator, output
34       @parser = parser
35       @generator = code_generator
36       @output = output
37     end
39     # Performs the compilation.
40     def compile
41       section = :code
42       errors = []
43       while true
44         begin
45           statement = @parser.parse_top_level
47           break if statement == nil
48           next if statement.empty?
50           case statement[0]
51           when :section
52             section = statement[1]
53           else
54             @generator.add section, statement
55           end
57         rescue Parser::MultipleErrors => e
58           errors.concat e.errors
60         rescue Parser::ParseError => e
61           errors << e
62         end
64         if errors.length >= 100
65           # Too many errors, give up.
66           raise Error.new(errors)
67         end
68       end
70       undefined_symbols = @generator.undefined_symbols
71       unless undefined_symbols.empty?
72         msg = "The following symbols are used, but have not been defined" +
73           " or imported:\n" + undefined_symbols.to_a.sort!.join(" ")
74         errors << RuntimeError.new(msg)
75       end
77       if errors.empty?
78         @generator.write @output
79       else
80         raise Error.new(errors)
81       end
82     end
83   end
84 end