Geoffrey Broadwell a écrit :
On Mon, 2008-07-21 at 09:34 +0200, François Perrad wrote:
Geoffrey Broadwell a écrit :
fperrad: How do these bindings actually work?
There'll work with runtime/parrot/library/OpenGL.pir.

OK ... so what could be improved about runtime/parrot/library/OpenGL.pir
so that you didn't have to write any bindings at all, or so that your
bindings could be greatly simplified?  So far, I'm seeing the following:

Ok, talking about libraries :
Lua compiler & Lua Standard Libraries are complete (as far as the current Parrot supports it).
So, since April 2008, I wrote some extension libraries for Lua :
- lua/src/lib/base64.pir : wrapper over library/MIME/Base64.pir
- lua/src/lib/bc.pir : big number library, currently over the PMC BigInt (waiting for BigFloat)
- lua/src/lib/bitlib.pir : bitwise operation library, pure PIR
- lua/src/lib/lfs.pir : Lua File System library, over the PMC OS (still incomplete) - lua/src/lib/md5.pir & sha1.pir : wrapper over PMC MD5 & SHA1 (I wrote them on the outside of Lua) - lua/src/lib/random.pir : wrapper over library/Math/Random/mt19937ar.pir (I wrote it on the outside of Lua) - lua/src/lib/uuid.pir : wrapper over library/uuid.pir (I wrote it on the outside of Lua) Since mid-June 2008, I tried to write extension libraries for Pipp (PHP supplies more than 2500 functions !!!, huge work, but I believe that PHP could be the killer application for Parrot) : - pipp/src/common/php_API.pir & php_MACRO.pir : some helpers (argument checking) - pipp/src/common/php_base64.pir : wrapper over library/MIME/Base64.pir (but incomplete because PHP API has more options than MIME/Base64 Perl API)
- pipp/src/common/php_ctype.pir : pure PIR
- pipp/src/common/php_gmp.pir : started over PMC BigInt, but needs a full NCI binding over gmp
- pipp/src/common/php_math.pir : pure PIR
- pipp/src/common/php_md5.pir & sha1.pir : wrapper over PMC MD5 & SHA1
- pipp/src/common/php_pcre.pir : wrapper over library/pcre.pir (incomplete because no PhpArray support, and the NCI PCRE is incomplete and seems very old) - pipp/src/common/php_rand.pir : wrapper over PMC Random & library/Math/Random/mt19937ar.pir
- pipp/src/common/php_type.pir : pure PIR
As I need to write a NCI wrapper over gmp, I begin my study of NCI by using the OpenGL one (with Lua).

If I try to summarize my experiment with libraries :
Parrot will supply 3 kinds of common libraries for HLL
- written in Perl6, but currently not available (I don't know if NQP is suitable for writing library) - written in PIR, but only for bootstrap, because as Bernhard Schmalhofer tell "PIR is not a decent language"
   + good for libraries not common (in fact equivalent to builtins)
       - lua/src/lib/bitlib.pir
       - lua/src/lib/lfs.pir
       - pipp/src/common/php_ctype.pir
       - pipp/src/common/php_math.pir
       - pipp/src/common/php_type.pir
+ good when no native library available (but a full test suite is needed)
       - library/Math/Random/mt19937ar.pir (Mersenne Twisted)
- binding over native (C/C++) shared libraries
   + with native PMC (C compile/link)
- sometime, for security reason, a static linkage is mandatory (libssl is shared lib, but its subset libcrypto is static lib)
      - other advantage, PMC allows direct OO interface
   + with NCI : the best way (no C compile/link)
      - but only procedural interface (no direct OO)

2 designs choices :
- For long term maintenance, I write PIR close to original C. For example, I start Lua on Parrot aligned with version 5.0.2 and now it's 5.1.3. And in most of case, the original C is the only valid (updated) user & requirements documentation. - I try to emit the same (as possible) error or warning messages than the original implementation and to have the same interface. Rule of Least Surprise for the end user. And I could run the test suite against the original implementation.

Now, talking about Lua specifics :
- Lua Tables are the main (and the only) structured type in Lua, they supply array & hash (like PHP array).
They are used to supply the namespace support and the OO mecanism.
There are no keyword for namespace.
Standard Libraries & others live in their table (ie namespace).
So, in the init function of a library, I wrote (or generate) some boring code like :
   .const .Sub _mod_funct = 'func'
   _mod_func.'setfenv'(_lua__GLOBAL)
   set $P1, 'func'
   _mod[$P1] = _mod_func
I wait for a IMCC improvement (hi kjs) in order to support :
        .macro register(tname, fname)
            .const .Sub $fname = .fname
            $fname.'setfenv'(_lua__GLOBAL)
            set $P1, .fname
            .tname[$P1] = $fname
        .endm

- Currently, the LuaTable implementation don't support the Parrot namespaces API. But I think it's doable.

- Since my first implementation, libraries & generated code use the 2 same patterns for function preamble :
.sub 'func_with_vararg' : anon
   .param pmc arg1 :optional
   .param pmc argn :optional
   .param pmc vararg :slurpy
   ...
.sub 'func_without_vararg' :anon
   .param pmc arg1 :optional
   .param pmc argn :optional
   .param pmc extra :slurpy   # ignore silently extra parameters
   ...
After parameters are checked by helpers that could perform some type conversion (to_number, to_string, ...
) and eventually a default value support.
I could do the job with :optional, and without any :opt_flag.
It's a old design choice, perhaps now :opt_flag is better.

All that I do in a binding for Lua, I already did it in the whole Lua.
Now, I expect two things of Parrot :
1) for language interoperability :
an automatic conversion between LuaString & PhpString (if they are defined with "does string maps String").
  problems come with LuaTable (with array & hash part) and Perl6Hash
