Home About Applications Software License Documentation Download Community

Keystone Language Reference

08 March 2004
Language Reference API Reference

Overview
Modules
'bool' Data Type
Type Containers
Enumerated Types
Classes & Objects
Attributes
Exceptions

Overview

At the heart of the Keystone application framework is the Keystone C language.  The Keystone Application Framework itself, and programs that you write using Keystone are writen in Keystone C.  Currently, the language is implemented as a preprocessor which operates between the source code that you write, and the C compiler which compiles this code.  The preprocessor thus translates from the Keystone C language to straight C suitable for the C compiler.  This flow of operation is illustrated as follows:

The Keystone language is itself a superset of the C language, and is based heavily on C++. The design of the language has been made with these objectives

The Keystone C language is heavily intergrated with the Keystone C framework, and should not be considered in isolation. This document should read in reference to other Keystone documentation, and links are made in this document to this where relivant.

This document is a reference to the Keystone C language, it is however not intended an introduction to programming, Object Oriented Design or the C programming language. Excellent material exists on these topics, and is recommended in the references document.

This document assumes a familiarity with the C & C++ programming languages of the reader


Modules

Unlike an application written in straight C, Keystone does not use header files '.h'. Instead, a module is internally broken up into sections:

Modules are defined by the 'MODULE::' definition in the source.  The syntax is

    MODULE::<IMPORT | INTERFACE | IMPLEMENTATION | END>

A template for a module looks like this:

/*==========================================================================*/
MODULE::IMPORT/*============================================================*/
/*==========================================================================*/

#include "framework.h"

/*==========================================================================*/
MODULE::INTERFACE/*=========================================================*/
/*==========================================================================*/

/* Modules Interface section code goes here */

/*==========================================================================*/
MODULE::IMPLEMENTATION/*====================================================*/
/*==========================================================================*/

/* Modules Implementation section code goes here */

/*==========================================================================*/
MODULE::END/*===============================================================*/
/*==========================================================================*/


'bool' data type

Keystone introduces the 'bool' data type into the C language. 'bool' is a boolean truth value which may be either 'TRUE' or 'FALSE'. For example
bool active = TRUE;
type 'bool' type operated in the same way as the C language boolean evaluation, meaning when a boolean is evaluated as an integer, a value of 0 indicates 'FALSE' and a non-0 value indicates 'TRUE'. For example
int level_A = 20, level_B = 20;
bool active = TRUE;

if (active) {
   active = (level_A == level_B);
}

Type Containers

Lists

Arrays

Stacks

Bitfields


Enumerated Types


Classes & Objects

Defining

Keystone C uses a syntax simular to C++ to define classes.  A class is defined with this syntax:

class {class name} : {base class} {
 public:
   /*public class members and methods */
 private:
   /*private class members and methods */
};

'base class' in manditory, there is no such thing as a baseless class in Keystone.

Inheritence

Class Name and Alias

Every class has two static text strings associated with it, a name and (optionally) an alias.  This name information may be retrieved at run time by the application. Class name and aliases are used, for example, in loading and storing objects to persistent storage in XML

The classes 'name' is generated automatically when the class is defined and may not be modified.  The classes name is a text string with the content the same as the name used to define the class.  For example, a class defined as 'CExample' will have a class name of "CExample".

The class 'alias' is a more informal reference to the class.  Class aliases are specified by a

ALIAS<>
definition inside the class definition.  A class does not need to have an alias, but it may have only one alias.  For example:
class CExample : CObject {
   ALIAS<"demo">;
};

This defines a class with name 'CExample' and alias 'demo'

Methods

Methods operate on an object (an instance of a class) and modify that objects internal state. There are two parts to a method definition:

It is illegal to define a method body without a method prototype. The method prototype is declared inside the class definition, with this syntax:

{return type} {method name}({arg1, arg2, ...});

The method body is declared with this syntax

{return type} {class name}::{method name}(arg1, arg2, ...}) {
   {method body}
}

Inside the method body, a pointer to the object being operated on by the method may be refered to using the keyword 'this'
void CExample::value_set(int value) {
   this->value = value;
}

A method is involked from an application with this syntax:

{result} = {class name)({object}).{method name}({arg1, arg1, ...});

The following is an example defining and calling methods

class CExample : CObject {
 public:
   bool method_foo(void);
   bool method_bar(void);
}

bool CExample::method_foo(void) {
   return TRUE;
}

