# Perlito6/Ruby/Runtime.rb
# 
# DESCRIPTION
# 
# Provides runtime routines for the Perl6-in-Ruby compiled code
# 
# AUTHORS
# 
# The Pugs Team E<lt>perl6-compiler@perl.orgE<gt>.
# 
# COPYRIGHT
# 
# Copyright 2010, 2011, 2012 by Flavio Soibelmann Glock and others.
# 
# This program is free software; you can redistribute it and/or modify it
# under the same terms as Perl itself.
# 
# See L<http://www.perl.com/perl/misc/Artistic.html>


class C_Main
end
$Main = C_Main.new()


class C_Pair
    $Pair = C_Pair.new()
    namespace = $Pair
    attr_accessor :v_key
    def f_key()
        return self.v_key
    end
    attr_accessor :v_value
    def f_value()
        return self.v_value
    end


    send( :define_method, "f_perl".to_sym, lambda{ ||
        v_self = self
        return(((self.v_key).to_s + " => " + (mp6_perl(self.v_value)).to_s))
    } )
end

class Hash
    def f_pairs ()
        out = []
        for i in self.keys()
            p = C_Pair.new()
            p.v_key = i
            p.v_value = self[i]
            out.push(p)
        end
        return out;
    end
end


def mp6_to_num (v)
    if v.class == String
        if v.index(".")
            return v.to_f
        end
        return v.to_i
    end
    if v == nil
        return 0
    end
    return v
end

def mp6_to_bool (v)
    if v.class == String
        return v != "0" && v != ""
    end
    if v.class == Fixnum || v.class == Float || v.class == Bignum
        return v != 0
    end
    if v.class == Array 
        return v.length != 0
    end
    if v.class == C_Perlito6__Match
        return mp6_to_bool(v.v_bool)
    end
    return v
end

def mp6_to_scalar (v)
    if v.class == C_Perlito6__Match
        return v.f_scalar()
    end
    if v.class == Array 
        return v.length
    end
    return v
end

def mp6_isa(o, s)
    class_name = o.class.to_s.sub("__", "::").sub("C_","")
    if s == 'Str'
        return class_name == 'String'
    end
    if s == 'Int'
        return class_name == 'Fixnum' || class_name == 'Bignum'
    end
    if s == 'Num'
        return class_name == 'Float'
    end
    return class_name == s
end

class C_Perlito6__Match < Hash
    $Perlito6__Match = C_Perlito6__Match.new()
    namespace = $Perlito6__Match
    attr_accessor :v_from
    def f_from()
        return self.v_from
    end
    attr_accessor :v_to
    def f_to()
        return self.v_to
    end
    attr_accessor :v_capture
    def f_capture()
        return self.v_capture
    end
    attr_accessor :v_str
    def f_str()
        return self.v_str
    end
    attr_accessor :v_bool
    def f_bool()
        return self.v_bool
    end
    def f_scalar()
        if mp6_to_bool(self.v_bool)
            if self.v_capture != nil
                return self.v_capture
            else
                return self.v_str[self.v_from .. self.v_to-1]
            end
        end
        return nil
    end
    def to_s()
        return self.f_scalar().to_s()
    end
end

class C_Perlito6__Grammar
    $Perlito6__Grammar = C_Perlito6__Grammar.new()
    namespace = $Perlito6__Grammar
    def f_word(s, pos)
        /^(\w)/.match(s[pos,1])
        m = C_Perlito6__Match.new
        if $~
            m.v_str  = s
            m.v_from = pos
            m.v_to   = $~.end(1) + pos
            m.v_bool = true
        else
            m.v_bool = false
        end
        return m
    end
    def f_digit(s, pos)
        /^(\d)/.match(s[pos,1])
        m = C_Perlito6__Match.new
        if $~
            m.v_str  = s
            m.v_from = pos
            m.v_to   = $~.end(1) + pos
            m.v_bool = true
        else
            m.v_bool = false
        end
        return m
    end
    def f_space(s, pos)
        /^(\s)/.match(s[pos,1])
        m = C_Perlito6__Match.new
        if $~
            m.v_str  = s
            m.v_from = pos
            m.v_to   = $~.end(1) + pos
            m.v_bool = true
        else
            m.v_bool = false
        end
        return m
    end
end

def _dump(o)
    class_name = o.class.to_s.sub("__", "::").sub("C_","")
    attrs = ( o.methods.grep /^v_.+=/ ).map{ |x| 
                meth = x.to_s.sub("=",""); name = meth.sub("v_",""); (name + " => " + mp6_perl(o.send(meth))) 
            }.join(", ")
    return class_name + ".new(" + attrs + ")";
end
 
def mp6_perl(o)
    if o == false
        return 'False'
    end
    if o == true
        return 'True'
    end
    if o == nil
        return 'undef'
    end
    if o.class == String
        o = s.gsub( "\\", "\\\\\\")
        o = o.gsub( "'",  "\\\\\'")
        return "'" + o + "'"   
    end
    if o.class == Fixnum || o.class == Float || o.class == Bignum
        return o.to_s
    end
    if o.class == Array 
        return "[" + (o.map{|x| mp6_perl(x)}).join(", ") + "]"
    end
    if o.class == Hash
        out = []
        for i in o.keys()
            out.push(i + " => " + mp6_perl(o[i]))
        end
        return "{" + out.join(", ") + "}";
    end
    return _dump(o)
end

class IO
    $IO = IO.new(1, "w")
    def f_slurp(s)
        IO.read(s)
    end
end