CoreLang Syntax Reference

NOTE: This document is work in progress and "pre-draft"

 

Concepts and Principles

Principles

Corelang is a superset language to define a common syntax and provide the ground rules for the different DSL languages. It will provide the common syntax metaphor that will allow developers to feel that the DSLs have a common heritage.

​The key principles for the syntax are:

  • Based on the C family: C, C++, C#, Java
  • Supporting procedural constructs
  • Supporting declarative constructs
  • Strongly typed
  • Supporting Structured and Object Oriented Programming
  • Supporting key patterns. e.g. Factories and Delegation
  • Consistent, concise and familiar for developers
  • Garbage collection based memory management

Reference and Value Variables

Variables can either be declared as reference or value. This effects the memory management of the variable and the way it is assigned values.

Reference variables are stored and passed between variables as references to the value. This means that changes to its value is seen by all references to that variable. This is similar to pointers in C. Reference variables are always passed by reference.

Value variables are always passed by value and therefore involve a copy. Changes to a copied variable do not effect any source variables.

A value variable can be assigned a value from a reference variable (involving a copy), however a reference variable cannot be assigned a value from a value variable without an explicit copy. There can never be a reference to a value variable.

The motivation behind this is to allow:

  • A clear, consistent and explicit behaviour for value and reference handling.
  • Consistent approach between intrinsic values and objects
  • Simple and optimised memory management for value variables. A value variable only ever has one access point from the program, when that goes out of scope the memory can be freed.
  • Provide support for passing references when required, leveraging garbage collecting memory management.

Should I use the description "Instance Variable" rather than "Reference Variable"?

Exceptions

There are three types of exceptions:

  • Panics. These are not declared. They cascade up the stack either they are explicitly caught or the program exits. These are for error conditions that could not be reasonably expected.
  • Logic. These errors must be declared, caught and if required explicitly re-thrown. So they don't in general cascade up the stack.
  • Signal. Must be declared and can be caught. Instead of using a catch, the signal state can be checked.

Program File

The program file structure is:

File : Static_include* Package*

Includes

Including a source or binary file causes any factories to be registered.

Static include:

Static_include : 'include' SOURCE_FILE ';' 

Dynamic (runtime) loading:

Dynamic_include : 'include' PACKAGE_ID? 'from' BINARY_FILE ';'

Packages

Packages define name spaces.

PACKAGE_ID : ID ('.' ID)*

Package : 'package' PACKAGE_ID { Package_statement* }

Package Statements

Statements are:

Package_statement : Base_decl,  TBC ...

See subsequent sections for details of each statement.

Package Declarations (Globals)

Also see the Assignments Section

Intrinsic Types

The basic types are:

BASE_TYPE : 'real' | 'int' | 'void' | 'char' | 'string'

The base declaration syntax is:

Base_package_decl : BASE_TYPE '*'? ID ('=' Const_expr)? ';'

The * is used to indicate that the variable is a reference type, if not included then the variable is a value type. The * is a syntax nod to C.

Examples

// Simple Types
int a;  // package static
real b=1.3;
int* rx = 10; // Reference variable

Objects

The syntax is:

Object_decl : CLASS_TYPE '*'? ID ( '=' Const_expr | Const_object_factory )? ';'

CLASS_TYPE : ID;

The * is used to indicate that the variable is a reference type, if not included then the variable is a value type.

Containers

Corelang defines sets and dictionaries as intrinsic container types of the language replacing arrays etc. See "Containers - Sets and Dictionaries".

The syntax for a set is:

Set_decl :  '*'? CONTAINER_TYPE '[' ']'  '*'? ID ( '=' Const_set_expr)? ';' 

CONTAINER_TYPE : ID;
  • The first '*' indicates that the container holds references, otherwise it will hold values
  • The second '*' indicates that the container variable itself is of reference type, otherwise it will be of value type

This syntax is extended for a dictionary

Dict_decl :  '*'? CONTAINER_TYPE '[' 'unique'? INDEX_TYPE INDEX_ID ( ','  'unique'? INDEX_TYPE INDEX_ID )*  ']'  
             '*'? ID ( '=' Const_dict_expr)? ';' 

