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 <vector>

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

Value* unmarshal(void* vmptr,char* 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, char*& x, int id)
{
    Value *v;

    int i = un_int(vm,done,x)->getInt();
    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,NULL);
    }
}

Value* un_int(VMState* vm,vector<Value*>& done,char* &x)
{
    // Expecting [num]
    char* buf = (char*)GC_MALLOC(sizeof(char)*20);
    int i=0;
    
    if (*x!='[') {
      String *err = new String("Invalid int to unmarshall : ");
      err->append(new String(x));
      vm->kaya_throw(err->getVal(),254);
    }
    x++; // Move past the initial [
    while(*x!=']') {
      buf[i++]=*x;
      x++;
    }
    buf[i]='\0';
    int val = atoi(buf);

    x++;
    return MKINT(val);
}

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

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

Value* un_circle(VMState* vm,vector<Value*>& done,char* &x)
{
    if (*x!='[') vm->kaya_throw("Invalid circular structure",254);
    int circid = un_int(vm,done,x)->getInt();
//    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,char* &x)
{
    // Expecting [num]string
//    cout << "Doing string, x is " << x << endl;

    if (*x!='[') vm->kaya_throw("Invalid string to unmarshall",254);
    x++;
    int len = un_int(vm,done,x)->getInt(); // Euw, a bit inefficient, no need to make the intermediate Value really

    char* buf = (char*)GC_MALLOC(sizeof(char)*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;

    return MKSTR(buf);
}

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

    Array* ar = new Array();
    if (*x!='[') vm->kaya_throw("Invalid array to unmarshall",254);
    x++;
    int circid = un_int(vm,done,x)->getInt();
    Value* thisval = new Value(ar,arraytable);

    // 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,char* &x, int id)
{
//    cout << "Doing union " << endl;

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

    // Euw, a bit inefficient, no need to make the intermediate Value really
    int circid = un_int(vm,done,x)->getInt();
    int tag = un_int(vm,done,x)->getInt();
    int arity = un_int(vm,done,x)->getInt();

    Union* u = new Union(NULL,tag,arity,false);
    Value* thisval = new Value(u,uniontable);

    // 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,char* &x, int id)
{
//    cout << "Doing union " << endl;

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

    // Euw, a bit inefficient, no need to make the intermediate Value really
    int circid = un_int(vm,done,x)->getInt();
    int fnid = un_int(vm,done,x)->getInt();
    int arity = un_int(vm,done,x)->getInt();

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

    // 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;
}

Generated by  Doxygen 1.6.0   Back to index