Releases: rochus-keller/Oberon
Exception handling and some other new language features
Based on practical experience and discussions with other developers, this release officially adds the following new elements to the language.
Exception Handling
See here for a discussion and derivation.
See here for the specs.
Here is an example as implemented in this release:
module ExceptionExample
type Exception = record end
proc Print(in str: array of char)
var e: pointer to Exception
begin
println(str)
new(e)
raise(e)
println("this is not printed")
end Print
var res: pointer to anyrec
begin
pcall(res, Print, "Hello World")
case res of
| Exception: println("got Exception")
| anyrec: println("got anyrec")
| nil: println("no exception")
else
println("unknown exception")
// could call raise(res) here to propagate the exception
end
end ExceptionExample
Source code directives and conditional compilation
Oberon+ uses a syntax as suggested in the Oakwood guidelines.
See here for the specs.
Here is an example as implemented in this release:
<* AAA+ *>
<* BBB- *>
<* if AAA then *>
println("compiled for AAA")
<* elsif BBB & ~CCC then *>
println("compiled for BBB & ~CCC")
<* else *>
println("something else")
<* end *>
Variable length arrays (VLA)
In contrast to array pointers allocated with new(), variable length arrays (VLA) can be allocated on the stack instead of the heap, which makes them attractive to low-resource embedded applications where dynamic memory allocation is not feasible.
Here is an example as implemented in this release:
module VlaExample
proc Test(n, m: integer)
var i,j: integer; a: array var n, m of integer
begin
for i := 0 to n -1 do
for j := 0 to m-1 do
a[i,j] := i*j*2
end
end
println(a[2,3])
end Test
begin
Test(4,5)
end VlaExample
Non-local access
Oberon+ now also supports access to outer parameters and local variables from nested procedures (non-local access), as it was available in original Oberon and Oberon-2, but removed in Oberon-07.
Previous versions of Oberon+ followed Oberon-07 and didn’t support this feature, mostly because the "classic" implementation by "static links" doesn’t fit CIL/ECMA-335 or C99 backends; this version of Oberon+ supports an implementation based on hidden var parameters, which is feasible with the mentioned backends.
With this addition Oberon+ is now fully backwards compatible, i.e. each valid Oberon, Oberon-2 or Oberon-07 program is also a valid Oberon+ program.
Here is an example as implemented in this release:
module NlaExample
proc Outer()
var a,b,c: integer
proc Mid1( i: integer )
var d: integer
proc Inner( i: integer )
begin
a := a + i; d := i
Mid2(11)
end Inner
begin
b := b + i
Inner(12)
end Mid1
proc Mid2( i: integer )
begin
c := c + i
end Mid2
begin
a := 0; b := 0; c := 0
Mid1( 13 ) // calls Inner -> Mid2
Mid2( 14 )
println(a) // 12
println(b) // 13
println(c) // 11 + 14 = 25
end Outer
begin
Outer
end NlaExample
Precompiled versions
Here are the pre-compiled versions of the IDE (download, unpack/mount and run, no installation requried):
http://software.rochus-keller.ch/OberonIDE_win32.zip
http://software.rochus-keller.ch/OberonIDE_win64.zip
http://software.rochus-keller.ch/OberonIDE_macOS_x64.dmg
http://software.rochus-keller.ch/OberonIDE_linux_i386.tar.gz
http://software.rochus-keller.ch/OberonIDE_linux_x86_64.tar.gz
See also https://github.com/rochus-keller/Oberon/blob/master/README.md and http://oberon-lang.ch/.
Cross-platform OS abstraction and GUI library MVP
I'm pleased to announce the MVP release of the NAppGUI binding for Oberon+.
NAppGUI is a great, lean cross-platform OS abstraction and GUI library written and very well documented by Francisco García Collado. It perfectly matches Wirth's philosophy of simplicity, which he had already based his programming language Oberon on.
Francisco writes "I started working on this project [...] in mid 2008 when I was finishing my Computer Engineering studies at the University of Alicante. I wanted to develop a physical systems simulator that worked both on PC-Windows computers and Apple iMac without having to duplicate all the work. The technological alternatives of the time, such as GTK or Qt, did not convince me at all as they were too heavy, complicated to use and slow so they would end up tarnishing the quality, elegance and commitment that I was putting into my mathematical calculation algorithms. [...] In the middle of 2015, I began to think about the fact that all the technical effort made during these years is enough to become a product by itself. It was then that I created the NAppGUI project and started to migrate all the iMech libraries devoted to multiplatform development. [...] On September 31, 2019, I upload the first public version of NAppGUI." And as we know, in September 2021 he generously made the source code available to the public under a very liberal license.
Oberon+ uses a shared library version of NAppGUI via its FFI language. I converted the NAppGUI C header files using the C preprocessor and my C2OBX tool and then manually adjusted the generated external library modules as required when I migrated some of the NAppGUI demo applications to Oberon+. Only a few extensions in the Oberon+ language were needed, and thanks to the FFI language the code still looks quite similar to the examples in the NAppGUI documentation, which allows their reuse. Here is all you need to start: https://github.com/rochus-keller/Oberon/tree/master/testcases/NAppGUI; the directory contains the NAppCore, NAppDraw and NAppWidgets external library modules and some examples; it's easiest to begin with an example, e.g. Fractals. The examples are included with the pre-compiled versions of the Oberon IDE (see below).
Here is a screenshot of the Fractals application running in the IDE:
Note that you can run the exact same application either with the compiled CLI bytecode under Mono or with the C99 transpiled code with any compatible C compiler on any platform supported by NAppGUI!
Here are the pre-compiled versions of the IDE with included NAppGUI shared library version for each platform (download, unpack/mount and run, no installation requried):
http://software.rochus-keller.ch/OberonIDE_win32.zip
http://software.rochus-keller.ch/OberonIDE_macOS_x64.dmg
http://software.rochus-keller.ch/OberonIDE_linux_i386.tar.gz
Note that some versions of WebKit (i.e. macOS) seem to refuse to download from http; in this case please use another tool like e.g. wget.
See also https://github.com/rochus-keller/Oberon/blob/master/README.md and http://oberon-lang.ch.
Oberon+ cross-platform FFI language MVP
I'm pleased to announce the MVP release of the Oberon+ foreign function interface (FFI) language.
The FFI language is a first-class citizen of Oberon+ and allows the use of existing C shared libraries in Oberon+ applications and thus the reuse of a huge pool of proven libraries without having to program directly in C and without adaptation/integration efforts. And yes, if the library is available on different platforms/architectures, an Oberon+ program can access these libraries directly and unmodified on all these platforms/architectures.
Here is the section of the FFI language in The Programming Language Oberon+, and here is a background article.
The FFI language is now implemented in both the CLI bytecode generator and also the new C99 transpiler.
As an example here is the CLI version of the Oberon System using the well-known SDL2 library as a cross-platform keyboard/mouse/window abstraction: OberonSystem_ObxIDE_CIL_2021-12-30.zip. And here is the corresponding C99 version: OberonSystem_ObxIDE_Cgen_2021-12-30.zip; it was generated with the "Build & Run/Export C" menu item of the IDE and can be compiled e.g. with GCC using gcc -O2 --std=c99 *.c -lm -o obs
or with MSVC using cl /O2 /MD /Fe:obs.exe *.c
. To run the example you need the SDL2 shared library; it can e.g. be downloaded from here or installed from your Linux distribution (actually only the SDL2.dll/.so/.dylib file is required; the file is included in the pre-compiled versions of the IDE, see below).
Here is the code where the Oberon System uses the SDL library. And here is the Oberon+ external library module of the SDL2 library; it was automatically generated from the SDL2 C header files using my C2OBX tool with just a few manual adjustments.
Here are the pre-compiled versions of the IDE with integrated CLI and C99 compiler (download, unpack/mount and run, no installation requried):
http://software.rochus-keller.ch/OberonIDE_win32.zip (a copy is also attached to this post, see below)
http://software.rochus-keller.ch/OberonIDE_macOS_x64.dmg (a copy is also attached to this post, see below)
http://software.rochus-keller.ch/OberonIDE_linux_i386.tar.gz
See also https://github.com/rochus-keller/Oberon/blob/master/README.md and http://oberon-lang.ch.
🎉 🎆 🎊 HAPPY NEW YEAR!
Oberon+ to C99 transpiler MVP
I'm proud to present the MVP version of the Oberon+ to C99 transpiler. It is integrated with the Oberon+ IDE 0.9.28 and can be run with the "Build & Run/Export C" menu item. The transpiler generates C code compatible with ISO 9899:1999 with no other dependencies than the C standard library and the Boehm-Demers-Weiser garbage collector (libgc).
The current version of the transpiler passes all tests and runs all benchmarks, but only a subset of Oakwood is implemented and the FFI is pending as well.
Update 2021-12-30: Both FFI and the Oakwood library are ready.
The generated C code performs about twice as good as the generated CLI assemblies under Mono 5 when compiled with GCC or CLANG with -O2 optimizations. Here is the report with the Linux Are-we-fast-yet results.
I did measurements with different GCC and CLANG versions (on i386 and x86_64) as well as with TCC. The code compiled with TCC runs half as fast as when compiled with GCC -O2; even the GCC result without optimizations is a bit faster than the TCC generated executable. CLANG on the other hand generates code with about the same overall performance (geomean over all benchmarks) as GCC. Interestingly the Havlak benchmark produces a segfault when compiled with GCC -O2, but not with GCC and no optimizations; Havlak generated with CLANG -O2 or TCC works without segfaults. Here is the table with the detailed results in case you're interested. And here is the generated C code of the benchmark suite in case you want to run it yourself; just unpack the ZIP to a directory and run "cc -O2 --std=c99 *.c -lm -DOBX_USE_BOEHM_GC -lgc" there (with cc either gcc or clang, provided libgc-dev is installed); note that the Havlak is commented out in Tester.c (enable it when using CLANG).
Update 2021-12-30: the C99 code generated with IDE version 0.9.38 no longer produces a segfault when compiled with GCC -O2. Here is the generated C code of the benchmark suite.
Here are the binary versions of the IDE with integrated C transpiler (download, unpack/mount and run, no installation requried):
http://software.rochus-keller.ch/OberonIDE_win32.zip (use the Mono version of the IDE)
http://software.rochus-keller.ch/OberonIDE_macOS_x64.dmg
http://software.rochus-keller.ch/OberonIDE_linux_i386.tar.gz
See also https://github.com/rochus-keller/Oberon/blob/master/README.md and http://oberon-lang.ch.
Oberon+ IDE (Mono) MVP release
I'm proud to present the CLI/Mono version of the Oberon+ IDE as an alternative (and replacement in medium term) of the LuaJIT based IDE and toolchain.
Mono is a great technology and very well suited as an Oberon+ runtime environment. In contrast to LuaJIT it supports static typing on bytecode level and a corresponding speed-up. I did measurements with the Are-we-fast-yet benchmark suite and found a speedup factor 2.5 on Linux compared to LuaJIT (see this report for more information). Mono is still sufficiently fast compared to the new CoreCLR engine from Microsoft; I did measurements with different versions of Mono and CoreCLR and found performance differences to be within 30% (see this article for more information). I prefer Mono over CoreCLR because of wider platform support, the soft-debugger wire protocol (which the Oberon+ IDE uses) and the lean minimal configuration (less than 10 MB).
LuaJIT is still an impressive piece of work; but apparently I reached the limits of the concept; even after days of debugging there are still misterious crashes in the tracing JIT after successfully running several thousand iterations of the same benchmark (no crashes if the JIT is turned off, but of course at the expense of performance). The same applies to the FFI, which runs fine with the basic SDL test case, but crashes when I use the same SDL FFI for the Oberon System.
Mono seems more stable so far, even if I use version 3 of it. It is a bit less lean than LuaJIT, but much faster; especially the debugger is much faster; whereas in LuaJIT running in debug mode was much slower (and thus breakpoints only of limited use because of which I added the trap() procedure to the language) the speed-down in Mono is negligible; setting a breakpoint somewhere in Are-we-fast-yet and running the app until the breakpoint is hit takes only a second (instead of up to several minutes with LuaJIT). Also fetching local values is more convenient and I could even implement incremental fetching which is very well supported by the wire protocol. Mono runs on its own process controlled by the IDE. My implementation of the wire protocol is in https://github.com/rochus-keller/monotools/; this repository also includes my implementation of the MDB (debug symbols) generator; the code generator is based on my modified version of the DotNetPELib: https://github.com/rochus-keller/pelib/. Thanks to these implementations I am not dependent on the .NET framework and its toolchain.
Here are binary versions (download, unpack/mount and run, no installation requried) for Windows and macOS:
http://software.rochus-keller.ch/OberonIDE_win32.zip (includes both the LuaJIT and Mono versions of the IDE and command line tools)
http://software.rochus-keller.ch/OberonIDE_macOS_x64.dmg (includes the Mono version of the IDE and LuaJIT and Mono versions of the command line tools).
http://software.rochus-keller.ch/OberonIDE_linux_i386.tar.gz (includes the Mono version of the IDE and command line tool; Qt 5.4.2 is statically linked)
This version of Oberon+ IDE (Mono) doesn't yet support the Oberon+ FFI concept; it's the next item on my list, so check back in case you need it.
See also https://github.com/rochus-keller/Oberon/blob/master/README.md and http://oberon-lang.ch.
Oberon+ MVP release
After six month of development and testing I'm proud to present the MVP release of the Oberon+ programming language and compiler, together with a lean but powerful IDE. The compiler currently generates LuaJIT 2.0 bytecode (other backends will follow).
The full Are-we-fast-yet benchmark suite has been ported to Oberon+ as a proof-of-concept, demonstrating all relevant language features including generic modules and their application.
Oberon+ is the Oberon I personally would have hoped for, which doesn't force me to capitalize keywords, where I can omit semicolons and most of the commas, and which supports generic programming without giving up simplicity.
Here is a pre-comiled Win32 version of the Oberon+ IDE: http://software.rochus-keller.ch/OberonIDE_win32.zip.
Here is a pre-compiled macOS version: http://software.rochus-keller.ch/OberonIDE_macOS_x64.dmg
The ZIP/DMG can just be unpacked/mounted and the application double-clicked; no other installation required. The ZIP/DMG includes the language specification and representative example projects.
For more information see https://github.com/rochus-keller/Oberon/blob/master/README.md.
Oberon IDE mvp release
After about two months of work I'm glad to release the new Oberon IDE with integrated source level debugger. The IDE makes use of my new validating Oberon-07 parser/AST and LuaJIT 2.0 bytecode generator. Code is compiled on the fly while typing and can immediately be run and inspected with the built-in LuaJIT VM. As with the OberonViewer there is syntax coloring and semantic highlighting/navigation. When a runtime exception occurs the stack and local variables are automatically displayed even if not in the debugger.
This project is a proof-of-concept to show that it is feasible to re-use LuaJIT for strongly/statically typed languages and directly generate LuaJIT bytecode (instead of using Lua as an intermediate language). See here for more information about the motivation of the project: https://medium.com/@rochus.keller/implementing-call-by-reference-and-call-by-name-in-lua-47b9d1003cc2. To my knowledge this is the only (working) compiler generating LuaJIT bytecode besides the original Lua compiler by Mike Pall.
Here is a link to a pre-comiled Win32 version of the Oberon IDE: http://software.rochus-keller.info/OberonIDE_win32.zip. The ZIP can just be unpacked and the exe double-clicked; no other installation required. The ZIP includes a version of the Oberon System (from https://github.com/rochus-keller/OberonSystem) to analyze and play around with (note that the middle mouse button is emulated by CTRL+ left click).
See the readme file (https://github.com/rochus-keller/Oberon/blob/master/README.md) for more information and some screenshots.
Feature Release
C++ generator now also emits FOR statement which allows to translate the OR package.
Supports language version "Oberon+" with lower-case keywords and built-ins, underscores in idents and line comments.
Includes a separate Oberon to Lua converter supporting the full Oberon syntax and semantics (see OBNLC.pro).
Feature Release
The C++ generator now uses the DIV and MOD functions of _Root instead of the C++ "/" and "%" operators because of the special way these operations are handled in Oberon (e.g. (-1) DIV 16 equals to -1, not to zero).
Feature Release
This release adds a C++ code generator as a stand-alone command line application (OBNCPP) and integrated with OberonViewer.
Current features:
- Generates C++03 compatible code with no other dependencies than the standard libraries
- Generates stub headers for the synthesized (missing) modules to ease implementing the missing parts
- Arrays including strings are implemented by C++ template classes
- Modules are dynamically created to maintain the correct initialization dependencies
- Comments of the original files are also translated
- Oberon idents conflicting with C++ keywords are postfixed by underscore
- The generated code is well readable and maintainable
Note that currently only the subset of Oberon-07 used by the Lola-2 compiler is supported; see https://github.com/rochus-keller/Lolac for an example of the generated code.
Also note that there is no garbage collector code generated yet, but an arena based collector can easily be implemented outside of the generator by customizing the _Root class; future versions will generate a regular mark & sweep collector.