aboutsummaryrefslogblamecommitdiff
path: root/model.cpp
blob: a00a76553ac4ea734bc2df0e082d0bd3e0dddca6 (plain) (tree)
1
2
3
4
5
6
7
8
9
                 
                  

                   
 
                                             
                     
 
                                                       
 

                                        
                                            
 
                                                                  
 
                               
                                

 



                                    
                                                                       
 
                                  
 
                               








                               
 
 
                             
                                                        

 
 



                               



                                
                          


                 



                         
                            


                                                      

                                       
                 
                      



                                   

                                                           
                    
             


                                                    
             
                



                                                         


            

                                       






                                                          
         
                  
     



                                      
 
 
                                           
                                                 
                 
 


                                            
 
                                                                      
 


                                                         
                                                    
 


                                             
 

                                                   
 


                                        
 
                                                        
 
                              






















                                                                                    
 



                                                                                       
 




                                                                          
 


                                        
 
                                                                     
 
                                                                               


                                       


                                           
 









                                              
                                                 
                                                                               
 
                                                 
 
                                                                                  
 


                                        
 
                                                                            

                                            
                               








                                                           
                                    



                                         
                                    

 
                                                         
 



                                   
                            


                                   







                                           
                                   
                                        

 
                                          
                               




                                                   
                                                             

                                        

                                                                  
 



                                                                       
 

                                                             
 
 
                                                                            
 


                                                                             
                                     
                
 
 
                                             

                                                
 
                              
                                                            
     

                                                
     

                                                

 
                                                          

                                  
                                                 

                            




                                                                             
 
                                                        
                                                 
 

























                                                     
                        
         
     
 

                                                             
 

                                                     
 

                                                        
 












                                               
     










                                               
#include <cstdio>
#include "model.h"
#include "exc.h"
#include "consts.h"

static ReprCons *repr_stack[REPR_STACK_SIZE];
EvalObjAddrHash hash;

FrameObj::FrameObj(ClassType _ftype) : ftype(_ftype) {}

EmptyList *empty_list = new EmptyList();

EmptyList::EmptyList() : Pair(NULL, NULL) {}

ReprCons *EmptyList::get_repr_cons() { return new ReprStr("()"); }

bool FrameObj::is_ret_addr() { 
    return ftype & CLS_RET_ADDR;
}

bool FrameObj::is_parse_bracket() { 
    return ftype & CLS_PAR_BRA;
}

EvalObj::EvalObj(int _otype) : FrameObj(CLS_EVAL_OBJ), otype(_otype) {}

void EvalObj::prepare(Pair *pc) {}

bool EvalObj::is_simple_obj() {
    return otype & CLS_SIM_OBJ;
}

bool EvalObj::is_sym_obj() {
    return otype & CLS_SYM_OBJ;
}

bool EvalObj::is_opt_obj() {
    return otype & CLS_OPT_OBJ;
}

bool EvalObj::is_pair_obj() {
    return this != empty_list && (otype & CLS_PAIR_OBJ);
}


bool EvalObj::is_num_obj() {
    return otype & CLS_NUM_OBJ;
}

bool EvalObj::is_bool_obj() {
    return otype & CLS_BOOL_OBJ;
}

int EvalObj::get_otype() {
    return otype;
}

bool EvalObj::is_true() {
    return true;
}

string EvalObj::ext_repr() {
    hash.clear();
    // TODO: Performance improvement 
    // (from possibly O(n^2logn) to strictly O(nlogn))
    ReprCons **top_ptr = repr_stack; 
    *top_ptr++ = this->get_repr_cons();
    EvalObj *obj;
    hash.insert(this);
    while (!(*repr_stack)->done)
    {
        if ((*(top_ptr - 1))->done)
        {
            top_ptr -= 2;
            obj = (*top_ptr)->next((*(top_ptr + 1))->repr);
            if (obj)
            {
                *(++top_ptr) = obj->get_repr_cons();
                if (hash.count((*top_ptr)->ori))
                    *top_ptr = new ReprStr("#inf#");
            }
            else
            {
                hash.erase((*top_ptr)->ori);
                *top_ptr = new ReprStr((*top_ptr)->repr);
            }
        }
        else
        {
            top_ptr--;
            obj = (*top_ptr)->next("");
            if (obj)
            {
                *(++top_ptr) = obj->get_repr_cons();
                if (hash.count((*top_ptr)->ori))
                    *top_ptr = new ReprStr("#inf#");
            }
            else *top_ptr = new ReprStr((*top_ptr)->repr);
        }
        top_ptr++;
    }
    string &res = (*repr_stack)->repr;
    if (this->is_pair_obj())
        res = "(" + res + ")";
    return res;
}

