Logo Search packages:      
Sourcecode: kaya version File versions  Download package

unpickler.cc

/**
    Kaya run-time system
    Copyright (C) 2004, 2005 Edwin Brady

    This file is distributed under the terms of the GNU Lesser General
    Public Licence. See COPYING for licence.
*/

using namespace std;

#include <stdlib.h>
#include <stddef.h>
#include <inttypes.h>
#include <vector>
#include "wchar.h"

#include "Heap.h"
#include "VMState.h"
#include "VM.h"
#include "stdfuns.h"
#include "unpickler.h"

Value* unmarshal(void* vmptr,wchar_t* x, int id)
{
    VMState* vm = (VMState*)vmptr;
    vector<Value*> done;
    Value* v = unpickle(vm, done, x, id);
    return v;
}

Value* unpickle(VMState* vm, vector<Value*>& done, wchar_t*& x, int id)
{
    Value *v;

    int i = read_int(vm,x);
    if (i!=id) {
      vm->kaya_throw("Invalid unmarshalling id",253);
    }

    switch(x[0]) {
    case 'I':
      x++;
      v=un_int(vm,done,x);
      return v;
    case 'S':
      x++;
      v=un_string(vm,done,x);
      return v;
    case 'U':
      x++;
      v=un_union(vm,done,x,id);
      return v;
    case 'F':
      x++;
      v=un_closure(vm,done,x,id);
      return v;
    case 'A':
      x++;
      v=un_array(vm,done,x,id);
      return v;
    case 'R':
      x++;
      v=un_real(vm,done,x);
      return v;
    case 'C':
      x++;
      v=un_circle(vm,done,x);
      return v;
    default:
      vm->kaya_throw("Invalid value to unmarshall",254);
      return new Value(NULL,KVT_NULL);
    }
}

int read_int(VMState* vm, wchar_t* &x) {
    wchar_t buf[30]; // = (wchar_t*)GC_MALLOC_ATOMIC(sizeof(wchar_t)*20);
    int i=0;
    
    if (*x!='[') {
      String *err = new String(L"Invalid int to unmarshall : ");
      err->append(new String(x));
      vm->kaya_throw(err->getVal(),254);
    }
    x++; // Move past the initial [
    while(*x!=']' && i<30) {
      buf[i++]=*x;
      x++;
    }
    if (i == 50) {
      String *err = new String(L"Invalid int to unmarshall : ");
      err->append(new String(x));
      vm->kaya_throw(err->getVal(),254);
    }
    buf[i]='\0';
    int val = wcstoimax(buf,NULL,10);
    //      = atoi(wctostr(buf));

    x++;
    return val;
}

Value* un_int(VMState* vm,vector<Value*>& done,wchar_t* &x)
{
    // Expecting [num]
    return mkint((void*)read_int(vm,x));
}

Value* un_real(VMState* vm,vector<Value*>& done,wchar_t* &x)
{
    // Expecting [num]
    wchar_t buf[100]; // = (wchar_t*)GC_MALLOC_ATOMIC(sizeof(wchar_t)*100); // Yeah, horrible, I know.
    int i=0;
    
    if (*x!='[') {
      String *err = new String(L"Invalid float to unmarshall : ");
      err->append(new String(x));
      vm->kaya_throw(err->getVal(),254);
    }
    x++; // Move past the initial [
    while(*x!=']' && i<100) {
      buf[i++]=*x;
      x++;
    }
    buf[i]='\0';
    double val = wcstod(buf,NULL);

    x++;
    return MKREAL(val);
//    vm->kaya_throw("Not implemented yet",255);
//    return new Value(NULL,NULL);
}

Value* un_circle(VMState* vm,vector<Value*>& done,wchar_t* &x)
{
    if (*x!='[') vm->kaya_throw("Invalid circular structure",254);
    int circid = read_int(vm,x);
//    cout << circid << "," << done.size() << endl;
    if (done.size()<(unsigned)circid) 
      vm->kaya_throw("Invalid circular structure",253);
    return done[circid];
}

Value* un_string(VMState* vm,vector<Value*>& done,wchar_t* &x)
{
    // Expecting [num]string
//    cout << "Doing string, x is " << x << endl;

    if (*x!='[') vm->kaya_throw("Invalid string to unmarshall",254);
    x++;
    int len = read_int(vm,x);
    int alloc = read_int(vm,x);
    if (alloc < len) {
      alloc = len;
    }
    
    wchar_t buf[len+1]; // = (wchar_t*)GC_MALLOC_ATOMIC(sizeof(wchar_t)*len+1);
    int i=0;

    while(i<len) {
      buf[i++]=*x;
      x++;
    }
    buf[i]='\0';
    x++;

//    cout << "Got string of length " << len << "," << buf << endl;
//    cout << "x is " << x << endl;
    Value* str = createString(alloc);
    str->getString()->append(buf);
    return str;
}

