class Compiler

Attributes

errors[R]
runtime[R]

Public Class Methods

new() click to toggle source
# File lib/compiler.rb, line 20
def initialize
        @errors = []
        @message_base_id = 0
        @message_id = 0
end

Public Instance Methods

add_error(error) click to toggle source
# File lib/compiler.rb, line 283
def add_error error
        @errors.push error
end
check_case(type, initial_case, ast) click to toggle source
# File lib/compiler.rb, line 255
def check_case type, initial_case, ast
        if type == 'node_nick' and initial_case != ast.nickname[0].char_case
                add_error InitialCaseError.new type, initial_case, ast
        elsif initial_case != ast.name[0].char_case
                add_error InitialCaseError.new type, initial_case, ast
        end
end
check_type_nodes(member_type_ast, member_type_def) click to toggle source
# File lib/compiler.rb, line 228
def check_type_nodes member_type_ast, member_type_def
        return if @runtime == member_type_def.runtime

        @runtime.nodes.each do |n|
                external_node = member_type_def.runtime.nodes.find { |node| n.name == node.name }
                if external_node == nil
                        add_error CorrespondingNodeNotFoundError.new member_type_def, n.name
                        return
                end

                if external_node.language != n.language
                        add_error NodeLanguageMismatchError.new member_type_def, n, external_node
                        return
                end
        end
end
check_type_param_count(ast, expected_count) click to toggle source
# File lib/compiler.rb, line 279
def check_type_param_count ast, expected_count
        add_error TypeParamCountMismatchError.new ast, expected_count if ast.params.length != expected_count
end
check_type_unique(ast) click to toggle source
# File lib/compiler.rb, line 263
def check_type_unique ast
        type_def, _ = self.get_type ast, false
        return if type_def == nil

        if type_def.is_a? BuiltinTypeDef
                add_error BuiltinNameConflictError.new ast
        else
                self.check_unique 'type', type_def, ast
        end
end
check_unique(type, old_def, new_ast) click to toggle source
# File lib/compiler.rb, line 274
def check_unique type, old_def, new_ast
        return if old_def == nil
        add_error DuplicateDefError.new type, old_def.name, old_def.ast, new_ast
end
compile(filename, read_version) click to toggle source
# File lib/compiler.rb, line 26
def compile filename, read_version
        content = File.read filename, encoding: 'utf-8'
        tokens = Lexer::lex content, filename
        begin
                ast = Parser::parse tokens
        rescue RLTK::NotInLanguage => e
                add_error UnexpectedTokenError.new e.current
                return
        end
        @runtime = Runtime.new filename if @runtime == nil
        self.compile_ast @runtime, ast, read_version
end
compile_ast(runtime, ast, read_version) click to toggle source
# File lib/compiler.rb, line 39
def compile_ast runtime, ast, read_version
        @runtime = runtime
        @runtime.version = ast.version if read_version
        ast.decls.each do |decl|
                begin
                        case decl
                        when IncludeDecl
                                compile_include decl
                        when EnumDecl
                                compile_enum decl
                        when NodeDecl
                                compile_node decl
                        when StructDecl
                                compile_struct decl
                        when DirectionDecl
                                compile_direction decl
                        when SequenceDecl
                                compile_sequence decl
                        end
                rescue CompilerError => e
                        @errors.push e
                end
        end
end
compile_direction(direction_ast) click to toggle source
# File lib/compiler.rb, line 111
def compile_direction direction_ast
        client = @runtime.nodes[direction_ast.client]
        if client == nil
                add_error NodeNotFoundError.new direction_ast, direction_ast.client
                return
        end

        server = @runtime.nodes[direction_ast.server]
        if server == nil
                add_error NodeNotFoundError.new direction_ast, direction_ast.server
                return
        end

        if client == server
                add_error ClientServerSameError.new direction_ast
                return
        end

        @message_base_id += 1000
        @message_id = 0

        direction_def = @runtime.get_direction client, direction_ast.direction, server
        if direction_def == nil
                direction_def = DirectionDef.new direction_ast, client, server
        end

        direction_ast.messages.each do |message_ast|
                self.check_case 'message', :upper, message_ast
                self.check_unique 'message', direction_def.messages[message_ast.name], message_ast
                direction_def.add_message self.compile_message direction_def, message_ast
        end
        @runtime.add_direction direction_def
end
compile_enum(enum_ast) click to toggle source
# File lib/compiler.rb, line 75
def compile_enum enum_ast
        self.check_case 'enum', :upper, enum_ast
        self.check_type_unique enum_ast
        enum_def = EnumTypeDef.new enum_ast
        enum_ast.elements.each do |element_ast|
                self.check_case 'enum element', :upper, element_ast
                self.check_unique 'enum element', enum_def.elements[element_ast.name], element_ast
                element_def = EnumElementDef.new element_ast
                enum_def.add_element element_def
        end
        @runtime.add_enum enum_def
