Skip to content

Embedding C

Dibyendu Majumdar edited this page Oct 16, 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 allows C type declarations via a string argument. A restriction is imposed that the declared types contain no pointers or unions. All type declarations in a chunk of code are amalgamated in the generated code, hence duplicate declarations are not allowed.
  • C__unsafe takes a list of symbols and a C code in string argument. The restriction is imposed that code may not make function calls or attempt to return or goto.
  • C__new allows a userdata type of given struct type to be created. A size argument is required; the value of 1 means a single element, and larger number means that an array of the type will be allocated.
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 is 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.

Values assigned to the primitive types are reflected in Ravi code. The other supported types are reference types anyway, however making changes to Lua strings is not permitted (although this is not yet enforced).

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

The keyword C__new can be used 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.
Clone this wiki locally