2) thin NCI binding for all native shared libraries (gmp, GD, OpenGL, MySQL, ...)
  I think this layer doesn't add functionality or behavior.
  With generated code from .h
  Specific OSes  path search hidden
A way to import all methods in my namespace, without get_global or get_hll_global for each symbol.

If NCI binding is thin, it could be common & reusable for each HLL.
But in other hand, each HLL needs a specific layer with its specific argument checking.

When you study wrappers in C interpreters, there are thin. It's just glue (generated or not) for building a bridge between languages. And this glue depends more on target interpreter than on library wrapped. SWIG is a well-known tool, but I wrote a obscure Perl module CORBA::Python that generates C/Python API from IDL file. For example, wxPerl & wxPython include both a thin wrapper over wxWidget. Now, wxPython package is better than wxPerl, because the wxPython community is larger and adds functionalities in pure Python modules. In early version, wxPython allows only calling convention close to C++ one, now current versions are more pythonic (named parameter, ...). It's done in Python. In the same way, when you write a Perl 5 extension, the XS part is minimum, the perlish interface or OO interface is written in a .pm file.

I think argument type checking & conversion are HLL specific. This layer could be written in PIR or in HLL (when checking subroutines are callable from HLL). Currently, in Pipp, PIR is the only way because the compiler is in early stage (but in progress). But this way is only valid for binding over shared libraries. PHP has many specific extension written in pure C, I think these extension must be rewrite in PHP (not a job for PIR). In Lua, PIR is available since the beginning, so with the time I become fluent in PIR.

Finally, improvement in runtime/parrot/library/OpenGL.pir :
at this time, just split the function '_export_all_functions' into '_export_GL_functions' & '_export_GLUT_functions'.

François.
1. HLL access to the GL constants.  At the very least, you should
   already be able to define your constant table using the generated
   constants in runtime/parrot/include/opengl_defines.pasm, rather than
   having to hardcode them all.  Even better, this should all be wrapped
   up in an HLL-friendly way for you, but I've been looking for
   suggestions on how best to do that in a cross-HLL manner.

2. Namespace unflattening (glFoo -> gl.Foo, glutBar -> glut.Bar).  That
   should be easy for runtime/parrot/library/OpenGL.pir to do, but may
   not be valuable to you if you already have to do everything else
   below.

3. All subs are marked :anon, and then manually added into a global
   LuaTable which appears to be reimplementing a namespace.  Why?  And
   if all Lua namespaces are created this way, does LuaTable implement
   enough of the Parrot namespace API that other HLLs will be able to
   work with Lua-implemented modules?

4. Ignore extra args to each function (which I'm just guessing is the
   purpose of the '.param pmc extra :slurpy' on every sub).  Why do
   you want to do this?

5. All params are marked :optional (but don't have matching :opt_flag
   params) and seem required by the code.  Again, why do this?

6. Argument type checking and conversion.  This appears to be the "real"
   problem, though this seems like the exact kind of problem that Parrot
   was supposed to make easier for us.  If you have to manually wrap
   every function in a cross-language library in every HLL because
   Parrot won't Do The Right Thing, that seems like a design flaw.

7. Simplified wrappers around some common functions.  I've been thinking
   about creating some of these (most OpenGL wrappers for scripting
   languages seem to do this, to a greater or lesser degree).  Whether
   it is worth it to try to do this in runtime/parrot/library/OpenGL.pir
   depends on how many HLL implementors are trying to get exact ports
   of existing bindings in the original (non-parrot) implementation of
   their language, and how many would be willing to share a common
   simplified binding.

Anything else I'm missing?


-'f

Reply via email to