NAME

embed.pod - Parrot embedding system overview

SYNOPSIS

    #include "parrot/api.h"

    int main(int argc, char* argv[])
    {
        Parrot_PMC interp = NULL;
        Parrot_PMC pf = NULL;
        Parrot_PMC args = NULL;

        if (!Parrot_api_make_interpreter(NULL, NULL, 0, &interp)) {
            fprintf(stderr, "Cannot create Parrot interpreter!\n");
            return 1;
        }

        if (!Parrot_api_load_bytecode_file(interp, "foo.pbc", &pf))
            show_last_error_and_exit(interp);
        
        if (!Parrot_api_pmc_wrap_string_array(interp, argc, argv, &args))
            show_last_error_and_exit(interp);
        
        if (!Parrot_api_run_bytecode(interp, pf, args))
            show_last_error_and_exit(interp);
            
        Parrot_api_destroy_interpreter(interp);
        exit(EXIT_SUCCESS);
    }
    
    static void
    show_last_error_and_exit(Parrot_PMC interp)
    {
        ASSERT_ARGS(show_last_error_and_exit)
        Parrot_String errmsg, backtrace;
        Parrot_Int exit_code, is_error;
        Parrot_PMC exception;

        if (!Parrot_api_get_result(interp, &is_error, &exception, &exit_code, &errmsg))
            exit(EXIT_FAILURE);
        if (is_error) {
            if (!Parrot_api_get_exception_backtrace(interp, exception, &backtrace))
                exit(EXIT_FAILURE);
            print_parrot_string(interp, stderr, errmsg, 1);
            print_parrot_string(interp, stderr, backtrace, 0);
        }

        exit(exit_code);
    }
    
    static void
    print_parrot_string(Parrot_PMC interp, ARGMOD(FILE *vector), Parrot_String str,
            int newline)
    {
        ASSERT_ARGS(print_parrot_string)
        char * msg_raw;
        if (!str)
            return;
        Parrot_api_string_export_ascii(interp, str, &msg_raw);
        if (msg_raw) {
            fprintf(vector, "%s%s", msg_raw, newline ? "\n" : "");
            Parrot_api_string_free_exported_ascii(interp, msg_raw);
        }
    }

FILES

include/parrot/api.h

DESCRIPTION

This is the documentation for Parrot's embedding API.

Overview

Parrot defines a strict embedding API. This API may only be used by embedding applications, and other functions exported by libparrot may not be used at the same time. All embedding API functions are named Parrot_api_* and are located in the file include/parrot/api.h. No other header files are necessary or permissible for embedding applications.

All embedding API functions return an integer status code: 0 on failure and 1 on success. If a failure code is returned, other API calls can be made to retrieve the error object and then query information from it.

Data structures

The embedding API makes use of very few core data types.

Parrot_String
Parrot's internal string type, which contains character encoding information.
Parrot_PMC
A Polymorphic Container object. This is the opaque external type for (PMC *). PMCs represent any object more complicated than a primitive string or number type, and can also provide high-level wrappers around primitive types.
Parrot_Int
Parrot's integer numeric type.
Parrot_Float
Parrot's floating point numeric type.

Function signatures

What is a function signature? It is a string which represents the calling and return conventions of a function. It is a very succinct representation of the answer to the question "How do I call this function and what does it return?".

All function signatures follow the form of:

    Foo->Bar

where Foo and Bar are a list of zero or more Parrot datatypes. Foo and Bar are individually called 'type signatures'. The datatypes on the left of the arrow are function arguments being passed in and the datatypes on the right are the datatype being returned. No spaces are allowed in a function signature.

There are four datatypes that can be used in Parrot function signatures:

    I <=> Parrot_Int
    N <=> Parrot_Float (Numeric)
    S <=> Parrot_String
    P <=> Parrot_PMC

Here are some example function signatures and what they mean:

   INN->N   In: Integer, two Numerics    Out: Numeric
   SIN->S   In: String, Integer, Numeric Out: String
   P->S     In: PMC                      Out: String
   PiP->S   In: PMC (method call)        Out: String
   NN->N    In: Two Numerics             Out: Numeric
   I->I     In: Integer                  Out: Integer
   I->N     In: Integer                  Out: Numeric
   N->P     In: Numeric                  Out: PMC
   Pi->     In: none (method call)       Out: none
   ->I      In: none                     Out: Integer
   ->       In: none                     Out: none

Parrot functions support an unlimited number of function inputs and outputs.