Value* un_array(VMState* vm,vector<Value*>& done,wchar_t* &x, int id)
{
//    cout << "Doing array " << endl;

    if (*x!='[') vm->kaya_throw("Invalid array to unmarshall",254);
    x++;
    int circid = read_int(vm,x);
    int sz = read_int(vm,x); // advisory only, but it makes memory usage much more efficient if it's right...
    if (sz == 0) { // unless it's zero, in which case explictly set a small size
      sz = 5;
    }
    Array* ar = new Array(sz);
    Value* thisval = new Value(ar,KVT_ARRAY);

    // Remember the value in case we get a circular structure
    done.push_back(thisval);
    if ((unsigned)circid!=done.size()-1) {
      vm->kaya_throw("ECB made a flawed assumption. Shout at him.",252);
    }
    
    while(x[0]!=']')
    {
      Value* v = unpickle(vm,done,x,id);
      ar->push_back(v);
    }
    x++;
//    thisval->setPtr(new Value(ar,arraytable));
    return thisval;
}

Value* un_union(VMState* vm,vector<Value*>& done,wchar_t* &x, int id)
{
//    cout << "Doing union " << endl;

    if (*x!='[') vm->kaya_throw("Invalid union to unmarshall",254);
    x++;

    int circid = read_int(vm,x);
    int tag = read_int(vm,x);
    int arity = read_int(vm,x);

    Union* u;
    if (arity > 0 || tag > 20) { // 20 is a bit arbitrary, yes
      u = new Union(NULL,tag,arity,false);
    } else {
      u = un_union_static(tag);
    }
    Value* thisval = new Value(u,KVT_UNION);

    // Remember the value in case we get a circular structure
    done.push_back(thisval);
    if ((unsigned)circid!=done.size()-1) {
      vm->kaya_throw("ECB made a flawed assumption. Shout at him.",252);      
    }

//    cout << "Adding " << circid << "," << done.size() << endl;

    int i=0;
    while(i<arity)
    {
      Value* v = unpickle(vm,done,x,id);
      u->args[i]=v;
      i++;
    }
    x++;

    return thisval;
}

Value* un_closure(VMState* vm,vector<Value*>& done,wchar_t* &x, int id)
{
//    cout << "Doing union " << endl;

    if (*x!='[') vm->kaya_throw("Invalid closure to unmarshall",254);
    x++;

    int circid = read_int(vm,x);
    int fnid = read_int(vm,x);
    int arity = read_int(vm,x);

    Closure* c = new Closure(NULL,getFn(fnid),arity,arity,false);
    Value* thisval = new Value((void*)c,KVT_FUNC);

    // Remember the value in case we get a circular structure
    done.push_back(thisval);
    if ((unsigned)circid!=done.size()-1) {
      vm->kaya_throw("ECB made a flawed assumption. Shout at him.",252);      
    }

//    cout << "Adding " << circid << "," << done.size() << endl;

    int i=0;
    while(i<arity)
    {
      Value* v = unpickle(vm,done,x,id);
      c->setArg(i,v);
      i++;
    }
    x++;

    return thisval;
}

#define STATIC_UNION(t) case t: static Union* u## t = new Union(NULL,t,0,false); return u## t;

Union* un_union_static(int tag) {
  switch (tag) {
    STATIC_UNION(0)
    STATIC_UNION(1)
    STATIC_UNION(2)
    STATIC_UNION(3)
    STATIC_UNION(4)
    STATIC_UNION(5)
    STATIC_UNION(6)
    STATIC_UNION(7)
    STATIC_UNION(8)
    STATIC_UNION(9)
    STATIC_UNION(10)
    STATIC_UNION(11)
    STATIC_UNION(12)
    STATIC_UNION(13)
    STATIC_UNION(14)
    STATIC_UNION(15)
    STATIC_UNION(16)
    STATIC_UNION(17)
    STATIC_UNION(18)
    STATIC_UNION(19)
    STATIC_UNION(20)
  }
  // can't happen
  return new Union(NULL,tag,0,false);
}

Generated by  Doxygen 1.6.0   Back to index