end
compile_include(include_ast) click to toggle source
# File lib/compiler.rb, line 64
def compile_include include_ast
        dir = File.dirname @runtime.filename
        filename = include_ast.filename + '.brotorift'
        full_path = File.join dir, filename
        if not File.exists? full_path
                add_error IncludeFileNotFoundError.new filename, include_ast.position
                return
        end
        self.compile full_path, false
end
compile_message(direction_def, message_ast) click to toggle source
# File lib/compiler.rb, line 145
def compile_message direction_def, message_ast
        @message_id += 1
        message_def = MessageDef.new message_ast, @message_base_id + @message_id
        message_ast.members.each do |member_ast|
                self.check_case 'message member', :lower, member_ast
                self.check_unique 'message member', message_def.get_member(member_ast.name), member_ast

                nodes_to_check = [direction_def.client, direction_def.server]
                member_type_def = self.get_member_type nodes_to_check, member_ast.type
                member_def = MemberDef.new member_ast, member_type_def
                message_def.add_member member_def
        end
        message_def
end
compile_node(node_ast) click to toggle source
# File lib/compiler.rb, line 88
def compile_node node_ast
        self.check_case 'node', :upper, node_ast
        self.check_case 'node_nick', :upper, node_ast
        self.check_unique 'node', @runtime.nodes[node_ast.name], node_ast
        self.check_unique 'node', @runtime.nodes[node_ast.nickname], node_ast
        node_def = NodeDef.new node_ast
        @runtime.add_node node_def
end
compile_sequence(sequence_ast) click to toggle source
# File lib/compiler.rb, line 160
def compile_sequence sequence_ast
        self.check_case 'sequence', :upper, sequence_ast
        self.check_unique 'sequence', @runtime.get_sequence(sequence_ast.name), sequence_ast
        sequence_def = SequenceDef.new sequence_ast
        sequence_ast.steps.each do |step_ast|
                sequence_def.add_step self.compile_step step_ast
        end
        @runtime.add_sequence sequence_def
end
compile_step(step_ast) click to toggle source
# File lib/compiler.rb, line 170
def compile_step step_ast
        client = @runtime.nodes[step_ast.client]
        if client == nil
                add_error NodeNotFoundError.new step_ast, step_ast.client
                return nil
        end

        server = @runtime.nodes[step_ast.server]
        if server == nil
                add_error NodeNotFoundError.new step_ast, step_ast.server
                return nil
        end

        if client == server
                add_error ClientServerSameError.new step_ast
                return nil
        end

        direction_def = @runtime.get_direction client, step_ast.direction, server
        if direction_def == nil
                add_error DirectionNotFoundError.new step_ast, client, step_ast.direction, server
                return nil
        end

        message_def = direction_def.messages[step_ast.message]
        if message_def == nil
                add_error MessageNotFoundError.new step_ast, direction_def
                return nil
        end

        StepDef.new step_ast, direction_def, message_def
end
compile_struct(struct_ast) click to toggle source
# File lib/compiler.rb, line 97
def compile_struct struct_ast
        self.check_case 'struct', :upper, struct_ast
        self.check_type_unique struct_ast
        struct_def = StructTypeDef.new struct_ast
        struct_ast.members.each do |member_ast|
                self.check_case 'struct member', :lower, member_ast
                self.check_unique 'struct member', struct_def.get_member(member_ast.name), member_ast
                member_type_def = self.get_member_type @runtime.nodes.values, member_ast.type
                member_def = MemberDef.new member_ast, member_type_def
                struct_def.add_member member_def
        end
        @runtime.add_struct struct_def
end
get_member_type(nodes_to_check, member_type_ast) click to toggle source
# File lib/compiler.rb, line 203
def get_member_type nodes_to_check, member_type_ast
        type_def, runtime = self.get_type member_type_ast, true
        return nil if type_def == nil

        params = []
        case type_def.name
        when 'List'
                self.check_type_param_count member_type_ast, 1
                params.push self.get_member_type nodes_to_check, member_type_ast.params[0]
        when 'Set'
                self.check_type_param_count member_type_ast, 1
                params.push self.get_member_type nodes_to_check, member_type_ast.params[0]
        when 'Map'
                self.check_type_param_count member_type_ast, 2
                params.push self.get_member_type nodes_to_check, member_type_ast.params[0]
                params.push self.get_member_type nodes_to_check, member_type_ast.params[1]
        else
                self.check_type_param_count member_type_ast, 0
        end

        member_type_def = TypeInstanceDef.new member_type_ast, type_def, params, runtime
        self.check_type_nodes member_type_ast, member_type_def
        member_type_def
end
get_type(ast, raise_error) click to toggle source
# File lib/compiler.rb, line 245
def get_type ast, raise_error
        return nil if ast == nil
        
        type_def, runtime = @runtime.get_type ast.name
        return type_def, runtime if type_def != nil

        add_error TypeNotFoundError.new ast, ast.name if raise_error
        return type_def, runtime
end