In addition to the basic signature elements shown above, lower-case letters may be used to modify some types of inputs and outputs:

    Pi -> the invocant for a method call. Pi must be the first argument, if it
          is to be used.
    Pf -> The PMC is an aggregate (Hash, Array). The elements of the PMC will
          be separated out and will be passed individually.
    Sn -> The String is the name of the previous argument, which is passed by
          name, not by position.

Parrot function signature strings are used when a Parrot function or method call needs to be made.

Interpreter initialization and destruction

Parrot_Int Parrot_api_make_interpreter(parent, init, flags, &interp)
Creates a new interpreter, with optional initialization information and creation flags. The intepreter will have a child/parent relationship with parent, if provided. The returned interpreter object is itself a PMC, and can be operated on like any other PMC if desired.
Parrot_Int Parrot_api_set_executable_name(interp, name)
Sets the executable name of the calling process.
Parrot_Int Parrot_api_destroy_interpreter(interp)
Destroys an interpreter. After this call is made, the interpreter and all PMC and STRING objects created from it are dead and cannot be used.

Loading and running bytecode

Parrot_Int Parrot_api_load_bytecode(interp, path, &pbc)
Reads Parrot bytecode (.pbc) file from the specified location and returns it as a PMC.
Parrot_Int Parrot_api_ready_bytecode(interp, pbc, &main)
Loads a PBC PMC into the interpreter but does not run it. It returns a reference to the :main Sub PMC, if one is available. This causes any :load Sub PMCs to be executed.
Parrot_Int Parrot_api_run_bytecode(interp, pbc, args)
Loads and executes the given bytecode, executing any :init Sub PMCs, and then the :main Sub with the given arguments.

Data manipulation

Native types

Parrot_Int Parrot_api_string_export_ascii(interp, pstring, &cstring)
Parrot_Int Parrot_api_string_export_wchar(interp, pstring, &cstring)
Returns the char* or wchar_t* representation of the Parrot string. An exported string must be explicitly freed to prevent memory leaks.
Parrot_Int Parrot_api_string_free_exported_ascii(interp, cstring)
Parrot_Int Parrot_api_string_free_exported_wchar(interp, cstring)
Free's a char* or wchar_t* which has been exported.
Parrot_Int Parrot_api_string_import_ascii(interp, cstring, &pstring)
Parrot_Int Parrot_api_string_import_wchar(interp, cstring, &pstring)
Converts a native char* or wchar_t* string into a Parrot_String.
Parrot_Int Parrot_api_string_import_binary(interp, bytes, length, &pstring)
Imports an unsigned char* array of bytes. It is not treated like a normal C string, and is not expected to be null-terminated.

PMCs

Parrot_Int Parrot_api_pmc_wrap_string_array(interp, argc, argv, &args)
Wraps a char** string array into a string array PMC
Parrot_Int Parrot_api_pmc_box_string(interp, pstring, &pmc)
Creates a new PMC to wrap a Parrot_String.
Parrot_Int Parrot_api_pmc_get_class(interp, key, &class)
Retrieves a Class PMC using a key PMC. The key can be a string, or a string array PMC.
Parrot_Int Parrot_api_new_from_class(interp, class, init, &pmc)
Instantiates a new PMC from it's class object.
void Parrot_api_pmc_keep_alive(interp, pmc, alive)
If alive is 1, the PMC becomes immortal and cannot be collected by Parrot's GC. Do this if the PMC is still being used, but is not reachable by Parrot's GC. This would be the case if the PMC reference were passed to an external library. If alive is 0, the PMC becomes mortal again and can be collected like normal if it is found to be unreachable.

Calling subroutines and Methods

COMPILING

Note: This section is aimed at you if you are writing an application external to parrot which links against an installed parrot library.

Compiler and linker flags

Your application will need to include the appropriate header files and link against parrot and its dependencies.

Because the location of these files can vary from platform to platform, and build to build, a general method is provided to find out the necessary flags to use.

parrot_config is the helper tool for determining anything related to parrot configuration, determining compiler and linker flags to build against parrot is no different.

To start, you should find parrot_config in the path or allow your user to provide this location for you. You can check this by running parrot_config with VERSION as the argument to determine the version of parrot you are working with.

To determine the necessary C compiler flags, use embed-cflags:

  parrot_config embed-cflags

... and to find the necessary linker flags, use embed-ldflags:

  parrot_config embed-ldflags

The parrot_config command can be incorporated with a compile as shown here performing both compiling and linking in one step.

  cc src/disassemble.c `parrot_config embed-cflags` `parrot_config embed-ldflags`

EXAMPLES

Load bytecode as a library and run a single subroutine

    TODO

SEE ALSO

frontend/parrot/main.c and t/src/embed/*.t for Parrot's use of the embedding system.