Pair::Pair(EvalObj *_car, EvalObj *_cdr) : 
    EvalObj(CLS_PAIR_OBJ), car(_car), cdr(_cdr), 
    next(NULL) {}

    ReprCons *Pair::get_repr_cons() {
        return new PairReprCons(this, this);
    }

RetAddr::RetAddr(Pair *_addr) : FrameObj(CLS_RET_ADDR), addr(_addr) {}

ParseBracket::ParseBracket(unsigned char _btype) : 
    FrameObj(CLS_SIM_OBJ | CLS_PAR_BRA), btype(_btype) {}

    UnspecObj::UnspecObj() : EvalObj(CLS_SIM_OBJ) {}

    ReprCons *UnspecObj::get_repr_cons() { 
        return new ReprStr("#<Unspecified>");
    }

SymObj::SymObj(const string &str) : 
    EvalObj(CLS_SIM_OBJ | CLS_SYM_OBJ), val(str) {}

    ReprCons *SymObj::get_repr_cons() { 
        return new ReprStr(val); 
    }

OptObj::OptObj() : EvalObj(CLS_SIM_OBJ | CLS_OPT_OBJ) {}

ProcObj::ProcObj(Pair *_body, 
        Environment *_envt, 
        EvalObj *_params) :
    OptObj(), body(_body), params(_params), envt(_envt) {}

    Pair *ProcObj::call(ArgList *args, Environment * &genvt,
            Continuation * &cont, FrameObj ** &top_ptr) {
        // Create a new continuation
        // static_cast see `call` invocation in eval.cpp
        Pair *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr;
        Continuation *_cont = new Continuation(genvt, ret_addr, cont, body);
        // Create local env and recall the closure
        Environment *_envt = new Environment(envt);   
        // static_cast<SymObj*> because the params is already checked
        EvalObj *ppar, *nptr;
        for (ppar = params;
                ppar->is_pair_obj(); 
                ppar = TO_PAIR(ppar)->cdr)
        {
            if ((nptr = args->cdr) != empty_list)
                args = TO_PAIR(nptr);
            else break;
            _envt->add_binding(static_cast<SymObj*>(TO_PAIR(ppar)->car), args->car);
        }

        if (ppar->is_sym_obj())
            _envt->add_binding(static_cast<SymObj*>(ppar), args->cdr); // (... . var_n)
        else if (args->cdr != empty_list || ppar != empty_list)
            throw TokenError("", RUN_ERR_WRONG_NUM_OF_ARGS);

        genvt = _envt;
        cont = _cont;                   
        *top_ptr++ = new RetAddr(NULL);   // Mark the entrance of a cont
        return body;                    // Move pc to the proc entry point
    }

ReprCons *ProcObj::get_repr_cons() { 
    return new ReprStr("#<Procedure>"); 
}

SpecialOptObj::SpecialOptObj(string _name) : OptObj(), name(_name) {}

BoolObj::BoolObj(bool _val) : EvalObj(CLS_SIM_OBJ | CLS_BOOL_OBJ), val(_val) {}

bool BoolObj::is_true() { return val; }

ReprCons *BoolObj::get_repr_cons() { 
    return new ReprStr(val ? "#t" : "#f"); 
}

BoolObj *BoolObj::from_string(string repr) {
    if (repr.length() != 2 || repr[0] != '#') 
        return NULL;
    if (repr[1] == 't')
        return new BoolObj(true);
    else if (repr[1] == 'f')
        return new BoolObj(false);
    return NULL;
}

NumObj::NumObj(NumLvl _level, bool _exactness) : 
    EvalObj(CLS_SIM_OBJ | CLS_NUM_OBJ), exactness(_exactness), level(_level) {}

    bool NumObj::is_exact() { return exactness; }

    StrObj::StrObj(string _str) : EvalObj(CLS_SIM_OBJ | CLS_STR_OBJ), str(_str) {}

    ReprCons *StrObj::get_repr_cons() { 
        return new ReprStr(str); 
    }

CharObj::CharObj(char _ch) : EvalObj(CLS_SIM_OBJ | CLS_CHAR_OBJ), ch(_ch) {}

CharObj *CharObj::from_string(string repr) {
    size_t len = repr.length();
    if (len < 2) return NULL;
    if (repr[0] != '#' || repr[1] != '\\') return NULL;
    if (len == 3) return new CharObj(repr[2]);
    string char_name = repr.substr(2, len - 2);
    if (char_name == "newline") return new CharObj('\n');
    if (char_name == "space") return new CharObj(' ');
    throw TokenError(char_name, RUN_ERR_UNKNOWN_CHAR_NAME);
}

ReprCons *CharObj::get_repr_cons() {
    string val = "";
    if (ch == ' ') val = "space";
    else if (ch == '\n') val = "newline";
    else val += ch;
    return new ReprStr("#\\" + val);
}