INDEX_TYPE : ID;

INDEX_ID : ID;
  • The 'unique' keyword indicates that the index will be unique for each member - like a primary key

Examples

// set
*string[] c; // This is a set {"one", "two", "three"}; ordered so c[1] == "two"; (zero based). Items are stored as references.

string[unique int, unique string] *b; // Dictionary reference with two unique anonymous lookup indexes. Items stored as values.
string[int id,string code] b;  // Named indexes
b = {"item1"[1,"code1"], "item2"[2,"code2"], "default value"[*]};

Assignments

Intrinsic Types

The syntax is

Base_assign : ID '=' Expr ';'

Example (also demonstrating reference and value variables)

int* rx = 10; // Reference variable
int vx = 5;   // Value variable


vx = rx;      // Legal value copy
int* y;
y = rx;       // Legal, reference copy - so y and rx correspond to the same instance
int z;
z = vx;       // Legal, value copy - so z and vx are different instances
rx = vx;      // Illegal,  you can't have a reference to a value variable
rx = new vx;  // Legal, explicit copy
y = new rx;   // Legal y and rx correspond to different instances 
              // because y is a explicit copy of rx

Objects

The syntax is:

Object_assign : ID '=' Expr | Object_factory ';'

Examples (factory):

// Classic constructor style
widget = new formWithLayout("hello", new field(40), new button("OK", memberFunction) );

xyz c = new xyz(abc); // Constructor
inf i1 = xyz(abc);    // Class xyz must implement interface i1
inf i2 = inf(abc);    // Using a interface factory

Example of a literal style expression

widget = formWithLayout {
             title = "hello";
             entry = field { length = 40; }; 
             done  = button { label = "OK"; action->memberFunction; }; 
         };

Containers

Const_set_expr :

Const_dict_expr :



b = {"item1"[1,"code1"], "item2"[2,"code2"], "default value"[*]};

Expressions

Expr :

includes new keyword to explicitly create a copy of an intrinsic variable

Const_expr :

An object instance can be created from a factory optionally overriding attributes:

Object_factory :  
  'new'    (   ID   (   '(' Expr ( ',' Expr )* ')'    )?   )?
               (   '{'    ATTRIBUTE_ID '=' Expr ( ',' ATTRIBUTE_ID = Expr )*   '}'    )? ;

Const_object_factory :
  'new'    (    ID   (   '(' Const_expr ( ',' Const_expr )* ')'    )?   )?
               (    '{'    ATTRIBUTE_ID '=' Const_expr ( ',' ATTRIBUTE_ID = Const_expr )*   '}'   )? ;

Where the ID of the factory is not specified the default is used based on target type.

ATTRIBUTE_ID is a member attribute of the ID (or target class).

ATTRIBUTE_ID : ID ; 

An object can be defined by a literal - but with a key restriction, only the default (i.e. with no arguments) class (not interface) can be used and this constructor must allow build time execution by only updating the instance members and accessing package constant variables. This is to allow the object to be created at build time (an implementation may in fact create these as start-up before Main or other containing function gets called). This allows complex static or at least start-up resources to be defined within the Corelang code without having to revert to XML files and the like.

Object_literal : ID?  
                 (    '{'   Attribute '=' Const_expr ( ',' Attribute = Const_expr )*   '}'   )? ;

Where the ID is not specified the default is used based on target type which must be a class not an interface.

Notice that the 'new' keyword is not used as this is a declarative literal definition not a runtime instruction

Container Expressions Literals

Containers - Sets and Dictionaries

Corelang defines sets and dictionaries as intrinsic container types of the language. These replace arrays and container classes which might have been implemented in standard libraries. A mechanism exists to define the implementation to be used (see Container Classes).

Like all variables containers can be either be of value or reference type. Note however that copying a container class may be expensive unless (or even if) an implementation implements a lazy copy approach. Likewise the contents of a container can be of value or reference type.

