class Rserve::Protocol::REXPFactory
representation of R-eXpressions in Ruby
Constants
- XT_ARRAY_BOOL
xpression type: RBool[]
- XT_ARRAY_BOOL_UA
internal use only! this constant should never appear in a
REXP
- XT_ARRAY_CPLX
xpression type: Complex[] @since
Rserve
0.5- XT_ARRAY_DOUBLE
xpression type: double[]
- XT_ARRAY_INT
xpression type: int[]
- XT_ARRAY_STR
xpression type: String[] (currently not used, Vector is used instead)
- XT_BOOL
xpression type: RBool
- XT_CLOS
xpression type: closure (there is no java class for that type (yet?). currently the body of the closure is stored in the content part of the
REXP
. Please note that this may change in the future!)- XT_DOUBLE
xpression type: double
- XT_FACTOR
xpression type:
RFactor
; this XT is internally generated (ergo is does not come from Rsrv.h) to supportRFactor
class which is built fromXT_ARRAY_INT
- XT_HAS_ATTR
used for transport only - has attribute
- XT_INT
xpression type: integer
- XT_LANG
xpression type: language construct (currently content is same as list)
- XT_LANG_NOTAG
xpression type: language list (w/o tags) @since
Rserve
0.5- XT_LANG_TAG
xpression type: language list (w tags) @since
Rserve
0.5- XT_LIST
xpression type: dotted-pair list (RList)
- XT_LIST_NOTAG
xpression type: dotted-pair list (w/o tags) @since
Rserve
0.5- XT_LIST_TAG
xpression type: dotted-pair list (w tags) @since
Rserve
0.5- XT_NULL
xpression type: NULL
- XT_RAW
xpression type: raw (byte[]) @since
Rserve
0.4-?- XT_S4
xpression type: S4 object
@since
Rserve
0.5- XT_STR
xpression type: String
- XT_SYM
xpression type: symbol (content is symbol name: String)
- XT_SYMNAME
xpression type: symbol name @since
Rserve
0.5- XT_UNKNOWN
xpression type: unknown; no assumptions can be made about the content
- XT_VECTOR
xpression type: generic vector (RList)
- XT_VECTOR_EXP
xpression type: expression vector
- XT_VECTOR_STR
xpression type: string vector
Attributes
Public Class Methods
# File lib/rserve/protocol/rexpfactory.rb, line 82 def initialize(*args) @attr=nil if args.size==0 elsif r=args[0] r=Rserve::REXP::Null if r.nil? a=r.attr @cont=r @attr=REXPFactory.new(a) if !a.nil? if r.is_a? REXP::Null @type=XT_NULL elsif r.is_a? REXP::List l=r.as_list @type=l.named? ? XT_LIST_TAG : XT_LIST_NOTAG if r.is_a? REXP::Language @type = (@type==XT_LIST_TAG) ? XT_LANG_TAG : XT_LANG_NOTAG; end elsif r.is_a? REXP::GenericVector @type = XT_VECTOR; # FIXME: may have to adjust names attr elsif r.is_a? REXP::S4 @type = XT_S4 elsif r.is_a? REXP::Integer @type = XT_ARRAY_INT elsif r.is_a? REXP::Double @type = XT_ARRAY_DOUBLE elsif r.is_a? REXP::String @type = XT_ARRAY_STR elsif r.is_a? REXP::Symbol @type = XT_SYMNAME elsif r.is_a? REXP::Raw @type = XT_RAW elsif r.is_a? REXP::Logical @type = XT_ARRAY_BOOL else raise ArgumentError("***REXPFactory unable to interpret #{r}") end end end
Public Instance Methods
# File lib/rserve/protocol/rexpfactory.rb, line 73 def get_REXP @cont end
# File lib/rserve/protocol/rexpfactory.rb, line 76 def get_attr @attr.nil? ? nil : @attr.cont end
Calculates the length of the binary representation of the REXP
including all headers. This is the amount of memory necessary to store the REXP
via do@link getBinaryRepresentationend. Please note that currently only XT_INT, XT_DOUBLE and XT_STR are supported! All other types will return 4 which is the size of the header. @return length of the REXP
including headers (4 or 8 bytes)*/
# File lib/rserve/protocol/rexpfactory.rb, line 475 def get_binary_length l=0 rxt = type if (type==XT_LIST or type==XT_LIST_TAG or type==XT_LIST_NOTAG) rxt=(!cont.as_list.nil? and cont.as_list.named?) ? XT_LIST_TAG : XT_LIST_NOTAG; end #System.out.print("len["+xtName(type)+"/"+xtName(rxt)+"] "); rxt=XT_ARRAY_STR if (type==XT_VECTOR_STR) ; # VECTOR_STR is broken right now has_attr= false; a = get_attr; al = nil; al = a.as_list if (!a.nil?) has_attr=true if (!al.nil? and al.size()>0) l+=attr.get_binary_length if has_attr if (rxt==XT_NULL or rxt==XT_S4) elsif (rxt==XT_INT) l+=4 elsif (rxt==XT_DOUBLE) l+=8 elsif (rxt==XT_RAW) l+=4 + cont.as_bytes.length l=l-(l&3)+4 if ((l&3)>0) elsif (rxt==XT_STR or rxt==XT_SYMNAME) l+=(cont.nil?)?1:(cont.as_string.length()+1); l=l-(l&3)+4 if ((l&3)>0) elsif (rxt==XT_ARRAY_INT) l+=cont.as_integers().length*4 elsif (rxt==XT_ARRAY_DOUBLE) l+=cont.as_doubles().length*8 elsif (rxt==XT_ARRAY_CPLX) l+=cont.as_doubles().length*8 elsif (rxt==XT_ARRAY_BOOL) l += cont.as_bytes().length + 4 l = l - (l & 3) + 4 if ((l & 3) > 0) elsif ([XT_LIST_TAG, XT_LIST_NOTAG, XT_LANG_TAG, XT_LANG_NOTAG, XT_LIST, XT_VECTOR].include? rxt) lst = cont.as_list i=0 while (i<lst.size) x=lst.at(i) l+=(x.nil?)?4:(REXPFactory.new(x).get_binary_length) if(rxt==XT_LIST_TAG) pl=l s=lst.key_at(i) l+=4 l+=(s.nil?) ? 1:(s.length+1) l=l-(l&3)+4 if ((l&3)>0) end i+=1 end l=l-(l&3)+4 if ((l&3)>0) elsif rxt==XT_ARRAY_STR sa=cont.as_strings i=0 sa.each do |v| if(!v.nil?) b=v.unpack("C*") l+=b.length end l+=1 end l=l-(l&3)+4 if ((l&3)>0) else raise "NOT IMPLEMENTED" end l+=4 if (l>0xfffff0) l+4 end
# File lib/rserve/protocol/rexpfactory.rb, line 549 def get_binary_representation(buf,off) myl=get_binary_length; is_large=(myl>0xfffff0); a = get_attr; al = nil; al = a.as_list if (!a.nil?) has_attr=(!al.nil? and al.size()>0) rxt=type ooff=off rxt==XT_ARRAY_STR if(type==XT_VECTOR_STR) # VECTOR_STR is broken right now if (type==XT_LIST || type==XT_LIST_TAG || type==XT_LIST_NOTAG) rxt=(!cont.as_list.nil? and cont.as_list.named?) ? XT_LIST_TAG : XT_LIST_NOTAG end set_hdr(rxt|(has_attr ? XT_HAS_ATTR : 0), myl - (is_large ? 8 : 4 ),buf,off); off+=(is_large ? 8 : 4); if has_attr puts "REXP BIN ATTR: #{attr.cont.inspect}" if $DEBUG off=attr.get_binary_representation(buf, off) end puts "REXP BIN: #{xt_name(rxt)}(#{rxt})[#{myl}], '#{cont.inspect}' attr?:#{has_attr}" if $DEBUG if(rxt==XT_S4 or rxt==XT_NULL) elsif(rxt==XT_INT) set_int(cont.as_integer, buf, off) elsif(rxt==XT_DOUBLE) set_long(doubleToRawLongBits(cont.as_double), buf, off) elsif(rxt==XT_ARRAY_INT) ia=cont.as_integers io=off ia.each{|v| set_int(v,buf,io); io+=4} elsif(rxt==XT_ARRAY_BOOL) ba=cont.as_bytes io=off set_int(ba.length,buf,io) io+=4 if(ba.length>0) ba.each {|v| buf[io] = ( (v == REXP::Logical::NA) ? 2 : ((v == REXP::Logical::FALSE) ? 0 : 1) ); io+=1 } while ((io & 3) != 0) buf[io] = 3 io+=1 end end elsif(rxt==XT_ARRAY_DOUBLE) da=cont.payload io=off da.each do |v| # HACK # On i686, NA returns [162, 7, 0, 0, 0, 0, 240, 127] # So if we got a Double::NA, we should set mannualy this array if cont.na? v #if v==REXP::Double::NA buf[io,8]=REXP::Double::NA_ARRAY else set_long(doubleToRawLongBits(v), buf, io) end io+=8 end elsif(rxt==XT_RAW) by=cont.as_bytes set_int(by.length,buf,off); off+=4 by.each_with_index {|v,i| buf[off+i]=v} off+=by.length while ((off & 3) != 0) buf[off] = 0 off+=1 end elsif(rxt==XT_ARRAY_STR) sa=cont.as_strings io=off sa.each do |v| if !v.nil? b=v.unpack("C*") b.each_with_index{|vv,index| buf[io+index]=vv} io+=b.length end buf[io]=0 io+=1 end i=io-off while ((i&3)!=0) buf[io]=1; io+=1 i+=1 # padding if necessary.. end elsif ([XT_LIST_TAG, XT_LIST_NOTAG, XT_LANG_TAG, XT_LANG_NOTAG, XT_LIST, XT_VECTOR,XT_VECTOR_EXP].include? rxt) io=off #puts "io:#{io}" lst=cont.as_list #p lst if !lst.nil? lst.size.times do |ii| x=lst.at(ii) #puts "#{x}" x==REXP::Null if x.nil? #p buf io=REXPFactory.new(x).get_binary_representation(buf,io) #p buf #p io if(rxt==XT_LIST_TAG or rxt==XT_LANG_TAG) io=REXPFactory.new(REXP::Symbol.new(lst.key_at(ii))).get_binary_representation(buf, io) end end #times end #end if elsif (rxt==XT_SYMNAME or rxt==XT_STR) get_string_binary_representation(buf,off,cont.as_string) else raise "Can't represent on binary #{xt_name{rxt}}" end # end def puts "END BUFFER:#{buf}" if $DEBUG ooff+myl end
# File lib/rserve/protocol/rexpfactory.rb, line 676 def get_string_binary_representation(buf,off,s) s||="" io=off b=s.unpack("C*") puts "STRING REPRESENTATION: #{b}" if $DEBUG b.each_with_index {|v,i| buf[io+i]=v} io+=b.length buf[io]=0 io+=1 while ((io&3)!=0) buf[io]=0; # padding if necessary.. io+=1 end io end
# File lib/rserve/protocol/rexpfactory.rb, line 121 def parse_REXP(buf,o) xl=get_len(buf,o) has_at = (buf[o]&128)!=0 puts "content:#{buf.slice(o,xl+4)} '#{buf.slice(o+4,xl+4).pack("C*")}'" if $DEBUG is_long = (buf[o]&64 )!=0 xt = buf[o]&63 o+=4 if is_long o+=4 eox=o+xl @type=xt @attr=REXPFactory.new() @cont=nil if has_at puts "Processing attribs:" if $DEBUG o = attr.parse_REXP(buf, o) puts "FINAL ATTRIB:" if $DEBUG pp get_attr.as_list if $DEBUG end puts "REXP: #{xt_name(@type)}(#{@type})[#{o},#{xl}], attr?:#{has_at}, attr=[#{get_attr}]" if $DEBUG if xt==XT_NULL @cont=REXP::Null.new(get_attr) return o end if xt==XT_DOUBLE lr=get_long(buf,o) d=[longBitsToDouble(lr)] o+=8 if(o!=eox) sexp_mismatch("double") o=eox end @cont=REXP::Double.new(d,get_attr) return o end if xt==XT_ARRAY_DOUBLE as=(eox-o).quo(8) i=0 d=Array.new(as) while(o<eox) d[i]=longBitsToDouble(get_long(buf,o)) o+=8 i+=1 end if(o!=eox) sexp_mismatch("double") o=eox end @cont=REXP::Double.new(d,get_attr) return o end if xt==XT_BOOL b=[buf[o]] b[0]=REXP::Logical::NA if (b[0]!=0 && b[0]!=1) @cont=REXP::Logical.new(b,get_attr) o+=1 if(o!=eox) sexp_mismatch("Warning: bool SEXP size mismatch\n") if (eox!=o+3) # o+3 could happen if the result was aligned (1 byte data + 3 bytes padding) o=eox end return o end if xt==XT_ARRAY_BOOL_UA as=(eox-o) i=0 d=Array.new(as) (eox-i).times {|ii| d[ii]=buf[o+ii]} o=eox d.length.each {|j| if d[j]!=0 and d[j]!=1 d[j]==REXP::Logical::NA end } @cont=REXP::Logical.new(d,get_attr) return o end if xt==XT_ARRAY_BOOL as=get_int(buf, o) o+=4 d=Array.new(as) as.times {|ai| d[ai]=buf[o+ai]} d.collect! {|v| if v!=0 and v!=1 REXP::Logical::NA else v end } o=eox @cont=REXP::Logical.new(d,get_attr) return o end if xt==XT_INT i=Array.new(get_int(buf,o)) @cont=REXP::Integer.new(i,get_attr) o+=4 if o!=eox $STDERR.puts "int SEXP size mismatch" o=eox end return o end if xt==XT_ARRAY_INT as=(eox-o).quo(4) i=0 d=Array.new(as) while(o<eox) d[i]=get_int(buf,o) o+=4 i+=1 end if o!=eox $STDERR.puts "int SEXP size mismatch" o=eox end # hack for factors if (!get_attr.nil?) ca = get_attr().as_list["class"] ls = get_attr().as_list["levels"] if (!ca.nil? and !ls.nil? and ca.as_string=="factor") # R uses 1-based index, Java (and Ruby) uses 0-based one @cont = REXP::Factor.new(d, ls.as_strings(), get_attr) xt = XT_FACTOR; end end if @cont.nil? @cont=REXP::Integer.new(d,get_attr) end return o end if (xt==XT_RAW) as=get_int(buf,o); o+=4 d=buf[o,as] o = eox; @cont = REXP::Raw.new(d, get_attr); return o; end if xt==XT_LIST_NOTAG or xt==XT_LIST_TAG or xt==XT_LANG_NOTAG or xt==XT_LANG_TAG lc=REXPFactory.new nf=REXPFactory.new l=Rlist.new while(o<eox) name=nil o=lc.parse_REXP(buf,o) if(xt==XT_LIST_TAG or xt==XT_LANG_TAG) o=nf.parse_REXP(buf,o) name=nf.cont.as_string if(nf.cont.symbol? or nf.cont.string?) end puts "Adding '#{name}'='#{lc.cont.inspect}'" if $DEBUG if name.nil? l.push(lc.cont) else l.put(name,lc.cont) end end p l.inspect if $DEBUG @cont=(xt==XT_LANG_NOTAG or xt==XT_LANG_TAG) ? REXP::Language.new(l, get_attr) : REXP::List.new(l, get_attr) pp @cont if $DEBUG if(o!=eox) $STDERR.puts "Mismatch" o=eox end return o end # old-style lists, for comaptibility with older Rserve versions - rather inefficient since we have to convert the recusively stored structures into a flat structure # NOT TESTED YET if (xt==XT_LIST or xt==XT_LANG) # is_root= false if (root_list.nil?) root_list = Rlist.new(); is_root= true; end headf = REXPFactory.new(); tagf = REXPFactory.new(); o = headf.parse_REXP(buf, o); el_index = root_list.size(); root_list.add(headf.cont); #System.out.println("HEAD="+headf.cont); o = parse_REXP(buf, o); # we use ourselves recursively for the body if (o < eox) o = tagf.parseREXP(buf, o); #//System.out.println("TAG="+tagf.cont); if (!tagf.cont.nil? and (tagf.cont.string? or tagf.cont.symbol?)) root_list.set_key_at(el_index, tagf.cont.as_string); end end if (is_root) @cont = (xt==XT_LIST)? REXP::List.new(root_list, get_attr): REXP::Language.new(root_list, get_attr) root_list = nil; #System.out.println("result="+cont); end return o; end if xt==XT_VECTOR or xt==XT_VECTOR_EXP v=Array.new while(o<eox) xx=REXPFactory.new() o = xx.parse_REXP(buf,o); v.push(xx.cont); end if (o!=eox) sexp_mismatch("int") o=eox; end # fixup for lists since they're stored as attributes of vectors if !get_attr.nil? and !get_attr.as_list['names'].nil? puts "PROCESSING NAMES" if $DEBUG nam=get_attr.as_list['names'] names=nil if nam.string? names=nam.as_strings elsif nam.vector? names=nam.as_list.map {|vv| vv.as_string} end l=Rlist.new(v,names) @cont=(xt==XT_VECTOR_EXP) ? REXP::ExpressionVector.new(l,get_attr) : REXP::GenericVector.new(l,get_attr) else @cont=(xt==XT_VECTOR_EXP) ? REXP::ExpressionVector.new(Rlist.new(v), get_attr) : REXP::GenericVector.new(Rlist.new(v), get_attr) end return o end if xt==XT_ARRAY_STR c=0 i=o while(i<eox) c+=1 if buf[i]==0 i+=1 end s=Array.new(c) if c>0 c=0; i=o; while(o < eox) if buf[o]==0 begin s[c]=buf[i,o-i].pack("C*") rescue s[c]="" end c+=1 i=o+1 end o+=1 end end @cont=REXP::String.new(s, get_attr) return o end if xt==XT_VECTOR_STR v=Array.new while(o<eox) xx=REXPFactory.new o=xx.parse_REXP(buf,o) v.push(xx.cont.as_string) end sa=Array.new(v.size) i=0 while(i<sa.length) sa[i]=v.get(i) i+=1 end @cont=REXP::String.new(sa,get_attr) return o end if (xt==XT_STR||xt==XT_SYMNAME) i = o; while (buf[i]!=0 && i<eox) i+=1 end if (xt==XT_STR) @cont = REXP::String.new(buf[o,i-o].pack("C*"), get_attr); else @cont = REXP::Symbol.new(buf[o,i-o].pack("C*")) end o = eox; return o; end if (xt==XT_SYM) sym = REXPFactory.new o = sym.parse_REXP(buf, o); # PRINTNAME that's all we will use @cont = REXP::Symbol.new(sym.get__REXP().as_string) # content of a symbol is its printname string (so far) o=eox; return o; end if (xt==XT_CLOS) headf = REXPFactory.new() bodyf = REXPFactory.new() o=headf.parse_REXP(buf,o) o=bodyf.parse_REXP(buf,o) @cont=REXP::Function.new(headf.cont,bodyf.cont) if o!=eox $STDERR.puts "CLOS SEXP size mismatch" o=eox end return o; end if (xt==XT_UNKNOWN) @cont = REXP::Unknown.new(get_int(buf,o), get_attr) o=eox; return o; end if (xt==XT_S4) @cont = REXP::S4.new(get_attr) o=eox return o; end @cont=nil o=eox raise "Unhandled type:#{xt}" return o end
# File lib/rserve/protocol/rexpfactory.rb, line 79 def sexp_mismatch(type) STDERR.puts("Warning: #{type} SEXP size mismatch") end
# File lib/rserve/protocol/rexpfactory.rb, line 691 def xt_name(xt) case xt when XT_NULL then "NULL"; when XT_INT then "INT"; when XT_STR then "STRING"; when XT_DOUBLE then "REAL"; when XT_BOOL then "BOOL"; when XT_ARRAY_INT then "INT*"; when XT_ARRAY_STR then "STRING*"; when XT_ARRAY_DOUBLE then "REAL*"; when XT_ARRAY_BOOL then "BOOL*"; when XT_ARRAY_CPLX then "COMPLEX*"; when XT_SYM then "SYMBOL"; when XT_SYMNAME then "SYMNAME"; when XT_LANG then "LANG"; when XT_LIST then "LIST"; when XT_LIST_TAG then "LIST+T"; when XT_LIST_NOTAG then "LIST/T"; when XT_LANG_TAG then "LANG+T"; when XT_LANG_NOTAG then "LANG/T"; when XT_CLOS then "CLOS"; when XT_RAW then "RAW"; when XT_S4 then "S4"; when XT_VECTOR then "VECTOR"; when XT_VECTOR_STR then "STRING[]"; when XT_VECTOR_EXP then "EXPR[]"; when XT_FACTOR then "FACTOR"; when XT_UNKNOWN then "UNKNOWN"; else "<unknown #{xt}" end end