// ---------------------------------------------------------------------------
// - Predicate.cpp                                                           -
// - afnix engine - predicate builtin functions implementation               -
// ---------------------------------------------------------------------------
// - This program is free software;  you can redistribute it  and/or  modify -
// - it provided that this copyright notice is kept intact.                  -
// -                                                                         -
// - This program  is  distributed in  the hope  that it will be useful, but -
// - without  any  warranty;  without  even   the   implied    warranty   of -
// - merchantability or fitness for a particular purpose.  In no event shall -
// - the copyright holder be liable for any  direct, indirect, incidental or -
// - special damages arising in any way out of the use of this software.     -
// ---------------------------------------------------------------------------
// - copyright (c) 1999-2008 amaury darsch                                   -
// ---------------------------------------------------------------------------

#include "Set.hpp"
#include "Byte.hpp"
#include "Real.hpp"
#include "Cons.hpp"
#include "List.hpp"
#include "Enum.hpp"
#include "Item.hpp"
#include "Heap.hpp"
#include "Queue.hpp"
#include "Regex.hpp"
#include "Plist.hpp"
#include "Buffer.hpp"
#include "Thread.hpp"
#include "Vector.hpp"
#include "BitSet.hpp"
#include "Logger.hpp"
#include "Symbol.hpp"
#include "Options.hpp"
#include "Lexical.hpp"
#include "Condvar.hpp"
#include "Relatif.hpp"
#include "Builtin.hpp"
#include "Boolean.hpp"
#include "Promise.hpp"
#include "Closure.hpp"
#include "Resolver.hpp"
#include "Instance.hpp"
#include "Exception.hpp"
#include "Character.hpp"
#include "HashTable.hpp"
#include "Qualified.hpp"
#include "Librarian.hpp"
#include "PrintTable.hpp"

namespace afnix {

  // nilp: nilp predicate

  Object* builtin_nilp (Runnable* robj, Nameset* nset, Cons* args) {
    if (args == nilp) return new Boolean (true);
    if (args->length () != 1) 
      throw Exception ("argument-error","too many arguments with nil-p");
    Object* car = args->getcar ();
    Object* obj = (car == nilp) ? nilp : car->eval (robj,nset);
    if (obj == nilp) return new Boolean (true);
    return new Boolean (false);
  }

  // this procedure checks that we have one argument only and returns
  // the evaluated object
  static inline Object* get_obj (Runnable* robj, Nameset* nset, Cons* args,
				 const String& pname) {
    if ((args == nilp) || (args->length () != 1))
      throw Exception ("argument-error", "illegal arguments with predicate",
		       pname);
    Object* car = args->getcar ();
    Object* obj = (car == nilp) ? nilp : car->eval (robj,nset);
    return obj;
  }

  // evlp: eval predicate

  Object* builtin_evlp (Runnable* robj, Nameset* nset, Cons* args) {
    try {
      Object* obj = get_obj (robj, nset, args, "eval-p");
      Object::cref (obj);
      return new Boolean (true);
    } catch (Exception&) {
      return new Boolean (false);
    }
  }

  // symp: symbol predicate

