cesanta / v7

Embedded JavaScript engine for C/C++
Other
1.42k stars 177 forks source link

Script BASIC #573

Closed ScriptBasic closed 7 years ago

ScriptBasic commented 7 years ago

I think the problems I'm having with Script BASIC and V7 is that SB only supports LONG, DOUBLE, ARRAYS (index & associative) and STRINGS (C str & binary) As you say, I got lucky with a SB 64 bit long and v7_val_t on Umuty 64 bit. It's a shame we couldn't connect on Windows. I might give Script BASIC 64 bit Windows another try.

mkmik commented 7 years ago

please consider wrapping the v7_val_t in a memory block passed by reference:

v7_val_t *vp = (v7_val_t *) malloc(sizeof(v7_val_t));
*vp = result;
besRETURN_LONG(vp);

then, when you need to access that val_t again in another C function invoked by Basic you just need to make sure you interpret the argument as v7_val_t *p and you dereference it when you pass it to V7 API.

ScriptBasic commented 7 years ago

That's a cool idea! I'll give it a shot and let you know if it works. When you say dereference vp, do mean free it?

mkmik commented 7 years ago

no, I mean *vp.

Obviously you have to free it as well, but that's a different problem. Which might not be easy.

A better trick is to pack a 64-bit value in a double:

union dv { 
  double d;
  v7_val_t v;
} ;

double val_to_double(v7_val_t v) {
  union dv dv;
  dv.v = v;
  return dv.d;
}

v7_val_t double_to_val(double d) {
  union dv dv;
  dv.d = d;
  return dv.v;
}

.....
besRETURN_DOUBLE(val_to_double(result));
....
mkmik commented 7 years ago

which btw is exactly what we do internally in V7. The V7 values are actually encoded as double floating point numbers, by exploiting the encoding of NaN (not a number) values: see https://docs.cesanta.com/v7/master/#/v7-internals/nan-packing.md/

ScriptBasic commented 7 years ago

Derefencing and freeing is handled by the SB extension API.

I like the conversion method you used. Much cleaner.

I think this might work.

mkmik commented 7 years ago

I strongly suggest you use the val_to_double/double_to_val approach; handling pointers and memory allocations in C is notoriously hard to debug.

ScriptBasic commented 7 years ago

I tried to get things working with the conversion routines but I'm having some issues with type casting. I attached the Script BASIC interfacer.c and output from the makefile compile. Can you take a peek and see what I'm doing wrong? sbv7.zip

mkmik commented 7 years ago

I didn't review the whole thing, I stopped here:

  DIM AS double boolptr;
  DIM AS int istrue;
  besARGUMENTS("ii")
    AT v7, AT istrue
  besARGEND
  boolptr = v7_mk_boolean(v7, istrue);
  besRETURN_DOUBLE(JS2Double(boolptr));

you're incorrectly assigning a v7_val_t into a variable of type double (with a confusing name of boolptr btw).

v7_mk_boolean returns a v7_val_t and if you want to convert it properly to a boolean you need to do it via the JS2Double function you have at the beginning of your file.

Automatic C conversion as in double foo = v7_mk_boolean(....) doesn't work, because it will try to represent a 64-bit integer as floating point number (i.e. converting integer to a floating point representation of the same numerical value). While the trick done by JS2Double is to store the exact same bit pattern in a double variable which is 64-bit on every platform and thus can be passed around by your BASIC interpreter and later be converted back to a 64-bit integer.

Thus it should be:

  DIM AS v7_val_t boolval;
  DIM AS int istrue;
  besARGUMENTS("ii")
    AT v7, AT istrue
  besARGEND
  boolval = v7_mk_boolean(v7, istrue);
  besRETURN_DOUBLE(JS2Double(boolval));

Another very basic issue I found is:

besFUNCTION(js_get_bool)
  DIM AS unsigned long v7;
  DIM AS double boolptr;
  DIM AS int truefalse;
  besARGUMENTS("ii")
    AT v7, AT truefalse
  besARGEND
  truefalse = v7_get_bool(v7, Double2JS(boolptr));
  besRETURN_LONG(truefalse);
besEND

Here you're just confusing input and output variables.

Which should obviously be:

besFUNCTION(js_get_bool)
  DIM AS unsigned long v7;
  DIM AS double boolval;
  DIM AS long truefalse;
  besARGUMENTS("ir")
    AT v7, AT boolval
  besARGEND
  truefalse = v7_get_bool(v7, Double2JS(boolval));
  besRETURN_LONG(truefalse);
besEND

I didn't look at any further issues, especially since you didn't describe where to look in particular.

I suggest you focus more and use more care when programming; that's the path to success. Otherwise, you'll not only have serious trouble making this work, but you will also make people less likely to help you again.

I suggest you read a good book about C, for example "The C Programming Language (Second Edition)" by Brian Kernighan and Dennis Ritchie.

ScriptBasic commented 7 years ago

I changed all the double's to v7_val_t types but still getting errors.

You are using non-standard variable types and your documentation sucks. I'm trying to get through this and don't need the "read a beginner's C book". The references to ptr were early on in the program definition before unrevealing the mysteries behind the code.

C:\sbgcc\source\extensions\js>mingw32-make -B                                                                   
gcc -w -D_WIN32 -m32 -ggdb -c -o ..\..\bin\mod\obj\js\s_interface.o interface.c                                 
interface.c: In function 'js_own':                                                                              
interface.c:219:24: error: incompatible type for argument 1 of 'Double2JS'                                      
   v7_own(v7, Double2JS(&cvar));                                                                                
                        ^                                                                                       
interface.c:56:17: note: expected 'double' but argument is of type 'v7_val_t ** {aka long long unsigned int **}'
 static v7_val_t Double2JS(double d) {                                                                          
                 ^                                                                                              
interface.c: In function 'js_disown':                                                                           
interface.c:230:35: error: incompatible type for argument 1 of 'Double2JS'                                      
   found = v7_disown(v7, Double2JS(&cvar));                                                                     
                                   ^                                                                            
interface.c:56:17: note: expected 'double' but argument is of type 'v7_val_t ** {aka long long unsigned int **}'
 static v7_val_t Double2JS(double d) {                                                                          
                 ^                                                                                              
interface.c: In function 'js_get_string':                                                                       
interface.c:453:39: error: incompatible type for argument 1 of 'Double2JS'                                      
   sbstr = v7_get_string(v7, Double2JS(&resultptr), NULL);                                                      
                                       ^                                                                        
interface.c:56:17: note: expected 'double' but argument is of type 'v7_val_t * {aka long long unsigned int *}'  
 static v7_val_t Double2JS(double d) {                                                                          
                 ^                                                                                              
interface.c: In function 'js_get_cstring':                                                                      
interface.c:465:40: error: incompatible type for argument 1 of 'Double2JS'                                      
   sbcstr = v7_get_string(v7, Double2JS(&cstrptr), &cstrlen);                                                   
                                        ^                                                                       
interface.c:56:17: note: expected 'double' but argument is of type 'v7_val_t * {aka long long unsigned int *}'  
 static v7_val_t Double2JS(double d) {                                                                          
                 ^                                                                                              
interface.c: In function 'js_apply':                                                                            
interface.c:705:92: error: incompatible type for argument 1 of 'Double2JS'                                      
     rtncode = v7_apply(v7, Double2JS(funcptr), V7_UNDEFINED, Double2JS(argsptr), Double2JS(&result));          
                                                                                            ^                   
interface.c:56:17: note: expected 'double' but argument is of type 'v7_val_t * {aka long long unsigned int *}'  
 static v7_val_t Double2JS(double d) {                                                                          
                 ^                                                                                              
interface.c:707:97: error: incompatible type for argument 1 of 'Double2JS'                                      
     rtncode = v7_apply(v7, Double2JS(funcptr), Double2JS(objptr), Double2JS(argsptr), Double2JS(&result));     
                                                                                                 ^              
interface.c:56:17: note: expected 'double' but argument is of type 'v7_val_t * {aka long long unsigned int *}'  
 static v7_val_t Double2JS(double d) {                                                                          
                 ^                                                                                              
Makefile:17: recipe for target 'bin\mod\obj\js\s_interface.o' failed                                            
mingw32-make: *** [bin\mod\obj\js\s_interface.o] Error 1                                                        

C:\sbgcc\source\extensions\js>