VecObj::VecObj() : EvalObj(CLS_SIM_OBJ | CLS_VECT_OBJ) {}

EvalObj *VecObj::get_obj(int idx) {
    return vec[idx];
}

size_t VecObj::get_size() { 
    return vec.end() - vec.begin();
}

void VecObj::resize(int new_size) {
    vec.resize(new_size);
}

void VecObj::push_back(EvalObj *new_elem) {
    vec.push_back(new_elem);
}

ReprCons *VecObj::get_repr_cons() {
    return new VectReprCons(this, this);
}

StrObj *StrObj::from_string(string repr) {
    size_t len = repr.length();
    if (repr[0] == '\"' && repr[len - 1] == '\"')
        return new StrObj(repr.substr(1, len - 2));
    return NULL;
}

BuiltinProcObj::BuiltinProcObj(BuiltinProc f, string _name) :
    OptObj(), handler(f), name(_name) {}

    Pair *BuiltinProcObj::call(ArgList *args, Environment * &envt,
            Continuation * &cont, FrameObj ** &top_ptr) {

        Pair *ret_addr = static_cast<RetAddr*>(*top_ptr)->addr;
        *top_ptr++ = handler(TO_PAIR(args->cdr), name);
        return ret_addr->next;          // Move to the next instruction
    }

ReprCons *BuiltinProcObj::get_repr_cons() { 
    return new ReprStr("#<Builtin Procedure: " + name + ">");
}

Environment::Environment(Environment *_prev_envt) : prev_envt(_prev_envt) {}

bool Environment::add_binding(SymObj *sym_obj, EvalObj *eval_obj, bool def) {
    bool has_key = binding.count(sym_obj->val);
    if (!def && !has_key) return false;
    binding[sym_obj->val] = eval_obj;
    return true;
}

EvalObj *Environment::get_obj(EvalObj *obj) {
    if (!obj->is_sym_obj()) return obj;
    SymObj *sym_obj = static_cast<SymObj*>(obj);

    string name(sym_obj->val);
    for (Environment *ptr = this; ptr; ptr = ptr->prev_envt)
    {
        bool has_key = ptr->binding.count(name);
        if (has_key) return ptr->binding[name];
    }
    // Object not found
    throw TokenError(name, RUN_ERR_UNBOUND_VAR);
}

Continuation::Continuation(Environment *_envt, Pair *_pc, 
        Continuation *_prev_cont, 
        Pair *_proc_body) : 
    prev_cont(_prev_cont), envt(_envt), pc(_pc), 
    proc_body(_proc_body) {}

    ReprCons::ReprCons(bool _done, EvalObj *_ori) : ori(_ori), done(_done) {}
    ReprStr::ReprStr(string _repr) : ReprCons(true) { repr = _repr; }
    EvalObj *ReprStr::next(const string &prev) {
        throw NormalError(INT_ERR);
    }

PairReprCons::PairReprCons(Pair *_ptr, EvalObj *_ori) : 
    ReprCons(false, _ori), state(0), ptr(_ptr) {}

    EvalObj *PairReprCons::next(const string &prev) {
        repr += prev;
        EvalObj *res;
        if (state == 0)
        {
            state = 1;
            res = TO_PAIR(ptr)->car;
            if (res->is_pair_obj()) 
                repr += "(";
            return res;
        }
        else if (state == 1)
        {   
            state = 2;
            if (TO_PAIR(ptr)->car->is_pair_obj()) 
                repr += ")";
            ptr = TO_PAIR(ptr)->cdr;
            if (ptr == empty_list)
                return NULL;
            repr += " ";
            if (ptr->is_simple_obj())
                repr += ". ";
            return ptr;
        }
        else 
        {
            return NULL;
        }
    }

VectReprCons::VectReprCons(VecObj *_ptr, EvalObj *_ori) :
    ReprCons(false, _ori), ptr(_ptr), idx(0) { repr = "#("; }

    EvalObj *VectReprCons::next(const string &prev) {
        repr += prev;

        if (idx && ptr->get_obj(idx - 1)->is_pair_obj())
            repr += ")";

        if (idx == ptr->get_size())
        {
            repr += ")";
            return NULL;
        }
        else 
        {
            if (idx) repr += " ";
            EvalObj *res = ptr->get_obj(idx++);
            if (res->is_pair_obj())
                repr += "(";
            return res;
        }
    }

bool is_list(Pair *ptr) {
    if (ptr == empty_list) return true;
    EvalObj *nptr;  
    for (;;)  
        if ((nptr = ptr->cdr)->is_pair_obj())  
            ptr = TO_PAIR(nptr);  
        else break;  
    return ptr->cdr == empty_list;
}