[PLA] #00012: L-value objects and simplified object interface
Clifford Wolf
clifford at clifford.at
Thu May 1 10:30:27 CEST 2008
Hi,
below you will find yet-another PLA about l-value handling.
btw: I still like the 'keyword less language' idea as concept and it was
nice to think about it from the parser and compiler perpective, but I think
I will write another PLA soon for a more SPL-like language syntax..
yours,
- clifford
/01 10\/11 20\/21 30\/31 40\/41 50\/51 60\/61 70\/71 80\
|--------||--------||--------||--------||--------||--------||--------||--------|
Programming Language Apocalypse #00012
Author: Clifford Wolf <http://www.clifford.at/>
Date: 2008-05-01
L-value objects and simplified object interface
***********************************************
This document describes a new way of handling l-values which allows the vm
to be much simplier as existing scripting language virtual machines.
The proposed object api
=======================
Besides functions for handling garbage collection or reference counting and
error handling, each object (or better said: class) must provide the following
two functions:
struct pla_class
{
struct pla_obj *(*get_value)(struct pla_obj *this);
// This function simply returns the object for r-values,
// and returns the value pointed to for an l-value. It
// returns NULL for an yet undefined l-value.
// Classes which never are l-values can simple set this
// function pointer to NULL. The function should only be
// called using a simple macro:
#define PLA_GET_VALUE(_class, _obj) \
(_class->get_value ? _class->get_value(_obj) : _obj)
struct pla_obj *(*exec_operator)(struct pla_obj *this,
const char *operator_string,
struct pla_obj *left, struct pla_obj *right);
// This function is called for each operator executed.
// Operators like assignment operations are implemented
// only in l-values and create a runtime error for r-values.
// Normal operators like additions, etc. only access their
// operand using the PLA_GET_VALUE() macro and so
// automatically resolve l-values to r-values. Assignment
// operations are also using the PLA_GET_VALUE() macro
// for the value beeing assigned.
}
struct pla_obj
{
struct pla_class *class;
}
As said, not included in this example are functions and variables for garbage
collection and error handling.
Sample implementation of a simple namespace
===========================================
The following is the implementation of a simple namespace, which conatains
26 one-letter variables. This sample implementation contains two classes:
the first class is a singe variable, implementing an assign function, and the
2nd part is the namespace class, implementing lookups of the variables.
/*** The Variables ***/
// The class struct containing the function pointers for my simple variables
//
static struct pla_class pla_class_simple_variable = {
.get_value = simple_variable_get_value,
.exec_operator = simple_variable_exec_operator
};
// The object struct type for my simple variables
//
// All object structs must contain the struct pla_obj as first member,
// so casting object struct pointers to generic pla_obj pointers is
// safe.
//
struct pla_obj_simple_variable
{
struct pla_obj common;
struct pla_obj *value;
};
// The get_value function for my simple variables
//
// The get_value functions are easy: in most cases there is none,
// and if there is one it simply returns a member of the object struct
// or creates a scalar object on demand.
//
static struct pla_obj *simple_variable_get_value(struct pla_obj *this)
{
pla_obj_simple_variable *self = this;
return PLA_GET_VALUE(self->value);
}
// The operator function for my simple variables
//
// Everything which isn't an assign operation is simply passed on
// to the value.
//
static struct pla_obj *simple_variable_exec_operator(struct pla_obj *this,
const char *operator_string,
struct pla_obj *left, struct pla_obj *right)
{
pla_obj_simple_variable *self = this;
// assign operation?
//
// we are the left operand. simply let self->value point to
// the value of the right operand.
//
if (!strcmp(operator_string, "=")) {
self->value = PLA_GET_VALUE(right);
return self->value;
}
// everything else?
//
// pass it on to our current value, if there is any.
//
if (self->value)
return simple_variable_exec_operator(self->value, operator_string, left, right);
return NULL;
}
/*** The Namespace ***/
// class struct for the namespace
//
static struct pla_class pla_class_simple_namespace = {
.get_value = NULL,
.exec_operator = simple_namespace_exec_operator
};
// object struct type for the namespace
//
struct pla_obj_simple_namespace
{
struct pla_obj common;
struct pla_obj_simple_variable variables[26];
};
// operator function for the namespace
//
// this only implements lookup functions.
//
static struct pla_obj *simple_namespace_exec_operator(struct pla_obj *this,
const char *operator_string,
struct pla_obj *left, struct pla_obj *right)
{
struct pla_obj_simple_namespace self = *this;
if (strcmp(operator_string, ".") && strcmp(operator_string, "[]"))
return NULL;
const char *varname = SPL_GET_OBJ_STRING(right);
if (!varname || strlen(varname) != 1 || varname[0] < 'a' || varname[0] > 'b')
return NULL;
return self->variables[varname[0] - 'a'];
}
Note that this sample code does not cover object creation and initialization.
Function calls
==============
Function calls can be simply implemented as a special operator with the
function as left and the argument list as right argument. So no additional
support for function calls is required in the VM core.
It is also possible for functions to return l-values usind the apporach
described in this document.
Object Creation
===============
Objects may be created using two ways: eighter using a class which provides
object creation functionality or using the vm directly for primitves such as
strings, numbers, functions, and everything else which can be declared
directly using the language.
VM Bytecode and Compiler
========================
Having all operators - including assignment operators - handled in the classes
reduces the VM bytecode and the compiler to a very thin subset of what is
usually found in VM bytecode interpreters and compilers.
--
"The generation of random numbers is too important to be left to chance."
- Robert R. Coveyou, Oak Ridge National Laboratory.
More information about the PLA
mailing list