# Copyright (C) 2008, Parrot Foundation. # vkon =head1 TITLE TclLibrary.pir - NCI interface to Tcl language (http://www.tcl.tk) =head1 DESCRIPTION This module implements Tcl/Tk interface for Parrot. =head1 TODO =over 2 =item Tcl_GetStringFromObj - check its declaration and usage func = dlfunc libtcl, "Tcl_GetStringFromObj", "tpp" # should be "tp3" =back =cut .include "hllmacros.pir" .include "datatypes.pasm" .namespace ['TclLibrary'] # derived from tcl.h: .const int TCL_OK = 0 .const int TCL_ERROR = 1 .const int TCL_RETURN = 2 .const int TCL_BREAK = 3 .const int TCL_CONTINUE = 4 # DEBUG .const int debug_objresult = 1 # .sub eval :method .param string str .local string res, error .local pmc f_evalex, f_getobjresult, f_getstringresult, f_resetresult f_resetresult = get_global '_tcl_resetresult' f_evalex = get_global '_tcl_evalex' f_getobjresult = get_global '_tcl_getobjresult' f_getstringresult = get_global '_tcl_getstringresult' .local pmc interp interp = getattribute self,'interp' f_resetresult(interp) .local int rc rc = f_evalex(interp,str,-1,0) # interp, string, length or -1, flags # check if the result is TCL_OK(=0) if rc==TCL_OK goto eval_ok res = f_getstringresult(interp,0) error = "error during Tcl_EvalEx: " . res die error eval_ok: # get the result (list result, etc - TBD) .IfElse(debug_objresult==1,{ .local pmc obj obj = f_getobjresult(interp,0) .local pmc tcl_obj_decl tcl_obj_decl = get_global '_tcl_obj_decl' # retrieve tcl_obj structure assign obj, tcl_obj_decl # ... and use it res = _pmc_from_tclobj(interp,obj) },{ res = f_getstringresult(interp,0) }) .return(res) .end # Constructor for the interpreter object. # optional parameter - path to the tcl shared library. .sub init :method :vtable .param string libname :optional .param int has_libname :opt_flag # get interpreter, store it globally .local pmc interp, f_createinterp, f_tclinit .local pmc libtcl libtcl = get_global '_libtcl' # if _libtcl not defined yet, then we're starting first time, so need # to call _tcl_load_lib unless_null libtcl, libtcl_loaded if has_libname goto with_libname '_tcl_load_lib'() goto with_libname_e with_libname: '_tcl_load_lib'(libname) with_libname_e: libtcl = get_global '_libtcl' libtcl_loaded: f_createinterp = dlfunc libtcl, "Tcl_CreateInterp", "p" interp = f_createinterp() unless_null interp, ok_interp die "NO interp\n" ok_interp: setattribute self,'interp', interp f_tclinit = dlfunc libtcl, "Tcl_Init", "vp" f_tclinit(interp) .end =over 4 =item _init Performs the initialization of Tcl bridge, namely instantiates TclLibrary class =cut .sub _init :load :init .local pmc tclclass tclclass = newclass ['TclLibrary'] addattribute tclclass, 'interp' .end =item _init_tclobj - creates a helper for Tcl_Obj struct # do the tcl.h adaptations =cut .sub _init_tclobj # "declare" a helper for Tcl_Obj structure # here is the definition of the Tcl_Obj struct # typedef struct Tcl_Obj { # int refCount; // When 0 the object will be freed. # char *bytes; // points to the first byte of the obj string representation... # int length; // number of bytes at *bytes, not incl.the term.null. # Tcl_ObjType *typePtr; // obj type. if NULL - no int.rep. # union { /* The internal representation: */ # long longValue; /* - an long integer value */ # double doubleValue; /* - a double-precision floating value */ # VOID *otherValuePtr; /* - another, type-specific value */ # Tcl_WideInt wideValue; /* - a long long value */ # struct { /* - internal rep as two pointers */ # VOID *ptr1; # VOID *ptr2; # } twoPtrValue; # struct { /* - internal rep as a wide int, tightly # * packed fields */ # VOID *ptr; /* Pointer to digits */ # unsigned long value;/* Alloc, used, and signum packed into a # * single word */ # } ptrAndLongRep; # } internalRep; # } Tcl_Obj; .local pmc tcl_obj_struct, tcl_obj_decl tcl_obj_decl = new 'ResizablePMCArray' push tcl_obj_decl, .DATATYPE_INT push tcl_obj_decl, 0 push tcl_obj_decl, 0 push tcl_obj_decl, .DATATYPE_CSTR push tcl_obj_decl, 0 push tcl_obj_decl, 0 push tcl_obj_decl, .DATATYPE_INT push tcl_obj_decl, 0 push tcl_obj_decl, 0 push tcl_obj_decl, .DATATYPE_INT push tcl_obj_decl, 0 push tcl_obj_decl, 0 # following items are for union, let it be 2 longs, which eventually # could be transformed to the required type push tcl_obj_decl, .DATATYPE_LONG push tcl_obj_decl, 2 push tcl_obj_decl, 0 # union TBD tcl_obj_struct = new 'UnManagedStruct', tcl_obj_decl set_global '_tcl_obj_decl', tcl_obj_decl # XXXXXXXXX <---------- .end # find proper shared library and use it. .sub _tcl_load_lib .param string libname :optional .param int has_libname :opt_flag # load shared library .local pmc libnames libnames = new 'ResizableStringArray' unless has_libname goto standard_names push libnames, libname say libname goto standard_names_e standard_names: push libnames, 'tcl85' push libnames, 'tcl84' push libnames, 'libtcl8.5' push libnames, 'libtcl8.4' push libnames, 'libtcl8.5.so' push libnames, 'libtcl8.4.so' standard_names_e: .local pmc libtcl libtcl = _load_lib_with_fallbacks('tcl', libnames) set_global '_libtcl', libtcl # initialize Tcl library .local pmc func_findexec func_findexec = dlfunc libtcl, "Tcl_FindExecutable", "vp" func_findexec(0) # few more functions, store them globally .local pmc func # need: Tcl_ResetResult, Tcl_EvalEx, Tcl_GetStringResult, etc func = dlfunc libtcl, "Tcl_ResetResult", "vp" set_global '_tcl_resetresult', func func = dlfunc libtcl, "Tcl_EvalEx", "iptii" set_global '_tcl_evalex', func func = dlfunc libtcl, "Tcl_GetStringFromObj", "tpp" # should be "tp3" set_global '_tcl_getstringfromobj', func func = dlfunc libtcl, "Tcl_GetStringResult", "tp" set_global '_tcl_getstringresult', func func = dlfunc libtcl, "Tcl_ListObjGetElements", "vippp" # should be "vip3p" set_global '_tcl_listobjgetelements', func func = dlfunc libtcl, "Tcl_GetObjResult", "pp" set_global '_tcl_getobjresult', func func = dlfunc libtcl, "Tcl_GetObjType", "it" set_global '_tcl_getobjtype', func '_init_tclobj'() .end # #static SV * #SvFromTclObj(pTHX_ Tcl_Obj *objPtr) =item pmc _pmc_from_tclobj(pmc interp, pmc tclobj) This is a (static) function that will convert Tcl object to pmc =cut .sub _pmc_from_tclobj .param pmc interp .param pmc tclobj # check what type this tcl obj is say "enter pmc_from_tclobj" # check what tclobj actually is (null, integer, list, etc) # ---> these lines will be factored out into some init stage! .... .local int tclBooleanTypePtr .local int tclByteArrayTypePtr .local int tclDoubleTypePtr .local int tclIntTypePtr .local int tclListTypePtr .local int tclStringTypePtr .local int tclWideIntTypePtr .local pmc f_getobjtype f_getobjtype = get_global '_tcl_getobjtype' tclBooleanTypePtr = f_getobjtype("boolean") tclByteArrayTypePtr = f_getobjtype("bytearray") tclDoubleTypePtr = f_getobjtype("double") tclIntTypePtr = f_getobjtype("int") tclListTypePtr = f_getobjtype("list") tclStringTypePtr = f_getobjtype("string") tclWideIntTypePtr = f_getobjtype("wideInt") # ..... <---- (see above) #.local pmc tcl_obj_struct #tcl_obj_struct = get_global '_tcl_obj_struct' if tclobj!=0 goto not_null # null say "NULL???" goto EOJ not_null: .local int obj_type obj_type = tclobj[3] if obj_type==0 goto EOJ # if obj_type is null, there's no internal rep if obj_type!=tclBooleanTypePtr goto m00 say "implement tclBooleanTypePtr!" goto EOJ m00: if obj_type!=tclByteArrayTypePtr goto m01 say "implement tclByteArrayTypePtr" goto EOJ m01: if obj_type!=tclDoubleTypePtr goto m02 #sv = newSViv(objPtr->internalRep.doubleValue); say "implement tclDoubleTypePtr" goto EOJ m02: if obj_type!=tclIntTypePtr goto m03 #sv = newSViv(objPtr->internalRep.longValue); .local int ires ires = tclobj[4] say ires .return(ires) m03: if obj_type!=tclListTypePtr goto m04 .local int objc .local pmc objv # pointer which will hold array of tcl_obj's # Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv); # if (objc) { .... } .local pmc f_listobjgetelements f_listobjgetelements = get_global '_tcl_listobjgetelements' #f_listobjgetelements.(0, tclobj, objc, objv) say "implement tclListTypePtr" goto EOJ m04: if obj_type!=tclStringTypePtr goto m05 say "implement tclStringTypePtr" goto EOJ m05: print "implement TCL obj_type " say obj_type EOJ: .local string str .local pmc f_getstr f_getstr = get_global '_tcl_getstringfromobj' str = f_getstr(tclobj, 0) .return(str) .end .sub MainLoop :method say "MainLoop" # TO BE FIXED self.'eval'(<<'EOS') while {[winfo exists .]} { update } EOS # .local pmc libtcl, f_mainloop # libtcl = get_global '_libtcl' # f_mainloop = dlfunc libtcl, "Tk_MainLoop", "v" # f_mainloop() say "MainLoop-e!" .end =item _load_lib_with_fallbacks(string friendly_name, pmc fallback_list) This function is more generally useful than just for this module -- it implements the search for a particular library that may appear under any of several different filenames. The C should be a simple array of strings, each naming one of the possible filenames, I the trailing shared library extension (e.g. C<.dll> or C<.so>). The C is only used to fill in the error message in case no match can be found on the system. BORROWED from OpenGL.pir - keep an eye on it (e.g. if it will be organized elsewhere - reuse it from there) =cut .sub _load_lib_with_fallbacks .param string friendly_name .param pmc fallback_list .local pmc list_iter list_iter = iter fallback_list .local string libname .local pmc library iter_loop: unless list_iter goto failed libname = shift list_iter library = loadlib libname unless library goto iter_loop loaded: print "tcl lib is " say libname .return (library) failed: .local string message message = 'Could not find a suitable ' message .= friendly_name message .= ' shared library!' die message .end =back =head1 SEE ALSO http://www.tcl.tk =head1 AUTHORS TBD =cut # Local Variables: # mode: pir # fill-column: 100 # End: # vim: expandtab shiftwidth=4 ft=pir: