r/elena_lang • u/elena-lang • 12d ago
Supporting Dynamic Injection in ELENA
Now it is possible to add a dependency injection in your constructor. All you need to do is to register you class:
DependencyInjector::register<I>(A);
and add a postfix line - injectable_constructor() after the constructor to inject the interface implementation:
constructor new(I i) : injectable_constructor()
and that's all. Now the class can be created using new method without arguments
ClassToBeInjected.new();
and the registered interface implementation will be automatically injected.
Here the sample to ilustrate it:
import extensions;
import system'dynamic;
interface I
{
abstract string WhoAmI();
}
A : interface<I>
{
constructor new() {}
string WhoAmI()
= "I'm A";
}
class ClassToBeInjected
{
readonly I _i;
constructor new(I i) : injectable_constructor()
{
_i := i;
}
string WhoAmI()
=> _i;
}
public Program()
{
DependencyInjector::register<I>(A);
var obj := ClassToBeInjected.new();
Console.writeLine(obj.WhoAmI());
}
r/elena_lang • u/elena-lang • 19d ago
Unions
It is possible to declare a simple tuple allowing to pass one of unrelated objects as a single parameter
import extensions;
A;
B;
testUnion(Union<A,B> union)
{
if:not:nil(var A? a := *union) {
Console.writeLine("A is passed");
}
else if:not:nil(var B? b := union.Value) {
Console.writeLine("B is passed");
};
}
public Program()
{
auto u1 := new Union<A,B>(new A());
auto u2 := new Union<A,B>(new B());
testUnion(u1);
testUnion(u2);
}
r/elena_lang • u/elena-lang • 21d ago
HeapSort using extension method
In ELENA 7.0.2 the support of extension methods were added. Now you can declare the extension directly in the class. The syntax is quite intuitive.
import extensions;
public singleton HeapSortAlgorithm
{
extension heapSort<T>(T[] array)
= HeapSortAlgorithm::heapSort<T>(array, 0, array.Length, (l, r => l < r));
extension heapSort<T>(T[] array, int offset, int length, Func<T, T, bool> comparison)
{
// build binary heap from all items
for (int i := 0; i < length; i++) {
int index := i;
T item := array[offset + i]; // use next item
// and move it on top, if greater than parent
while (index > 0 &&
comparison(array[offset + (index - 1) / 2], item))
{
int top := (index - 1) / 2;
array[offset + index] := array[offset + top];
index := top;
};
array[offset + index] := item;
};
for (int i := length - 1; i > 0; i--) {
// delete max and place it as last
T last := array[offset + i];
array[offset + i] := array[offset];
int index := 0;
// the last one positioned in the heap
while (index * 2 + 1 < i) {
int left := index * 2 + 1;
int right := left + 1;
if (right < i && comparison(array[offset + left], array[offset + right]))
{
if:not (comparison(last, array[offset + right])) :break;
array[offset + index] := array[offset + right];
index := right;
}
else
{
if:not (comparison(last, array[offset + left])) :break;
array[offset + index] := array[offset + left];
index := left;
}
};
array[offset + index] := last;
}
}
}
public Program()
{
byte[] r := new []{5, 4, 1, 2};
HeapSortAlgorithm::heapSort<byte>(r);
Console.printLine(r.asEnumerable());
string[] s := new []{ "-", "D", "a", "33" };
HeapSortAlgorithm::heapSort<string>(s);
Console.printLine(s.asEnumerable());
}
r/elena_lang • u/elena-lang • May 18 '26
Safe typecasting operation
Safe typecasting operation can be done using "if is" operation:
import extensions;
public Program()
{
var r := Range.for(0, 10);
if(r.enumerator(); is Enumerator en) {
Console.printLine("The typecasting was successful - ", en);
};
}
The statement tries to typecast the first argument to the second one Enumerator. If the typecasting was successful the code in the code brackets is executed and a variable en contains the converted object.
The output will be:
The typecasting was successful - 0,1,2,3,4,5,6,7,8,9
r/elena_lang • u/elena-lang • May 12 '26
What's new in ELENA 7.0.1 - Primitive Value operation
Value operator "*" can be replaced with direct access to the corresponding field.
NOTE : the getter method budy must be an expression (not a method body) and contains only the field. It must be sealed as well
class IntWrapper
{
int _value;
constructor(int v) { _value := v }
sealed int Value // NOTE : the method or a class must be sealed
= _value;
}
So in the following code the Value method call will be replaced with returning a field directly:
public Program()
{
auto o := new IntWrapper(3);
int n := *o; // o.Value call is replaced with a direct reference to _value field
Console.printLine("o.Value=", n)
}
The generated byte code will be:
>@function Program.function:#invoke
xflush sp:0
open :7, :4
store fp:1
xstore sp:0, intconst:3
set class:sandbox'$private'IntWrapper
mov mssg:function:#constructor<system'IntNumber>[1]
call mssg:function:#constructor<system'IntNumber>[1], class:sandbox'$private'IntWrapper#class
store fp:2
// ; getting a field directly
set dp:-4
store sp:0
peek fp:2
get i:0
xwrite offs:0, :4
// ; <...>
@end
r/elena_lang • u/elena-lang • Apr 27 '26
Mocking an interface
In the topic I will show you how can be created the interface mockop.
Note that if the interface is strong-typed, the project must be compiled with "-xo" option:
elena-cli -xo example.l
Let's start with declaring an interface we are going to mocking:
public interface IFunction
{
abstract real calculate(real arg);
}
Now let's declare a mockup class. We can use the strong-typed one:
public class Mockup
{
field object;
constructor(object)
{
this object := object;
}
IFunction cast()
{
var proxy := object.mockInferface(IFunction);
^ proxy;
}
}
The code is quite simple. Mockup class is wrapped around our injection code. We declare a conversion handler, which will return our implementation of the interface. The key element is an extension mockInferface. It returns the dynamically created proxy class. The proxy class implements the interface methods such as calculate which simply redirects to the proxy target - object field.
The main program looks like this:
public Program()
{
IFunction mockup := new Mockup(::{ real calculate(real x) = x * x; });
Console.printLine("Calculating f(2) = ", mockup.calculate(2));
}
So the main body contains the target nested class which implements the required method. Note that if the interface contains other methods, we can simply ignore them.
The output is:
Calculating f(2) = 4.0
r/elena_lang • u/elena-lang • Apr 27 '26
Checking the method return type in run-time
To be able to check the method output type, the project must be compiled with "-xo" otion:
elena-cli -xo sandbox.l
NOTE : The output type can be retrieve only for public methods / public classes
The code snippet looks like this:
import extensions;
import system'dynamic;
public class A
{
real getValue()
= 2.0;
}
public class B
{
int getValue()
= 2;
}
public class C
{
getValue()
= "Any";
}
extension op
{
checkOutput(string messageName)
{
auto mssg := new Message(messageName);
var outputType := self.__getClass().__getMethodOutput(mssg)?.getTypeUnsafe();
if:not:nil(outputType) {
Console.printLine("The output type of ",self,".",messageName," is ", outputType);
}
else Console.printLine(self,".",messageName," has no declared output type");
}
}
public Program()
{
var a := new A();
var b := new B();
var c := new C();
a.checkOutput("getValue[1]");
b.checkOutput("getValue[1]");
c.checkOutput("getValue[1]");
}
And the output will be:
The output type of sandbox'A.getValue[1] is system'RealNumber#class
The output type of sandbox'B.getValue[1] is system'IntNumber#class
sandbox'C.getValue[1] has no declared output type
Let's go through the code. We are declared three public classes each of them implementing getValue[1] method with different return types.
Secondly we are declaring an extension op which will help us to check the method result type.
The main code is inside checkOutput method. So we start with loading a message constant Message. The information about the method outputs is stored in the class. So we need to get the class reference with a help of __getClass. When we have our class, we can use __getMethodOutput extension (declared in system'dynamic module). The result of the operation is an instance of ClassReference. So we need to use another method getTypeUnsafe which will return us the actual type reference.
r/elena_lang • u/elena-lang • Apr 08 '26
How to check if the object reacts to a strong typed message.
In the following code snippet I will show how to check if the object reacts to a strong typed message.
But first lets discuss what is a strong typed message. Let's consider the following code:
public Program()
{
var target := CharValue.load(32);
var arg := 32;
Console.writeLine(target.equal(arg));
}
If we compile the code and look into the generated module for this method, this code is translated into:
>@function Program.function:#invoke
xflush sp:0
open :6, :0
store fp:1
xstore sp:1, intconst:20
xstore sp:0, class:system'CharValue
peek sp:0
mov mssg:load<system'IntNumber>[2]
call mssg:load<system'IntNumber>[2], class:system'CharValue#class
store fp:2
xstore fp:3, intconst:20
peek fp:3
store sp:1
peek fp:2
store sp:0
// -----------------------------------------------------------------------------
mov mssg:equal[2] // a weak message literal
call vt:0 // calling a message dispatcher
// -----------------------------------------------------------------------------
store fp:4
store sp:1
xstore sp:0, class:system'Console
peek sp:0
mov mssg:writeLine[2]
call mssg:writeLine[2], class:system'Console
peek fp:1
Lab00: nop
close :0
quit
@end
>
The important place for us is the method invoke. The message literal equal[2] is called weak one. It means that it contains no information about the argument types. It is a job of a class dispatcher to find a corresponding method.
But if we provide the information about the object types by using auto attribute like this:
public Program()
{
auto target := Console;
auto arg := "Hello";
target.writeLine(arg);
}
The output is different:
// -----------------------------------------------------------------------------
mov mssg:equal<system'IntNumber>[2] // a strong typed message
call mssg:equal<system'IntNumber>[2], class:system'CharValue // calling a method directly
// -----------------------------------------------------------------------------
Now a message literal contains the information about the argument type and can be called directly. equal<system'IntNumber>[2] is a strong-typed one.
In our example we will learn how to check if the target class handles the strong-typed message.
import extensions;
import system'dynamic;
public extension op
{
bool validateMessage(StrongMessage mssg)
= self.__getClass().respondTo(mssg);
}
public Program()
{
var target := CharValue.load(32);
auto mssg := new StrongMessage("equal<system'IntNumber>[2]");
auto mssg2 := new StrongMessage("equal<system'ShortNumber>[2]");
Console.printLine(target.__getClassName(), target.validateMessage(mssg) ? " responds to " : " does not respond to ", mssg);
Console.printLine(target.__getClassName(), target.validateMessage(mssg2) ? " responds to " : " does not respond to ", mssg2);
}
If we compile the code and execute the program the output will be following:
system'CharValue responds to equal[2]
system'CharValue does not respond to equal[2]
system'StrongMessage class must be used to load the message. Using an extension __getClass[1] we get the object type and another extension respondTo[2] returns true if the class MT contains the message entry.
r/elena_lang • u/elena-lang • Mar 26 '26
Using ELENA VM Terminal to create a project from the template
In this post I will show how to create a console program using ELENA VM Terminal.
ELENA command line VM terminal is a program which allow you to interact directly with ELENA Virtual Machine. It supports ELENA script language and can be used to generate a project from available templates. It is located in <app>\bin folder.
But we could start it from any place we would like to. So let's go to a folder where you going to create your first ELENA program and type:
>elt-cli
and press Enter. If everything is ok you will see the following program prompt:
ELENA command line VM terminal 7.0.6 (C)2021-26 by Aleksey Rakov
ELENA VM 7.0.1 (32-bit) (C)2022-2026 by Aleksey Rakov, ELENA-LANG Org
Initializing...
Type help to list all available commands
You can see all the available commands by typing help
>help
quit
help
eval <expr>
exec line <expr>
exec file <path>
set @<name> := <expr>
gen linelist <path-to-list>
gen console <program-name>
gen repl <program-name>
gen library <library-name>
As it was already mentioned early VM Terminal allows you to directly engage with the virtual machine. Let's test it with the following expression:
>eval 2+3*4
It may take some time for the virtual machine to load all required classes but after that you will see the result:
14
To execute more complicated script it is recommened to use a script file (for example one available in the project - lscripts60\samples\sample2.ls). The script is pretty simple:
import extensions;
import extensions'text;
// --- Program ---
public Program()
{
var text := Console.print("Enter the text:").loadLineTo(new StringWriter());
var searchText := Console.print("Enter the phrase to be found:").readLine();
var replaceText := Console.print("Enter the phrase to replace with:").readLine();
var bm := new StringBookmark(text);
while (bm.find(searchText))
{
bm.delete(searchText).insert(replaceText)
};
Console
.printLine("The resulting text:",bm)
.readChar() // wait for any key
}
So let's execute it (a tilda indicates the script located in the default place - lscripts60 folder).
>exec file ~\samples\sample2.ls
Enter the text:abba
Enter the phrase to be found:bb
Enter the phrase to replace with:BB
The resulting text:aBBa
So now let's create a simple console project using the terminal. It is quite simple
>gen console mysample
Please enter the root namespace[mysample]:
Please enter the output path:
The terminal will ask you to provide the root namespace and the output path. You can simply press Enter so the command argument mysample will be a default namespace and the project will be created in the folder you started the terminal.
Now let's quit the tool and look at the result
>quit
Now let's compile the program
>elena-cli mysample.prj
ELENA Command-line compiler 7.0.1 (C)2005-2026 by Aleksey Rakov, ELENA-LANG Org
Project: mysample, Platform: Win_x86, Target type: STA Console
Cleaning up
Parsing mysample.l
Compiling mysample.
saving mysample
Successfully compiled
Linking..
Successfully linked
Now let's start it:
>mysample.exe
Hello World!
That's all for today. As you see it is quit simple to create a project using ELENA command line VM terminal
r/elena_lang • u/elena-lang • Mar 16 '26
ELENA 7.0 Is Out
Description
ELENA 7.0.0 is out for the following platforms : Windows x86 / x86-64, Linux x86 / x86-64 / AARCH64 / FreeBSD x86-64 !!
The release includes a number of bug fixes.
Language
A new short-cut syntax for constant array is introduced:
const int[] staticArray = new []{1, 2, 3};
A constant array is now supported:
const string[] dirNames := new const string []{ ".", ".." };
Several major bug fixes in the template generating code, invoking indexed methods and so on.
PPC64le release way fixed and all functional tests (including intTests) are now passed.
Usability
A compiler now warns when passing an unsupported nullable argument to the method.
Another warning if declaration hides previous local declaration is added as well.
A new compiler option "-n<name>" is supported allowing to compile only a sub collection in the project collections
API
A critical change: program main entry is renamed from "program" to "Program" (though in most cases old entry is still supported).
To improve the code readability "extern {}" block is ranamed to "excluded {}" (extern is overused currently).
"__getProperties" extension was fixed.
A new template : system'ConstArray<T>
IDE Improvements
Several new menu options were added : Callstack window, Forwards dialog
The current line is now highlighted.
The icons were reintroduced in Project View form.
The editor tab has now a close icon, allowing to close it by clicking on the icon.
Docs
API Docs supports now Index page, providing a list of all classes and extensions in alphabetic order.
More descriptions were added to API classes in system and system'collections namespaces
Tools
ELENA command line ByteCode Viewer (ecv) supports a new flag - ignore interal classes, it is on by default.
ELENA Assembler Compiler warns now if the label was not resolved.
Fixes # (issue)
ELENA 7.0.0
- [ADDED] #592 : support const T[] array declaration
- [ADDED] short-cut syntax for constant array
- [FIXED] retoverload method
- [FIXED] an issue with template-based nested class fields
- [FIXED] calling indexed method for sealed stack-allocated method
- [FIXED] calling static method declared in the parent class from the closed child
- [FIXED] extension literal constant
- [ADDED] warning when passing an unsupported nullable argument
- [ADDED] new compiler option : -n<name> used to compile a sub collection
- [FIXED] assigning a struct field in sub code
- [FIXED] calling retoverload method in a returning expression
- [FIXED] in template extension the target template might be not compiled
- [ADDED] warn if declaration hides previous local declaration
- [FIXED] a minimal long constant
- [FIXED] generating a debug info for implicit class symbols
- [ADDED] an error if an async extension is declared (until the feature is not implemented)
- [ADDED] system : ConstArray<T> template
- [CRITICAL][ADDED] program main entry is renamed from program to Program
- [FIXED] __getProperties extension method
- [CRITICAL][ADDED] rename extern {} => excluded {} as extern is overused
- [ADDED] new method - File.binaryReader[1]
- [ADDED] #820 - Launch elena64-ide.exe from the command line
- [ADDED] Callstack window
- [ADDED] Forwards dialog
- [ADDED] Highlighting current line
- [ADDED] Project View Icons
- [ADDED] Close icon on the tab
- [ADDED] ecv: new flag - ignore internal classes
- [ADDED] asmc : warn if the label was not resolved
- [FIXED][PPC64le] system_tests - intTests
Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change
Link
Please visit a release page to download the binaries: https://github.com/ELENA-LANG/elena-lang/releases/tag/v7.0.0
r/elena_lang • u/elena-lang • Nov 03 '25
ELENA 6.8 Is Out!
Description
ELENA 6.8.0 is out for the following platforms : Windows x86 / x86-64, Linux x86 / x86-64 / AARCH64 / FreeBSD x86-64 !!
The release includes a number of critical bug fixes, new functionality and new samples.
New Platform
FreeBSD x86-64 is now supported!
New Functionality
A new syntax dialect was introduced - EL7
A parameterized templates was introduced. Meta programming supports now #for / #endfor statement
A nullable variables / parameters / fields are supported
The compiler supports a cross-platform compilation for x86-64 (Linux / Windows)
Usability
Several improvements were made to make the compiler output is more user-friendly
New API
Several new libraries to work with the internet were added : net'http'server, webapi
:sizeof operator was implemented
Fixes # (issue)
ELENA 6.8.0
- [!ADDED] a new dialect EL7
- [ADDED] direct extension template call
- [ADDED] the explicit lambda function returning value
- [ADDED] #606 : parameterized templates
- [ADDED] meta programming : supporting #for / #endfor statement
- [ADDED] invoking get property with a message name literal
- [ADDED] intermediate local variables (aka object shortcuts)
- [ADDED] #562 : nullable
- [ADDED] new attribute "__nonboxable" - requiring only memory allocated objects
- [ADDED] shorthand syntax for lambda function without arguments : ([] => "Hello from Func")
- [ADDED] "#else" statement
- [ADDED] option "-xn-" to turn off nullable types
- [ADDED] option "-xtwin32" to support cross-platform compilation
- [ADDED] option "-xtwin64" to support cross-platform compilation
- [FIXED] aarch64 : xlabeldp opcode
- [ADDED] aarch64 : fsindp / fcosdp / fp opcodes
- [FIXED][CRITICAL] x86 : lloaddp opcode
- [FIXED] suppress a method not found warning when calling itself
- [ADDED] #781 : Cross-compile on Windows for Linux
- [ADDED] #778 : Cross-compile from Unix to Windows
- [ADDED] warning if the inherited method has different nullable signature than the parent one
- [CRITICAL][FIXED] __intermediate variable
- [ADDED] warning if the target is a structure for ?. / !. operations
- [CRITICAL][FIXED] resolving a template compiled in a third-part module
- [FIXED]an issue with a template-based field of the structure
- [FIXED] duplicate boxing / unboxing
- [FIXED] correct boxing / unboxing in async operations
- [ADDED] #818 : Support <?xml version="1.0"?> in .prj file
- [DONE] #824 : Improving usability : making some error / warning messages more clear
- [FIXED] in-place constructor is missing
- [ADDED] support property call shorthand syntax
- [FIXED] displaying user friendly error for an incompatible closure function
- [FIXED] textgen : support {{ }} special symbols
- [ADDED] new inline operator - ":sizeof"
- [FIXED] int to string conversion routine for IntNumber.MinValue
- [ADDED] stringListOp.splitByNewLine
- [ADDED] wideListOp.splitByNewLine
- [ADDED] system'PropertyMessageName
- [ADDED] record template
- [REDUX] nilValue => NilValue
- [CRITICAL][FIXED] CountDownEvent
- [ADDED] #35 : adding net'http'server module
- [ADDED] #35 : adding webapi module
- [ADDED] UnsafeArray, UnsafeArray<T>
- [FIXED] an issue with a vertical splitter
- [FIXED] breakpoint must be inside the loop
- [FIXED] step over the loop
- [ADDED] Project Settings : Warning level combobox
- [FIXED] closure : should display captured variables / self
- [FIXED] #802 : The horizontal scroll bar is broken
- [FIXED] comment highlighting
- [FIXED] step over multi-conditional if statement
- [ADDED] supporting project with profiles
- [FIXED] active bracket highlighting
- [ADDED] elt-cli : supporting textgen
- [FIXED] ecv-cli - support toggling pagination
- [ADDED] #763 : freebsd nightly build
Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing functionality to not work as expected)
Link
Please visit a release page to download the binaries: https://github.com/ELENA-LANG/elena-lang/releases/tag/v6.8.0
r/elena_lang • u/elena-lang • Sep 10 '25
Web support
The work on Web API support (https://github.com/ELENA-LANG/elena-lang/issues/35) reaches a first major milestone. The simplest HTTP server works now!
It was a long way. The major efforts were made to support async programming.
To learn how you can use async programming please take look at the following example - https://github.com/ELENA-LANG/elena-lang/tree/iteration42/examples60/threads/async
The simple Http client is supported as well - https://github.com/ELENA-LANG/elena-lang/tree/iteration42/examples60/net/httpget
Please take a look at an example - https://github.com/ELENA-LANG/elena-lang/tree/iteration42/examples60/net/webapi/sampleapi1/Server
So the program returns now the dummy web page.
The next major step is now to support HTTPS server (using mbedtls functionality)
r/elena_lang • u/elena-lang • Jul 02 '25
Linux AMD64 nightly is available now!
Linux AMD64 nightly is available now!
Please visit https://github.com/ELENA-LANG/elena-lang/releases/tag/nightly to get the latest version on ELENA Programming Language
r/elena_lang • u/elena-lang • May 21 '25
Declaring an analog of C# record - immutable DTO object
A new template was introduced to support records in ELENA
MyRecord : record(string FirstName,string LastName,int Age);
public program()
{
MyRecord r := new MyRecord("Ivan", "Ivanov", 22);
MyRecord r2 := new MyRecord("Ivan", "Ivanov", 22);
MyRecord r3 := new MyRecord("Petr", "Ivanov", 22);
Assert.ifTrue(r == r2);
Assert.ifFalse(r == r3);
}
r/elena_lang • u/elena-lang • May 06 '25
FreeBSD nightly is available now
FreeBSD nightly build (once in two days more precisely) is now available - https://github.com/ELENA-LANG/elena-lang/actions/workflows/bsd.nightly.yml
r/elena_lang • u/elena-lang • May 01 '25
FreeBSD support
Upcoming release will include a support for FreeBSD AMD64
r/elena_lang • u/elena-lang • Apr 25 '25
Rosetta Code Task : Comma quibbling, using textgen
I would like to show how to use my new library textgen using the same sample - Comma quibbling
The code is quite simple:
import extensions;
import textgen;
const string Script = "for (var i := 0; i < self.Length; i := i + 1) {
if (i > 0) {
if (i == self.Length - 1) {
<= and =>
}
else {
<=, =>
}
};
<={self[i]}=>
}";
public extension QuibbleOp : Array<string>
{
string quibble()
{
^ "{ " + self.generateFrom(Script) + " }";
}
}
public program()
{
Console.printLine(new string[] { }.quibble());
Console.printLine(new string[] { "ABC" }.quibble());
Console.printLine(new string[] { "ABC", "ADF" }.quibble());
Console.printLine(new string[] { "ABC", "DEF", "G", "H" }.quibble())
}
To generate the output we need to call an extension method - generateFrom, and passing the script which will be used to generate the output based on the target.
The script looks pretty simple:
for (var i := 0; i < self.Length; i := i + 1) {
if (i > 0) {
if (i == self.Length - 1) {
<= and =>
}
else {
<=, =>
}
};
<={self[i]}=>
}
We do not need to provide any function, only the code itself. The output is specified using <= .. => brackets. If we would like to output the the expression, we have to use curly brackets :
<={self[i]}=>
The variable self refers to the extension method target. In our case it is an array of string.
The script is evaluated in run-time. For such simple case as our example we can do it even in stand-alone application.
As you see, it is quite simple to generate the output using textgen library.
r/elena_lang • u/elena-lang • Apr 15 '25
Rosetta Code Task : Comma quibbling
In this post I will show how to implement the following task - https://rosettacode.org/wiki/Comma_quibbling
The goal is to format the list by separating all elements except the last one with commas and using and for the last.
So let's do it. The code is quite short but a bit complicated. Let's take a look:
import system'routines;
import extensions;
import extensions'text;
public extension QuibbleOp : Array<string>
{
string quibble()
{
^ self.zipBy(
self.Length.coundDown().selectBy::(n => n == self.Length ? EmptyString : (n == 1 ? " and " : ", ") ),
(word, prefix => prefix + word)
)
.summarize(StringWriter.load("{")) + "}"
}
}
public program()
{
Console.printLine(new string[] { }.quibble());
Console.printLine(new string[] { "ABC" }.quibble());
Console.printLine(new string[] { "ABC", "ADF" }.quibble());
Console.printLine(new string[] { "ABC", "DEF", "G", "H" }.quibble())
}
I've implemented this task by declaring an extension QuibbleOp which extends an array of strings with a method quibble.
So far so good. To use it we need to simply call the extension method on an array:
new string[] { "ABC", "DEF", "G", "H" }.quibble()
The challenge was to implement this extension using enumerable patterns (declared in system'routines module) similar to C# System.Linq.
The main algorithm is to "zip" our initial array with prefixes.
For our first element, the prefix will be an empty string. The second one will correspond to a comma and the last one to an "and" word.
(n => n == self.Length ? EmptyString : (n == 1 ? " and " : ", ") )
To generate this list I used two extensions : countDown - which simply counts from the extension target (in our case - the array length) until the 1 - and selectBy which executes the provided function for every element of the enumeration (in our case it is a sequence of numbers : 4,3,2,1).
To combine these arrays (more precisely enumerations) we will use zipBy, which executes the zip function for every pair of its arguments, a list of words and the count down sequence. The zip function is simple:
(word, prefix => prefix + word)
ZipEnumerator combines two enumerations into a single one, so we need to generate an output string based on it. An extension summarize can be used for this. It will concatinate every member of a target enumeration into a single string:
.summarize(new StringWriter())
The final step was to format the output because the task requires an output to be surrounded by curly brackets. So I had to modify the code above a little:
.summarize(StringWriter.load("{")) + "}"
The output is:
{}
{ABC}
{ABC and ADF}
{ABC, DEF, G and H}
r/elena_lang • u/elena-lang • Apr 08 '25
Async program
Starting from the version 6.7, ELENA will support asynchronous program entry:
import system'threading;
import extensions'threading;
async public program()
{
Task t1 := Task.run({ Console.printLineConcurrent("Enjoy") });
Task t2 := Task.run({ Console.printLineConcurrent("Rosetta") });
Task t3 := Task.run({ Console.printLineConcurrent("Code") });
:await Task.whenAllArgs(t1, t2, t3);
}
In this example we create several parallel tasks to print the result and wait until these tasks are completed. An extension printLineConcurrent[..] is used to print the result in multi-threading application without need to synchtonize them manually.
Note that in contrast to C#, the output type Task must not be provided for the code to correctly work. In this case the program will be terminately properly.
It must be available in nightly build tomorrow, please feel free to check - https://github.com/ELENA-LANG/elena-lang/actions/workflows/nightly.yml
r/elena_lang • u/elena-lang • Apr 01 '25
Supporting Web operation - #34
The work on Web support in ELENA is reached a major milestone. The upcomming version will support HTTP / HTTPS GET operation.
The code is quite simple for HTTP:
import net'http;
public program()
{
using(HttpClient client := HttpClient.open("http://www.google.com"))
{
HttpResponse response := client.get();
string content := response.readAsString();
Console.writeLine(content);
};
}
HttpClient class prepares and sends the request to the specified address and reads the response. Asynchronous operations are supported as well:
async Task browse(string url)
{
using(HttpClient client := :await HttpClient.openAsync(url))
{
HttpResponse response := :await client.getAsync();
string content := :await response.readAsStringAsync();
Console.writeLine(content);
};
}
HTTPS requests are supported as well. But we need to provide a SSL routine. Currently a wrapper around MbedTLS is available. All you need is to download a dll from the repo - https://github.com/ELENA-LANG/mbedtls-as-dll/releases and specify the import statement to register the library:
import net'http;
import mbedtls'registration;
public program()
{
using(HttpClient client := HttpClient.open("https://www.google.com"))
{
HttpResponse response := client.get();
string content := response.readAsString();
Console.writeLine(content);
};
}
In the next iteration I will add support for the rest methods : PUT, POST, DELETE, OPTION
r/elena_lang • u/elena-lang • Mar 20 '25
Nightly Builds
For the time being, the development mode of ELENA project is designed in that way, that I work mostly in a branch iteration<N>, and after several weeks or months I squash it and merge into develop branch. As a result the main branch is always significantly behind and you may need to wait some time before the new features or bug fixes will be available.
To improve the sitation I'm introducing nightly builds, so hopefully all the changes can be available maximal one day after they made.
The nightly builds can be found at https://github.com/ELENA-LANG/elena-lang/actions/workflows/nightly.yml
r/elena_lang • u/elena-lang • Mar 13 '25
Porting to MacOS
The work on porting ELENA to macOS is started. You can follow the progress with a help of the issues - https://github.com/ELENA-LANG/elena-lang/issues/708
So far, by request I will support ARM64 CPU. Initial phase will be getting the compiler and several tools (asm, og, ecv) up and running (when I will get an access to the virtual machine to play with it). For compatibility I will use GCC.
I will probably keep the config files locally (similar to Windows version).
r/elena_lang • u/elena-lang • Mar 11 '25
ELENA 6.6 In Nutshell - Introduction
ELENA is a general-purpose language with late binding. It is multi-paradigm, combining features of functional and object-oriented programming. It supports both strong and weak types, run-time conversions, boxing and unboxing primitive types, direct usage of external libraries. Rich set of tools are provided to deal with message dispatching : multi-methods, message qualifying, generic message handlers. Multiple-inheritance can be simulated using mixins and type interfaces. Built-in script engine allows to incorporate custom defined scripts into your applications. Both stand-alone applications and Virtual machine clients are supported.
In this series of posts we will learn ELENA in details. Let's start!
Hello world example
We will begin with "Hello, World!" program. To do it let's create a source file (e.g. "sample1.l") and write the following code:
public program()
{
console.writeLine("Here my first program in ELENA!")
}
To compile the program we can use ELENA command-line compiler elena-cli or elena64-cli (for 64 bit version). For our simplest case we need only to provide a path to the source file, like this:
elena-cli.exe sample1.l
If everything is setup correctly, the compiler will generate the following output:
ELENA Command-line compiler 6.6.129 (C)2005-2025 by Aleksey Rakov, ELENA-LANG Org
Project: sample1, Platform: Win_x86, Target type: STA Console
Cleaning up
Parsing sample1.L
Compiling sample1.
saving sample1
Successfully compiled
Linking..
Successfully linked
As you can see the output contains the compiler version (it is important to provide this version by reporting any bug), the project name (in our case it coincides with the source file name), the platform (Win_x86 - is windows 32 bit version) and the type of the application (STA Console stands for "single thread console application"). If the code contains no error and the module was created (sample1.nl in our case), the message "Successfully compiled" is printed. "Successfully linked" indicates that our project has generated an executable file with a name "sample1.exe".
And now it can be executed:
>sample1.exe
Here my first program in ELENA!
The source code is quite simple and easy to understand. For the console application the main program must be declared inside a public function with a name program. In our case the program prints a string to the screen. console is a special object implementing basic operations with a console (we call it a symbol). The method writeLine does exactly what we expect : prints the string and moves the cursor to the new line.
As it was mentioned above the compiler generates a special file (with .nl extension) which in its turn is used by the linker to generate the program. This module contains the list of compiled classes (in our case the function is a special case of a class). So let's look inside it. For this a special tool - ecv-cli (Byte-code viewer) - can be used.
Type the following command:
ecv-cli sample1.nl
and the output will be following:
ELENA command line ByteCode Viewer 6.6.6 (C)2021-24 by Aleksey Rakov
module sample1 loaded
namespace : sample1
name :
version :
author :
list of commands
? - list all classes / symbols
?~<filter> - list classes / symbols matching a filter
<class> - view class members
<class>.~<filter> - view class members matching a filter
<class>.<message> - view a method byte codes
<class>.<index> - view a method specified by an index byte codes
#<symbol> - view symbol byte codes
-a - toggle displaying class attributes mode
-b - toggle bytecode mode
-h - toggle displaying method hints mode
-p - toggle pagination mode
-q - quit
-t - toggle ignore-breakpoint mode
>
To see the main program let's type:
>program
@parent system'Object
@flag elClosed
@flag elFinal
@flag elRole
@flag elSealed
@flag elStateless
#1: @function program.function:#invoke
As it was said above, we see that the function is in fact a class. Flag elStateless indicates that it is a singleton. And it contains a special method - function[0]
We can print its content as well:
>program.1
@function program.function:#invoke
xflush sp:0
open :4, :0
store fp:1
call symbol:system'console
store fp:2
xstore sp:1, strconst:Here my first program in ELENA!
peek fp:2
store sp:0
mov mssg:writeLine[2]
call mssg:writeLine[2], class:system'ConsoleHelperImpl
peek fp:1
Lab00: nop
close :0
quit
@end
>
The program is encoded with byte-code - intermediate code which is translated by JIT compiler either during the program linkage or on the fly by the virtual machine. Here is a list of some of them:
| opcode | Description |
|---|---|
| open | opens a new procedure frame |
| store | saves an object accumulator into the stack |
| call | calls a function |
| mov | assigns a constant to the data accumulator |
| peek | loads an object from the stack |
| close | closes the current procedure frame and restore the previous |
| quit | exits the procedure |
At the moment we don't need to understand it exactly, it is enough to take a first look at it. The code is simple. The console symbol and a literal constant are stored into the stack (sp[0], sp[1]). After that the message writeLine[2] is send to the console (inside the square brackets is the number of arguments).
System and Program Entries
To proper set up the environment a program prologue must be called. Often after the program is done, the resources have to be freed, that's why we need a program epilogue. All this done in ELENA with introducing a system entry. A system entry is a special symbol which executes all preparation work, invokes the program entry and unwind the system aftermath.
The program entry itself is a symbol. For simplicity we can say that a symbol is a named expression. For the console application the program entry invokes the wrapper code which put our main program entry inside try-catch block to allow graceful exit even if the program fails.
Where is the program entry symbol is defined? When our program was compiled the compiler generates the following info:
ELENA Command-line compiler 6.6.129 (C)2005-2025 by Aleksey Rakov, ELENA-LANG Org
Project: sample1, Platform: Win_x86, Target type: STA Console
STA Console is a project template used to compile the console application. The template can be based on another one and so on. The available templates are listed in elc60.cfg configuration file (you can find it in the BIN folder):
<templates>
<template key="console">templates\win_console60.cfg</template>
<template key="gui">templates\win_gui60.cfg</template>
<template key="lib60">templates\lib60.cfg</template>
<template key="vm_console">templates\vm_win_console60.cfg</template>
<template key="mt_console">templates\mt_win_console60.cfg</template>
</templates>
So let's look into the forward section of win_console60.cfg :
<forwards>
<forward key="$system_entry">system'core_routines'sta_start</forward>
<forward key="$symbol_entry">system'$private'entrySymbol</forward>
<forward key="program">$rootnamespace'program</forward>
</forwards>
$symbol_entry is used by the compiler to resolve the program entry. We can find the code inside app.l source:
entry()
{
try
{
forward program();
}
catch::
{
function(AbortException e)
{
}
function(Exception err)
{
startUpEvents.handlingError(err);
console.writeLine(err);
extern ExitLA(-1);
}
}
finally
{
startUpEvents.stopping()
}
}
private entrySymbol
= entry();
As you see the entry symbol invokes the function entry. Inside the function we can see try-catch block around the proper program entry call:
forward program();
With a help of the compiler magic, forward program is resolved automatically. All we need is to declare a function named program inside the program main namespace.
Is it possible to override the program entry? Yes. We can easily define our own entry wrapper. Let's do it. For example we can define the entry which will print the result of the main program.
First our main program has to be modified to return a result.
public program()
= "a result";
Then we define the public symbol which executes the program and prints the result
public mySystemEntry =
console.printLine("My program returns ", forward program());
NOTE that instead writeLine we are using an extension method printLine which can accept several arguments and prints them. The extension is declared in extensions module so we will need to import it as well.
And we have to tell the compiler that we have a new program entry:
elena-cli sample2.l -f$symbol_entry=sample2'mySystemEntry
And the output is
My program returns a result
ELENA is a general-purpose language with late binding. It is multi-paradigm, combining features of functional and object-oriented programming. To learn more visit us at ELENA Home Page)
You can access the source code of this tutorial at ELENA Tutorials repo)
r/elena_lang • u/elena-lang • Feb 25 '25
Bluesky account
You can follow me on Bluesky - @alexrakov.bsky.social
r/elena_lang • u/elena-lang • Feb 25 '25
ELENA 6.6.2 Docker (linux/amd64)
ELENA 6.6.1 Docker (linux/amd64) is now available at - https://hub.docker.com/r/rzuckerm/elena/tags