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