|
Ironseed is a general-purpose crossplatform binary version-compatible
programming language, also an answer to
Microsoft's COM technology
Microsoft's COM technology
A way to solve vtable id crashes using IDL while heavily restricting
programmer and breaking to pieces object-oriented paradigm.
|
|
but without limitations of later. It uses late symbol linkage to avoid
vtable id crashes instead of MS's method "Just do not edit code and
it's vtable ids won't change".
Among other highlights there are signals and (planned) templates and
cross-platform bytecode compileable to native.
|
|
Syntax of Ironseed language is near (but not equal) to C/C++/Java.
An ironseed program consists of a number of class and function
declarations, and member method and function implementations.
Ironseed takes heavy usage of packages (or namespaces) and
an indentifer usualy consists of a number of simple identifiers
(alpha-numeric with leading alpha) separated by double colon '::'.
For example, a main function (which will be run at program start)
is named 'main'. For user convinices there are StartUsing and EndUsing
commands which add and remove package to search list, and ability
to explicate a package name by adding double colon at start,
for example '::std::string'.
Implementation part mostly consists of statements, which can be groupped
using curly brackets. In this small example, we declare main function
printing 'Hello, world !' three times.
#include <vector.ish>
#include <string.ish>
#include <kernel.ish>
int32 ::main(::std::vector args)
{
std::print("Hello, world !\n");
std::print("Hello, "+"world !\n");
std::printf("Hello, %s !\n","world");
}
|
|
There are following data types in Ironseed allowed: simple types
(integer, floating point, boolean), object references and enums.
Objects automaticaly count number of references and are automaticaly
destroyed on zero references so you have no need in garbage collecting.
To solve cross-reference problem there are on_delref() and std::weakref available.
|
3.3 Running ironseed programs |
|
At this moment, ironseed compiles programs to dynamic libraries and
you need a (really small) ironrun program which loads given library
into memory and starts ::main(::std::vector) function. This program
is linked against libIRONSEED dynamic library which contains all
C functions needed to resolve ironseed classes and functions and
to load dependent libraries.
|
3.4 Language constructs (preprocessor) |
|
Ironseed preprocessor is in developement stage and will possibly
change alot, but at this moment it is very alike to C preprocessor.
It understands #define, #include, #ifdef and #ifndef constructs.
|
#include works exactly the same way as in C. It adds contents
of destination file in place if itself. If file name is given
in double quotes, it's full destination path is compiled from
current directory, while if it is given in lighter-greater signs,
then full destination path is compiled using search paths.
Against some C compilers, if name is given in double quotes it
is never searched in search paths and vice verca, for lighter-greater
signs it is never searched in current directory (unless you add
current directory to search path using compiler options).
|
|
|
#define works nearly as in C, but (at this moment - dont know
how it will do later) can come upon infinte recurse.
#define A B
#define B C
#define C A
A
|
|
In this example, it will run into infinite recurse at the last line.
|
3.4.3 #ifdef, #ifndef, #else, #endif constructs |
|
As always the same as in C.
#ifndef MYMODULE_ISH
#define MYMODULE_ISH
#endif
|
|
|
|
3.5 Language constructs (compiler) |
|
Ironseed is much like C, but (of course) not without important differences.
|
|
Packages can be declared or pre-declared. They are proposed
for user convinience and are somewhat alike C++'s namespaces
and perl packages. All standart classes and functions are placed
in std, std::io, std::gui, std::dbi and etc. packages. Speaking
about compiler guts, a function printf located in std package
is realy a ::std::printf function, same as a file class located
in std::io package has real name ::std::io::file. For user
convinience there are StartUsing and EndUsing keywords which
add a namespace prefix to search list. A '::' namespace is
always added to search list, so you have no need to add double
colon at the start of class or function name.
package std;
package std {
class vector;
};
package std::io {
class file;
class test;
};
class test;
StartUsing std::io;
int32 main(std::vector args)
{
std::io::file f1;
file f2;
test t1;
std::io::test t2;
::std::io::test t2;
::test t3;
}
|
|
|
|
Enums be enums - not much to tell about them.
At this moment enums are strictly represented as int32, but
this can change at release point.
|
|
|
Same as in C, you can declare or implement function. The only
difference is that declaring a function you must prefix
it with 'extern' keyword.
#include <string.ish>
extern int32 print(::std::string);
extern int32 print(::std::string);
int32 main(std::vector args)
{
print("Hello, world!\n");
}
int32 main(std::vector args)
{
}
|
|
|
|
Among other data types, classes changed most in Ironseed.
First, classes do not have multiple inheritance - see
mclasses. All methods within class are always virtual
so you will always be able to make an ancessor with
some methods replaced or modified. Constructors and destructors
are named plainly as 'constructor' and 'destructor'.
class cl1: std::object {
public:
void constructor(void);
void destructor(void);
void m1(void);
void m2(void);
};
class cl2: cl1 {
public:
void constructor(void);
void destructor(void);
void m1(void);
void m3(void);
};
|
|
All data members are private, so if you want to allow
access to them from external code, you must use
'access' directive to attach functions responsible for
data reading and writting. External code stands for
all functions (except this class's constructor and
destructor) and methods of ancesstors - i.e. it is all
except strictly this class's methods, constructor and
destructor.
class myclass: std::object {
public:
void constructor(void);
std::string get_str(void) const;
void set_str(std::string v);
void m1(void);
std::string str;
access str OnRead get_str, OnWrite set_str;
};
class myclass2: myclass {
public:
void constructor(void);
void destructor(void);
void m1();
void m2();
}
void myclass::constructor(void)
{
str="MyString";
}
std::string myclass::get_str(void) const
{
return str->clone();
}
void myclass::set_str(std::string v)
{
str=v->clone();
}
void myclass::m1(void)
{
str="";
}
void myclass2::constructor(void)
{
str="MyString2";
}
void myclass2::m1(void)
{
str="aaa";
}
void myclass2::m2(void)
{
str=str+"aaa";
}
|
|
|
|
MClasses are classes with multiple inheritance allowed,
but at this moment they are heavy TODO.
|
|
|
This chapter describes statements as they should be rather then
what they are at this precise moment - for a level of
implementation see source files.
|
3.5.3.1 ExpressionStatement |
|
Expression statement is just an expression followed by ';' (semicolon) sign.
a=b*sin(x);
printf("Hello, world\n");
|
|
|
|
This statement syntax is equal to C++ syntax. After keyword 'if'
there is an expression in round brackets, a statement and
optionaly an 'else' keyword with second statement.
If expression in brackets is 'true', then first statement is
executed, else executed second statement (if exist). To allow
multiple statements to be executed group them using
BlockStatement.
Note on compiler: If stumbled upon shift/reduce conflict
(as shown in example below) the option is 'shift'.
if (a!=0) print("a is not zero\n");
if (b==0) print("b is zero\n"); else print("a is NOT zero\n");
if (b==0) {print("b");print(" is");print(" zero\n");}
if (b>0) if (b>10) print("b is big\n"); else print("b is small\n");
if (b>0) {if (b>10) print("b is big\n"); else print("b is small\n");}
|
|
|
|
This statement's syntax is equal to C++ as well.
|
|
This statement's syntax is equal to C++ as well.
|
|
This statement's syntax is equal to C++ as well, but
with one caveeat for those who are interested in
how ironc works: before issuing real 'return',
all object variables are del_ref'ed while since
we dont want a varible to return to be deleted
we call a set_nodestructorcall function before.
|
3.5.3.6 VarDeclarationStatement |
|
This statement's syntax is similar to C++ but at
this moment you can not initialize vars within it.
The syntax is as follows: data type followed by one
or more identifiers separated by commas and terminated
with semicolon.
uint32 a;
double b;
std::string c;
|
|
|
|
This statement's syntax is equal to C++ as well.
|
|
This statement should be used for debuging/error printing
purposes. It works similar to print function, but displays
file and function names and string number as well. Alert
syntax is the same if you called a function with two optional
parameters 'body' and 'header'. If program makes use of GUI
it will be possible to create popup error messages instead
of printing to stderr.
alert();
alert("Does not work");
alert("Does not work","Error");
|
|
|
|
|
3.6 Language constructs (ironC) |
|
IronC is a low-level implementation of ironseed model. This pseudo-language
(it is not even a language) is been converted to even more unreadable form
(but usable by C compiler) by ironC compiler.
The language has nearly
zero security checks and is used to create implementations of ironseed's
methods and functions in C. Ironseed compiler works the same way - it
just creates ironC code which is later processed by ironC compiler.
|
add_ref() and del_ref() functions are the most important ones in
automatic garbage removal concept. This concept allows program to
clear it's memory and delete objects whenever there is noone who
tracks a reference to them (in this case you would not be able
to gain a reference back to an object so why would you need it?).
To make this work, programmer must increase reference count each time
he creates a new reference to an object (unless this is a weak reference or
he knows what he is doing) and similary decrease reference
count each time he is about to remove a reference. After each
decrease he must check reference count versus zero to check if
anyone references this object, and if none, then call object's destructor
and then free memory used (this is only a brief but close to reality
view at this matter).
See also del_ref_if(), add_ref_if() and set_nodestructorcall() functions.
To automate this process, there are ironseed's C core level
add_ref() and del_ref() functions.
|
|
For matters of creation see add_ref() description. del_ref() function
accepts a pointer to object pointer (it is done due to that del_ref()
would be able to set object pointer to zero after object destruction).
Function's algorithm is as follows:
1) Decrease reference count for object
2) Call on_delref() method of this class if it is implemented and
it is not in progress
(Following points are done if reference count is zero)
3) Check if object's flag no_destructorcall is set to true, then
set it to false and return (no more points is executed)
4) Call destructor
5) Call event remover [TODO]
6) Ennull weak pointers connected to object (See ::std::weakref class)
7) Free used memory
8) Set pointer to NULL
object *mystr;
#assign mystr ::std::string
mystr=object_create(RTTI(::std::string));
PCALL[void ::std::string::constructor(wchar_t*)](mystr,L"Hello, World");
add_ref(mystr);
....
del_ref(&mystr);
|
|
|
|
This construct is used to make a function call. This is done
instead of standart call due to the following facts: a) So that
programmers would be able to create a multiple functions with
same name but different parameters, b) Because none of
ironseed structures have any alternatives in C except then void*,
and c) to check parameters' constantness and return value type.
The latter comment is the most important one: imagine you created
a function which returns a string, and some time after you changed
it to return some other object. C++ dynamic loader will not feel
the difference since it does not check types, but in ironseed
you will get a core error which would tell that additional information
of this function in program and library differs.
To make a function call you need to specify a function name and parameter
types in square brackets and give optional parameters in round brackets.
object *myobj;
int32 size;
....
size=CALL[::std::printf(::std::string,::std::vector)](mystr,myvec);
if (myobj!=NULL) del_ref(&myobj);
myobj=CALL[::std::sprintf(::std::string,::std::vector)](mystr,myvec);
add_ref(myobj);
|
|
|
3.6.4 CALL<...>[...](...) |
|
|
3.6.6 PCALL<...>[...](...) |
|
|
|
|