# Purpose: 
#
# $Id: source_structures.rb,v 1.3 2005/12/08 11:29:19 jonathanm Exp $
#
# Authors:  Rich Kilmer <rich@infoether.com>
# Contributors:
#
# This file is part of the FreeRIDE project
#
# This application is free software; you can redistribute it and/or
# modify it under the terms of the Ruby license defined in the
# COPYING file.
#
# Copyright (c) 2003 Rich Kilmer. All rights reserved.
#
module FreeRIDE
  module Tools
    module SourceStructures
    
      class RubyGlobalContext
        def initialize
          @required = []
        end
      end
      
      class Source
        attr_reader :filename, :path, :top_level_context
        
        def initialize(filename, path, context)
          @filename = filename
          @path = path
          @top_level_context = context
        end
      end
      
      class CodeObject
        attr_accessor :parent
      end
      
      class Atom < CodeObject
        
        attr_reader :point, :name
        
        def initialize(point, name = nil)
          @point = point
        end
        
      end
      
      class Region < CodeObject
        
        attr_reader :start_point, :end_point, :num_lines
        attr_accessor :num_comments
        
        def initialize(s_p, e_p = nil)
          @start_point = s_p
          @end_point = e_p
          @num_lines = 0
          @num_comments = 0
        end
        
        def end_point=(e_p)
          @end_point = e_p
          @num_lines = e_p.line_no - @start_point.line_no
        end
        
      end
      
      class Context < Region
        
        #attr_reader :attr_list, :alias_list
        #attr_reader :require_list, :include_list
        attr_reader :method_list, :class_list, :module_list #, :block_list
        attr_reader :singleton_class_list, :singleton_method_list
        #attr_reader :instance_var_list, :class_var_list, :global_var_list, :local_var_list, :constant_list
        #alias_method :identifier_list, :local_var_list
  
        attr_reader :name#, :visibility            
        attr_accessor :parent
        attr_accessor :total_num_comments
        
        def initialize(s_p, name = nil)
          super(s_p)
          
          @name = name
          #@alias_list = []
          #@attr_list = []
          
          #@block_list = []
          @method_list = []
          @class_list = []
          @module_list = []
          
          @singleton_method_list = []
          @singleton_class_list = []
          
          #@constant_list = []
          #@local_var_list = []
          #@instance_var_list = []
          #@class_var_list = []
          #@global_var_list = []
          
          @parent = nil
          #@visibility = :public
          
          #@include_list = []
          #@require_list = []
        end
        
        #        def add_alias(new_alias)
        #  	@alias_list.push(new_alias)
        #  	new_alias.parent = self
        #        end
        
        #        def add_attribute(new_attr)
        #  	@attr_list.push(new_attr)
        #  	new_attr.parent = self
        #  	new_attr.visibility = @visibility
        #        end
        
        #        def add_require(req)
        #  	@require_list.push(req)
        #  	req.parent = self
        #        end
        
        #        def add_include(inc)
        #  	@include_list.push(inc)
        #  	inc.parent = self
        #        end
        
        #      def add_block(b)
        #	@block_list.push(b)
        #	b.parent = self
        #	b.visibility = @visibility
        #      end
        
        def add_method(m)
          @method_list.push(m)
          m.parent = self
          
          #m.qualified_name
          m.visibility = @visibility
        end
        
        def add_class(c)
          @class_list.push(c)
          c.parent = self
        end
        
        def add_module(mod)
          @module_list.push(mod)
          mod.parent = self
        end
        
        def add_singleton_method(m)
          @singleton_method_list.push(m)
          m.visibility = @visibility
          m.parent = self
        end
        
        def add_singleton_class(c)
          @singleton_class_list.push(c)
          c.parent = self
        end
        
        #        def add_constant(const)
        #  	@constant_list.push(const)
        #  	const.parent = self
        #        end
        
        #        def add_global_var(gv)
        #  	@global_var_list.push(gv)
        #  	gv.parent = self
        #        end
        
        #        def add_instance_var(iv)
        #  	@instance_var_list.push(iv)
        #  	iv.parent = self
        #        end
        
        #        def add_class_var(cv)
        #  	@class_var_list.push(cv)
        #  	cv.parent = self
        #        end
        
        #        def add_local_var(lv)
        #  	@local_var_list.push(lv)
        #  	lv.parent = self
        #        end
        
        #        def set_visibility_for(methods, vis)
        #  	@method_list.each_with_index do |m,i|
        #  	  if methods.include?(m.name)
        #  	    m.visibility = vis
        #  	  end
        #  	end
        #        end
        
        #        def ongoing_visibility=(vis)
        #  	@visibility = vis
        #        end
        
        def each_module
          @module_list.each { |mod| yield mod }
        end
        
        def each_class
          @class_list.each { |klass| yield klass }
        end
        
        def each_method
          @method_list.each { |m| yield m }
        end
        
        def each_singleton_method
          @singleton_method_list.each { |m| yield m }
        end
        
        def each_singleton_class
          @singleton_class_list.each { |c| yield c }
        end
        
        def qualified_name
          raise StandardError, 'Context#qualified_name must be implemented in subclass.'
        end
        
        # Calculate the total number of comments, including those of child elements
        def calculate_total_comments
          @total_num_comments = @num_comments
          (@module_list + @class_list + @method_list + @singleton_method_list + 
                @singleton_class_list).each do |ctx|
            ctx.calculate_total_comments
            @total_num_comments += ctx.total_num_comments
          end
        end
        
      end
      
      class AnyModule < Context
  
        def qualified_name
          res = @parent.qualified_name
          if res == ''
            res = @name
          else
            res += '::' + @name
          end
          
          res 
        end
        
      end
      
      # TopLevel is in the context of Object's object
      class TopLevelContext < AnyModule
        attr_accessor :num_whitespace
        
        def initialize
          super( Position.new(0,0) )
          @name = ''
        end
        
        def qualified_name
          ''
        end
      end
      
      class NormalModule < AnyModule
      end
      
      class NormalClass < AnyModule
        attr_accessor :super_class
      end
      
      class SingletonClass < AnyModule
        # in some cases, this doesn't return the accurate name.
        def qualified_name
          @parent.qualified_name
        end
        
      end
      
      class AnyMethod < Context
        attr_accessor :visibility#, :params, :block_params
      end
      
      class SingletonMethod < AnyMethod
        
        SEPARATOR = '.'
        
        attr_reader :obj_name, :method_name
        
        def initialize(point, name)
          super(point, name)
          @obj_name, @method_name = name.split(SEPARATOR, 2)
        end
        
        def qualified_name
          res = @parent.qualified_name.dup << '.' << @method_name
          res
          #@method_name
        end
      end
      
      class NormalMethod < AnyMethod
        def qualified_name
          res = @parent.qualified_name
          if res == ''
            res = @name
          else
            res += '#' + @name
          end
        end
      end
      
      class Identifier < Atom
      end
      
      class LocalVar < Identifier
      end
      
      class InstanceVar < Identifier
      end
      
      class ClassVar < Identifier
      end
      
      class GlobalVar < Identifier
      end
      
      class Include < Atom      
      end
      
      class Alias < Atom
        
        SEPARATOR = ','
        
        attr_reader :new_name, :old_name
        
        def initialize(name, lex_token, nest, scope)
          super(name, lex_token, nest, scope)
          @new_name, @old_name = name.split(SEPARATOR, 2)
        end
        
        #def set_alias(new_n, old_n)
        #  @old_name = old_n
        #  @new_name = new_n
        #end
        
        #def alias_name 
        #	@new_name + ':' + @old_name
        #end
        
      end
      
      class Attr < Atom
        
        R = :read
        W = :write
        RW = :readwrite
        
        attr_accessor :mode, :visibility
        
      end
      
      class Require < Atom
      end
      
      class MethodParameters < CodeObject
        
        attr_reader :args, :multiple_arg, :block_arg
        
        def initialize(args)
          block_arg = ''
          multiple_arg = ''
          if /^\&/ =~ args[-1]
            block_arg = args.pop
          end
          if /^\*/ =~ args[-1]
            multiple_arg = args.pop
          end
          
          @multiple_arg = multiple_arg
          @block_arg = block_arg
          @args = args
        end
        
        def has_block_arg?
          if @block_arg != ''
            return true
          else
            return false
          end
        end
        
        def has_multiple_arg?
          if @multiple_arg != ''
            return true
          else
            return false
          end
        end
        
        def arity
          sign = @multiple_arg ? -1 : 1
          num has_block_arg? ? 1 : 0
          num += @args.size
          
          num *= sign
          num
        end
        
        def name
          result = args.join(', ') 
          if @multiple_arg 
            result << ', *' + @multiple_arg 
          end
          if @block_arg 
            result << ', &' + @block_arg
          end
          
          result
        end
        
      end
      
      class BlockParameters < CodeObject
        attr_reader :args
        
        def initialize(args)
          @args
        end
        
        def arity
          @args.size
        end
      end
      
    end
  end
end



syntax highlighted by Code2HTML, v. 0.9.1