bool CExample::method_bar(void) {
   return CExample(this).method_foo();
}

Virtual Methods

Object Construction / Destruction

Objects (instances of a classes) are created and destroyed using the 'new' and 'delete' operations.  Objects may be created either from statically allocated memory, or dynamically, from the heap.  

To create an object from statically allocated memory:

new({&object}).{class name}({arg1, arg2, ...});
To create an object dynamically
{object pointer} = new.{class name}({arg1, arg2, ...});

A simple example using both statically & dynamically allocated objects:

CExample demo_static, *demo_dynamic;

new(&demo_static).CExample();
demo_dynamic = new.CExample();

The following illustrates the life of an object:

On construction, the classes 'new' method is called (if present), then the classes constructor is called with the arguments passed in the 'new' operation.  The classes constructor is the classes method which has the same name as the class, so for the class 'CExample', method

CExample::CExample()
is the constructor

Objects are deleted using the 'delete' operation:

delete({&object});

On deletion:

In summary:

The following is a typical example of a class definition in relation to construction/destruction

class CExample : CObject {
 private:
   CString string;
   int value;

 public:
   void new(void);
   void CExample(int value);
   void ~CExample(void);
};

void CExample::new(void) {
   new(&this->string).CString(NULL);
};

void CExample::CExample(int value) {
   this->value = value;
   CString(&this->string).printf("%d", value);
};

void CExample::~CExample(void) {
   delete(&this->string);
};

Automatic Objects

Objects may be defined which are automatically constructed when your application starts. An automatic object is declared with this syntax:
OBJECT<{class name}, {object name}>;

Casting

A pointer to an object of any class, or a pointer to void data may be cast to a pointer to another class.  This is done using casting syntax, which is

{class name}({object});

It is valid to cast:

If the cast in invalid, and exception will be thrown at run time when the cast is attempted.  The exception throws is

EXCEPTION<CObject,InvalidCast>

See the section Exceptions in this document for more information on exceptions.

Class Information

Every class defined by the application framework, and classes defined by applications you write has a small associated information structure which you may use to retrieve information about the class at run time.  The structure has the name 'CObjClass' and may be retrieved in one of two ways:

For example to check if the object 'object' is of class 'CExample':

if (CObject(object).obj_class() == &class(CExample)) {
   /* test has proven true */
}

Exceptions


Class Attributes

Class attributes allow members of a class to be made avaliable to application users. A class member which is marked as an attribute may be:

Attributes are marked when a class is defined, with this syntax:

ATTRIBUTE<{type} {name}, "{alias}"}>

'{alias}' is optional, if ommitted the attribute will use "{name}" as it's name

The following example defines a class with a number of attributes:

class CExample : CObject {
 public:
   ALIAS<"example">;

   ATTRIBUTE<int width>;
   ATTRIBUTE<int height>;

   void new(void);
   void CExample(void);
   void ~CExample(void);
}
When this example class is stored persistently as XML, the result will look like:
<?xml version="1.0"?>

<example width="100" height="100"/>

The use of attribute is covered with examples in the tutorial

Basic Attribute Types

The following attribute types are built into the Keystone framework:

In addition, the following types are defined by Keystone graphics (part of the framework) and may be used in your application:

Array Attribute

Enumuerated Type Attributes

Defining New Attribute Types

Your application may define new attribute types for it's own use. An attribute type consistes of these parts:

typedef struct {
   int hour;
   int minute;
   int second;
} TTime;

ATTRIBUTE:typedef<TTime>;

bool ATTRIBUTE:convert<int>(struct tag_CObjPersistent *object,
                            const TAttributeType *dest_type, const TAttributeType *src_type,
                            int dest_index, int src_index,
                            void *dest, const void *src) {
   TTime *time;
   CString *string;

   if (dest_type == &ATTRIBUTE:type<TTime> && src_type == &ATTRIBUTE:type<CString>) {
      time   = (TTime *)dest;
      string = (CString *)src;
      *value = sscanf(CString(string).string(), "%d:%d:%d",
			                &time->hour, &time->minute, &time->second);
      return TRUE;
   }

   if (dest_type == &ATTRIBUTE:type<CString> && src_type == &ATTRIBUTE:type<TTime>) {
      time   = (TTime *)src;
      string = (CString *)dest;
      CString(string).printf("%d:%d:%d", *time);
      return TRUE;
   }
   return FALSE;
}


Exceptions