Sunteți pe pagina 1din 10

Ring Documentation, Release 1.

BreakPoint()
see "After breakpoint!" +nl
see "t = " + t + nl
see "End of program!" + nl

Screen Shots:
We have the Interactive Debugger at the Breakpoint!

We can print the variables values

We can change the variables values then continue execution

69.9. Using the Interactive Debugger 793


Ring Documentation, Release 1.6

We can run the Interactive Debugger in the Output Window

69.9. Using the Interactive Debugger 794


CHAPTER

SEVENTY

EMBEDDING RING IN RING

In this chapter we will learn about embedding Ring in Ring programs and applications.

70.1 Embedding Ring in Ring without sharing the State

From Ring 1.0 we already have functions for embedding Ring in the C language. Also we can execute Ring code
inside Ring programs using the eval() function. In this release we provide functions for embedding Ring in Ring
programs without sharing the state.
Advantages:
1. Quick integration for Ring programs and applications together without conflicts.
2. Execute and run Ring code in safe environments that we can trace.
Example:
pState = ring_state_init()
ring_state_runcode(pState,"See 'Hello, World!'+nl")
ring_state_runcode(pState,"x = 10")

pState2 = ring_state_init()
ring_state_runcode(pState2,"See 'Hello, World!'+nl")
ring_state_runcode(pState2,"x = 20")

ring_state_runcode(pState,"see x +nl")
ring_state_runcode(pState2,"see x +nl")

v1 = ring_state_findvar(pState,"x")
v2 = ring_state_findvar(pState2,"x")

see v1[3] + nl
see V2[3] + nl

ring_state_delete(pState)
ring_state_delete(pState2)

Output:
Hello, World!
Hello, World!
10
20
10
20

795
Ring Documentation, Release 1.6

70.2 Serial Execution of Programs

We can execute application after another application using ring_state_main()


Example:
chdir(exefolder()+"/../applications/formdesigner")
ring_state_main('formdesigner.ring')
chdir(exefolder()+"/../applications/cards")
ring_state_main('cards.ring')

70.3 ring_state_setvar()

Using ring_state_setvar() we can set variables value


The value could be (String, Number, List or C Pointer)
We need this function to quickly pass lists and C pointers to the Sub Ring Environment
Syntax:
ring_state_setvar(oState,cVariableName,Value)

Example:
load "guilib.ring"

myapp = null
win = null

func main
myapp = new qApp {
win = new qWidget() {
setWindowTitle("Advanced Example on using ring_state_setvar()")
move(100,100)
resize(600,400)
new qPushButton(win) {
setText("Test")
setClickEvent("Test()")
}
# We need this because using load 'guilib.ring' in the sub environment
# Will create timers by Qt and closing the window will not be enough
# To close the application
oFilter = new qAllEvents(win)
oFilter.setCloseEvent("myapp.quit()")
win.installeventfilter(oFilter)
show()
}
exec()
}

func test
pState = ring_state_init()
ring_state_runcode(pstate,"load 'guilib.ring'")
ring_state_runcode(pState,"x = NULL")
# Pass String
ring_state_setvar(pState,"x","hello")

70.2. Serial Execution of Programs 796


Ring Documentation, Release 1.6

