Skip to content

Embedding C

Dibyendu Majumdar edited this page Oct 15, 2021 · 21 revisions

Embedding C

Since C is the intermediate language used when generating machine code, we can allow a subset of C as an embedded high performance language.

It does not need to be full blown C as that would be too risky. Instead the goal should be to allow C to write snippets of high performance code.

Following features will not be provided:

  • Preprocessor
  • Ability to call functions or allocate memory
  • The interaction between Ravi and C will be limited to userdata types and primitive types / primitive arrays and strings. No access to Lua tables.
  • No assignments to Ravi primitive types in C code (this may be added as a feature later on)

Proposed syntax

New keywords C__decl, C__unsafe, C__new will be added.

  • C__decl will allow C type declarations via a string argument. A restriction is imposed that the structure contains no pointers or unions.
  • C__unsafe will take a list of symbols and a C code in string argument. Restriction is imposed that code may not make function calls or attempt to return or goto.
  • C__new will allow a userdata type of given struct type to be created.
C__decl [[
   typedef struct {
      int i;
  } MyStruct;
]]

local i: integer = 1
local j: integer = 2

C__unsafe(i,j) [[
     long long k = i+j; // Okay as primitive types
]]

When accessing userdata, string or Ravi array types, following implicit types will be used:

// For userdata and string types
typedef struct {
   char *ptr;
   unsigned int len;
} Ravi_StringOrUserData;

// For integer[]
typedef struct {
  lua_Integer *ptr;
  unsigned int len;
} Ravi_IntegerArray;

// For number[]  
typedef struct {
  lua_Number *ptr;
  unsigned int len;
} Ravi_NumberArray;

Userdata, string or primitive arrays declared in Ravi code will be accessed in the C snippet as follows:

local narray: number[] = table.numarray(100)
local udata = C__new('MyStruct', 1) -- userdata object of type, with 1 element

C__unsafe(udata, narray) [[
   // C code can cast the udata.ptr and narray.ptr to appropriate type
   MyStruct *mystruct = (MyStruct *)udata.ptr;
   mystruct->i = 42;
]]

Each symbol argument to C__unsafe will be made available in the C code.

  • Primitive integer or floating point values will have the types lua_Integer and lua_Number respectively.
  • Userdata or string types will be made available as Ravi_StringOrUserData structure.
  • integer[] and number[] arrays will be made available as Ravi_IntegerArray and Ravi_NumberArray respectively.

For string, full userdata, integer[] and number[] array types, a len attribute will be populated. The lightweight userdata, the len attribute will be set to 0.

Allocating userdata types

We can also add support for another keyword C__new to allocate a userdata type. A structure type name (must be previously declared using C__decl) can be provided, along with array size.

Status

  • This feature is under development; initial preview version is now available (12-Oct-2021)
  • A custom version of chibicc is used to parse and validate the C code to enforce some of the rules above.

Issues

  • How to allow data from userdata types to be copied to Ravi/Lua world?
Clone this wiki locally