#<ruby>

# This imports S-Lang functions into ruby
module SLang
  def SLang.bootstrap(refs)
    @@get_reference = refs[0]
    @@is_defined_ref = refs[1]
    @@get_variable_ref = refs[2]
    @@set_variable_ref = refs[3]
    @@get_namespaces_ref = refs[4]
  end
  
  def SLang.is_defined(name)
    @@is_defined_ref.call(name)
  end
  def SLang.get_variable(name)
    @@get_variable_ref.call(name)
  end
  
  # This makes the SLang namespace "namespace" accessible as SLang::name
  def SLang.import_namespace(namespace, name)
    raise "No such SLang namespace: #{namespace}" unless @@get_namespaces_ref.call[0].include? namespace
    name = name.to_sym
    return SLang.const_get(name) if SLang.const_defined? name
    c = Module.new {
      @@namespace = namespace
      def self.method_missing(meth, *args)
	method_name = "#{@@namespace}->%s" % meth.to_s
	if method_name =~ /(.*)=$/
	  return @@set_variable_ref.call($1, *args)
	end
	case SLang.is_defined(method_name)[0]
	when 1..2
	  ref = @@get_reference.call(method_name)[0]
	  return super if (ref == nil);
	  define_method(method_name) do |*args|
	    ref.call(*args)
	  end
	  ref.call(*args)
	when -2..-1
	  get_variable(method_name)[0]
	else
	  raise "no such SLang name: #{method_name}"
	end
      end
    }
    self.const_set(name, c)
  end
  
  def SLang.method_missing(meth, *args)
    method_name = meth.to_s
    if method_name =~ /(.*)=$/
      return @@set_variable_ref.call($1, *args)
    end
    case SLang.is_defined(method_name)[0]
    when 1..2
      ref = @@get_reference.call(method_name)[0]
      return super if (ref == nil);
      define_method(method_name) do |*args|
    	ref.call(*args)
      end
      ref.call(*args)
     when -2..-1
       get_variable(method_name)[0]
     else
       raise "no such SLang name: #{method_name}"
    end
  end
  
end

# This makes the sub and gsub methods of String, methods of Regexp
# What for?  Well, in Ruby you can do
# "nercpyitno".gsub(/(.)(.)/, '\2\1')            >>     "encryption"
# You can''t do that in S-Lang because Ruby strings are converted to
# native S-Lang strings.  Ruby regexps are passed as Ruby_Value types,
# so with this you can do
# variable re = rb_eval("/(.)(.)/");
# re.gsub("nercpyitno", "\\2\\1");               >>      "encryption"
class Regexp
  def sub(s, *args, &block)
    return s.sub(self, *args, &block)
  end
  
  def gsub(s, *args, &block)
    return s.gsub(self, *args, &block)
  end
end

__END__
#</ruby>
ifnot (is_defined("rb_eval"))
  import("ruby");
rb_load_file(__FILE__);
private define get_variable(name)
{
  @(__get_reference(name));
}

private define set_variable(name, value)
{
   @(__get_reference(name)) = value;
}

()=rb_eval("SLang").bootstrap([&__get_reference,
			      &is_defined,
			      &get_variable,
			      &set_variable,
			      &_get_namespaces]);

#ifexists _jed_version
define rb_backtrace()
{
   pop2buf("*Ruby backtrace*");
   eob();
   insert(rb_eval("$!.backtrace.join(\"\\n\")"));
}
add_completion("rb_backtrace");
#endif
provide("slruby");