A set provides an ordered list if items, a dictionary allows access to an item via index value(s). Indexes are always of value type - never references.

// set
string[] c; // This is a set {"one", "two", "three"}; ordered so c[1] == "two"; (zero based)




string[unique int, unique string] b; // Dictionary with two unique anonymous lookup indexes
string[int id,string code] b;  // Named indexes

b[3,"code 3"] = "hello";
b[*] = "default value";

// b is the dictionary/set itself
b = {"item1"[1,"code1"], "item2"[2,"code2"], "default value"[*]};
b += "item4"[4,"code2"];

b = { ["index"]="value" };  // Nice candy if we can parse this

b[#0==2] == b[2] == "item2"
b[#1=="code1"] == "item1"
b[5] == "default value" // if no default value would have thrown an exception
b[code=="code1"] == "item1"

int n=1;
b[#(n)=="code1"] == "item1"

// non-unigue indexes e.g.
string[] result; // result set
string[string surname] people;
result = dataset[surname=="Smith"];

// this is also valid
string[unique string taxref] people;
result = dataset[taxref=="1234567890"]; // can return an empty set rather than throw an exception

// In general a[boolean expression based on indexes] - returns a set - unless the compiler is sure it is only one result item ...
result = dataset[name="Smith" && age==20]

Package Functions

public int gdgd(int x) {} // package static function
ret(params) func // function with params returning ret
int() funcRetInt;
int(string) magnitudeFunc;

Interfaces

interface inf implements inf2, inf3
{
   int xxx
   int func(int);

   inf(abc); // There is a factory ...  
}

Register factories

An include statement (static or dynamic) registers all the class factories within the package or binary file.

Classes

// base class - no includes
class zxy implements inf1, inf2
{
   inf1(abc)  // factory
   xyz(abc)  // constructor
   ~xyz()    // disposer - exception handling?
}

class ccc implements inf1, inf2 includes baseclass1, baseclass2
{
}



// Container operations
c[3]=null; // to delete
c+=aaa; // append

func[id]; func[id#index];  // Function on elements of set/dict
=== id.func(); id.func(int index);
max[a];  // max value
max[a#0]; // max value for index 0
min[a];  
sum[a];
product[a];
count[a];
count[a#0]; // number of unique instances of index 1
indexes[a]; // number of indexes - 0 or 1 for a set?

// Container Statements
foreach[b] {value=b; index=b#0; index2=b#code // (perhaps); } // plus break / continue

foreach[a=b] {value=a; b[1]; // refers to the b set not iterator }

where[b,d; b=d && (b<1 || d#code>5 || b#0==3)] {} else {};

Disposing Objects

Container Classes

// Interface
interface <contains>[<index...1>]
{
  // Collection Functions
  // iterator
  add
  delete
}

// Set
string[] aset = impl(){};
class myset implements <contains>[]
{

}

// Dictionary
string[int] aset = impl(){};
class mydic implements <contains>[<index1>, ...]
{
} 


dispose c; // throws exception if ref cound not 1 (or disposer error)

Object and member/function delegation

// Concept: Function->delegate function
int function(int a) -> object.delegatefunc(a);
interface inf -> delegateObject;

class xxx implements abc
{
 abc delegate = abc(); // default factory
 interface abc -> delegate;

 // per function
 int func(int a) -> delegate.func2(a);    
}

// candy
delegate abc; ===  interface abc -> abc();
delegate abc(param); ===  interface abc -> abc(param);

We need anonymous functions ....

access control - private, public, package, protected, readref, readcopy, writeref writecopy? (readref==writecopy), candelegate
interfaces can have public (default) or protected
classes can have private (default), public, package or protected
get, get*, set, set*
real virtual attributes

class hierachy

// Do we need typedef?

Statements

Container Statements / Aggregates

TODOs

  • level of class extention plus containment and delegation
  • Plus syntax candy to smooth edges
  • use cases
  • ui
  • data persistence
  • language logging tool, retry, panic errors, error, flow control
  • intrinsic vs objects - I.e. what is an int?
  • Comments & Comment Metadata