  Object* builtin_symp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "symbol-p");
    bool result = (dynamic_cast <Symbol*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // lexp: lexical predicate

  Object* builtin_lexp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "lexical-p");
    bool result = (dynamic_cast <Lexical*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // setp: set predicate

  Object* builtin_setp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "set-p");
    bool result = (dynamic_cast <Set*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // clop: closure predicate

  Object* builtin_clop (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "closure-p");
    bool result = (dynamic_cast <Closure*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // quap: qualified predicate

  Object* builtin_qualp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "qualified-p");
    bool result = (dynamic_cast <Qualified*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // intp: integer predicate

  Object* builtin_intp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "integer-p");
    bool result = (dynamic_cast <Integer*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // rltp: relatif predicate

  Object* builtin_rltp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "relatif-p");
    bool result = (dynamic_cast <Relatif*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // bytep: byte predicate

  Object* builtin_bytep (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "byte-p");
    bool result = (dynamic_cast <Byte*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // realp: real predicate

  Object* builtin_realp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "real-p");
    bool result = (dynamic_cast <Real*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // nump: number predicate

  Object* builtin_nump (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "number-p");
    if (dynamic_cast <Integer*> (obj) != nilp) {
      Object::cref (obj);
      return new Boolean (true);
    }
    bool result = (dynamic_cast <Real*> (obj) != nilp) ? true : false;
    Object::cref (obj);
    return new Boolean (result);
  }
  
  // boolp: boolean predicate

  Object* builtin_boolp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "boolean-p");
    bool result = (dynamic_cast <Boolean*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // charp: character predicate

  Object* builtin_charp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "character-p");
    bool result = (dynamic_cast <Character*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }
  
  // strp: string predicate

  Object* builtin_strp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "string-p");
    bool result = (dynamic_cast <String*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }
  
  // litp: literal predicate

  Object* builtin_litp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "literal-p");
    bool result = (dynamic_cast <Literal*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // bufp: buffer predicate

  Object* builtin_bufp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "buffer-p");
    bool result = (dynamic_cast <Buffer*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }
   
  // vecp: vector predicate

  Object* builtin_vecp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "vector-p");
    bool result = (dynamic_cast <Vector*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // consp: cons predicate

  Object* builtin_consp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "cons-p");
    bool result = (dynamic_cast <Cons*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // listp: cons predicate

  Object* builtin_listp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "list-p");
    bool result = (dynamic_cast <List*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }
  
  // nstp: nameset predicate

  Object* builtin_nstp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "nameset-p");
    bool result = (dynamic_cast <Nameset*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // prmp: promise predicate

  Object* builtin_prmp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "promise-p");
    bool result = (dynamic_cast <Promise*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // lbrnp: librarian predicate

  Object* builtin_lbrnp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "librarian-p");
    bool result = (dynamic_cast <Librarian*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // clsp: class predicate

  Object* builtin_clsp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "class-p");
    bool result = (dynamic_cast <Class*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // instp: instance predicate

  Object* builtin_instp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "instance-p");
    bool result = (dynamic_cast <Instance*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // ashp: hash table predicate

  Object* builtin_ashp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "hashtable-p");
    bool result = (dynamic_cast <HashTable*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // thrp: thread predicate

  Object* builtin_thrp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "thread-p");
    bool result = (dynamic_cast <Thread*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // logp: logger predicate

  Object* builtin_logp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "logger-p");
    bool result = (dynamic_cast <Logger*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // hashp: hash table predicate

  Object* builtin_hashp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "hash-p");
    bool result = (dynamic_cast <HashTable*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // heapp: heap predicate

  Object* builtin_heapp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "heap-p");
    bool result = (dynamic_cast <Heap*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // enump: enum predicate

  Object* builtin_enump (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "enum-p");
    bool result = (dynamic_cast <Enum*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // itemp: item predicate

  Object* builtin_itemp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "enum-p");
    bool result = (dynamic_cast <Item*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // queuep: queue predicate

  Object* builtin_queuep (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "queue-p");
    bool result = (dynamic_cast <Queue*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // bitset predicate

  Object* builtin_bitsp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "bitset-p");
    bool result = (dynamic_cast <BitSet*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // condvar predicate

  Object* builtin_condp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "condvar-p");
    bool result = (dynamic_cast <Condvar*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // regex predicate

  Object* builtin_regexp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "regex-p");
    bool result = (dynamic_cast <Regex*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // resolver predicate

  Object* builtin_rslvp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "resolver-p");
    bool result = (dynamic_cast <Resolver*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }  

  // print-table predicate

  Object* builtin_ptblp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "print-table-p");
    bool result = (dynamic_cast <PrintTable*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // property predicate

  Object* builtin_propp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "property-p");
    bool result = (dynamic_cast <Property*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }

  // plist predicate

  Object* builtin_plistp (Runnable* robj, Nameset* nset, Cons* args) {
    Object* obj = get_obj (robj, nset, args, "plist-p");
    bool result = (dynamic_cast <Plist*> (obj) == nilp) ? false : true;
    Object::cref (obj);
    return new Boolean (result);
  }
}