ring_state_runcode(pState,"? x")
# Pass Number
ring_state_setvar(pState,"x",100)
ring_state_runcode(pState,"? x")
# Pass List
ring_state_setvar(pState,"x",["one","two","three"])
ring_state_runcode(pState,"? x")
# Pass Object
# We can't pass the Ring Object (win)
# Because Objects store pointers to the Class Information
# And the class is related to the Parent Ring Environment
# And the sub Ring environment can't access it
# But we can pass C pointers like win.pObject
ring_state_setvar(pState,"x",win.pObject)
# Now we create the object again but using the same C pointer
# So we have access to the Same window in the parent Ring enviroment
ring_state_runcode(pState,"
new qWidget {
pObject = x
setwindowtitle('Message from the Sub Ring Environment')
}
")
ring_state_delete(pState)

70.3. ring_state_setvar() 797


CHAPTER

SEVENTYONE

EXTENSION USING THE C/C++ LANGUAGES

We can extend the Ring Virtual Machine (RingVM) by adding new functions written in the C programming language
or C++. The RingVM comes with many functions written in C that we can call like any Ring function.
We can extend the language by writing new functions then rebuilding the RingVM again, or we can create shared
library (DLL/So) file to extend the RingVM without the need to rebuild it.
The Ring language source code comes with two files to add new modules to the RingVM, ring_ext.h and ring_ext.c

71.1 ring_ext.h

The file ring_ext.h contains constants that we can change to include/exclude modules during the build process.
#ifndef ringext_h
#define ringext_h
/* Constants */
#define RING_VM_LISTFUNCS 1
#define RING_VM_REFMETA 1
#define RING_VM_MATH 1
#define RING_VM_FILE 1
#define RING_VM_OS 1
#define RING_VM_MYSQL 1
#define RING_VM_ODBC 1
#define RING_VM_OPENSSL 1
#define RING_VM_CURL 1
#define RING_VM_DLL 1
#endif

71.2 ring_ext.c

The file ring_ext.c check constants defined in ring_ext.h before calling the start-up function in each module.
Each module contains a function that register the module functions in the RingVM.
#include "ring.h"

void ring_vm_extension ( RingState *pRingState )


{
/* Reflection and Meta-programming */
#if RING_VM_REFMETA
ring_vm_refmeta_loadfunctions(pRingState);
#endif

798
Ring Documentation, Release 1.6

/* List Functions */
#if RING_VM_LISTFUNCS
ring_vm_listfuncs_loadfunctions(pRingState);
#endif
/* Math */
#if RING_VM_MATH
ring_vm_math_loadfunctions(pRingState);
#endif
/* File */
#if RING_VM_FILE
ring_vm_file_loadfunctions(pRingState);
#endif
/* OS */
#if RING_VM_OS
ring_vm_os_loadfunctions(pRingState);
#endif
/* MySQL */
#if RING_VM_MYSQL
ring_vm_mysql_loadfunctions(pRingState);
#endif
/* ODBC */
#if RING_VM_ODBC
ring_vm_odbc_loadfunctions(pRingState);
#endif
/* OPENSSL */
#if RING_VM_OPENSSL
ring_vm_openssl_loadfunctions(pRingState);
#endif
/* CURL */
#if RING_VM_CURL
ring_vm_curl_loadfunctions(pRingState);
#endif
/* DLL */
#if RING_VM_DLL
ring_vm_dll_loadfunctions(pRingState);
#endif
}

71.3 Module Organization

Each module starts by include the ring header file (ring.h). This files contains the Ring API that we can use to extend
the RingVM.
Each module comes with a function to register the module functions in the RingVM The registration is done by using
ring_vm_funcregister() function.
The ring_vm_funcregister() function takes two parameters, the first is the function name that will be used by Ring
programs to call the function. The second parameter is the function pointer in the C program.
for example, the ring_vmmath.c module contains the next code to register the module functions
#include "ring.h"

void ring_vm_math_loadfunctions ( RingState *pRingState )


{
ring_vm_funcregister("sin",ring_vm_math_sin);
ring_vm_funcregister("cos",ring_vm_math_cos);

71.3. Module Organization 799


Ring Documentation, Release 1.6

ring_vm_funcregister("tan",ring_vm_math_tan);
ring_vm_funcregister("asin",ring_vm_math_asin);
ring_vm_funcregister("acos",ring_vm_math_acos);
ring_vm_funcregister("atan",ring_vm_math_atan);
ring_vm_funcregister("atan2",ring_vm_math_atan2);
ring_vm_funcregister("sinh",ring_vm_math_sinh);
ring_vm_funcregister("cosh",ring_vm_math_cosh);
ring_vm_funcregister("tanh",ring_vm_math_tanh);
ring_vm_funcregister("exp",ring_vm_math_exp);
ring_vm_funcregister("log",ring_vm_math_log);
ring_vm_funcregister("log10",ring_vm_math_log10);
ring_vm_funcregister("ceil",ring_vm_math_ceil);
ring_vm_funcregister("floor",ring_vm_math_floor);
ring_vm_funcregister("fabs",ring_vm_math_fabs);
ring_vm_funcregister("pow",ring_vm_math_pow);
ring_vm_funcregister("sqrt",ring_vm_math_sqrt);
ring_vm_funcregister("unsigned",ring_vm_math_unsigned);
ring_vm_funcregister("decimals",ring_vm_math_decimals);
ring_vm_funcregister("murmur3hash",ring_vm_math_murmur3hash);
}

Tip: Remember that the function ring_vm_math_loadfunctions() will be called by the ring_vm_extension() function
(in the ring_ext.c file).

71.4 Function Structure

Each module function may contains the next steps


1 - Check Parameters Count
2 - Check Parameters Type
3 - Get Parameters Values
4 - Execute Code/Call Functions
5 - Return Value
The structure is very similar to any function (Input - Process - Output) But here we will use the Ring API for the steps
1,2,3 and 5.

71.5 Check Parameters Count

We can check the parameters count using the RING_API_PARACOUNT macro.


We can compare RING_API_PARACOUNT with any numeric value using == or != operators.
Example:
if ( RING_API_PARACOUNT != 1 ) {
/* code */
}

Example:

71.4. Function Structure 800


Ring Documentation, Release 1.6

if ( RING_API_PARACOUNT == 1 ) {
/* code */
}

71.6 Display Error Message

We can display error messages using the RING_API_ERROR() function.


The function will display the error and end the execution of the program.

Note: the behaviour of this function can be changed by the Ring code using Try/Catch/Done statements, so in your C
code, use Return after this function.

Syntax:
RING_API_ERROR(const char *cErrorMsg);

The Ring API comes with some of predefined error messages that we can use
#define RING_API_MISS1PARA "Bad parameters count, the function expect one parameter"
#define RING_API_MISS2PARA "Bad parameters count, the function expect two parameters"
#define RING_API_MISS3PARA "Bad parameters count, the function expect three parameters"
#define RING_API_MISS4PARA "Bad parameters count, the function expect four parameters"
#define RING_API_BADPARATYPE "Bad parameter type!"
#define RING_API_BADPARACOUNT "Bad parameters count!"
#define RING_API_BADPARARANGE "Bad parameters value, error in range!"
#define RING_API_NOTPOINTER "Error in parameter, not pointer!"
#define RING_API_NULLPOINTER "Error in parameter, NULL pointer!"
#define RING_API_EMPTYLIST "Bad parameter, empty list!"

71.7 Check Parameters Type

We can check the parameter type using the next functions


int RING_API_ISNUMBER(int nParameterNumber);
int RING_API_ISSTRING(int nParameterNumber);
int RING_API_ISLIST(int nParameterNumber);
int RING_API_ISPOINTER(int nParameterNumber);

The output of these functions will be 1 (True) or 0 (False).

71.8 Get Parameters Values

We can get paramters values using the next functions


double RING_API_GETNUMBER(int nParameterNumber);
const char *RING_API_GETSTRING(int nParameterNumber);
int RING_API_GETSTRINGSIZE(int nParameterNumber);
List *RING_API_GETLIST(int nParameterNumber);
void *RING_API_GETCPOINTER(int nParameterNumber, const char *cPoinerType);
int RING_API_GETPOINTERTYPE(int nParameterNumber);

71.6. Display Error Message 801


Ring Documentation, Release 1.6

71.9 Return Value

We can return values from our function using the next functions.
RING_API_RETNUMBER(double nValue);
RING_API_RETSTRING(const char *cString);
RING_API_RETSTRING2(const char *cString,int nStringSize);
RING_API_RETLIST(List *pList);
RING_API_RETCPOINTER(void *pValue,const char *cPointerType);

71.10 Function Prototype

When we define new function to be used for RingVM extension, we use the next prototype
void my_function_name( void *pPointer );

or we can use the RING_FUNC() Macro


RING_FUNC(my_function_name);

71.11 Sin() Function Implementation

The next code represents the sin() function implementation using the Ring API and the sin() C function.
void ring_vm_math_sin ( void *pPointer )
{
if ( RING_API_PARACOUNT != 1 ) {
RING_API_ERROR(RING_API_MISS1PARA);
return ;
}
if ( RING_API_ISNUMBER(1) ) {
RING_API_RETNUMBER(sin(RING_API_GETNUMBER(1)));
} else {
RING_API_ERROR(RING_API_BADPARATYPE);
}
}

71.12 Fopen() and Fclose() Functions Implementation

The next code represents the fopen() function implementation using the Ring API and the fopen() C Function.
The function takes two parameters, the first parameter is the file name as string. The second parameter is the mode as
string.
In the file ring_vmfile.h we have some constants to use as the pointer type like
#define RING_VM_POINTER_FILE "file"
#define RING_VM_POINTER_FILEPOS "filepos"

The function implementation in ring_vmfile.c

71.9. Return Value 802

S-ar putea să vă placă și