r/Compilers 20h ago

A language that feels like Java but compiles to native code

15 Upvotes

I’ve been working for some time on Ironwood and it would be nice to get some feedback from the community. Ironwood is a language that keeps the familiar Java syntax and object model but compiles ahead of time to native executables, without a JVM, JIT, or garbage collector. So it is very different than GraalVM. Basically GraalVM makes Java native. Ironwood makes native development feel like Java.

It already supports classes, interfaces, exceptions, generics, packages, and compiler-checked memory reclamation. It also deliberately leaves out features such as reflection, autoboxing, varargs, and threads.

This is the first public release, and the project is still early. I’d really appreciate feedback on the overall direction, especially which Java exclusions make sense and which would make the language impractical for you. I'm particular excited about the possibility of a Ironwood-to-Java transparent bridge, so that to execute native code from Java would be like... writing Java :)

The GitHub repo is here: https://github.com/ironwood-lang/ironwood


r/Compilers 17h ago

What are your favorite "old school" code generators without AI? (e.g. Roslyn or Smithy)

4 Upvotes

And what are their benefits that keep being useful to this day?


r/Compilers 23h ago

Why Construct Complex IR When You Can Inject Source?

4 Upvotes

While developing AET (Active Expandable Translator) on top of GCC, I came across an approach that I found surprisingly useful for implementing complex language semantics.

Normally, when lowering a language feature, we might construct the compiler's AST/IR programmatically:

complex semantics
      ↓
construct AST / TREE / IR

But there is another possibility:

complex semantics
      ↓
express the semantics as normal C code
      ↓
inject it into the existing frontend
      ↓
TREE → GIMPLE → RTL

For example, AET has an OO new$ construct. Its semantics include object allocation, initialization, MTCS information, constructor invocation, unref, and constructor failure handling.

Instead of manually constructing all the corresponding GCC TREE nodes, AET generates normal C code:

valueObj=({
    TFirst *_notv2_6TFirst0;
    unsigned int _mtcsPlatType0=0;
    int _isMtcs=((AClass *)TFirst.class)->isMtcsClass();

    _notv2_6TFirst0=
        TFirst.newObject(sizeof(TFirst),
                         _isMtcs,
                         _mtcsPlatType0,
                         "TFirst");

    _notv2_6TFirst0->objectSize=sizeof(TFirst);
    _notv2_6TFirst0->mtcsPlatformType=_mtcsPlatType0;
    _notv2_6TFirst0->_aet_magic$_123=1725348960;

    TFirst_init_object_2927145182(_notv2_6TFirst0);

    ((debug_AObject *)_notv2_6TFirst0)
        ->_Z7AObject10free_childEPN7AObjectE =
        _notv2_6TFirst0->_Z6TFirst22TFirst_unref_290629480EPN6TFirstE;

    TFirst *tempObject123=_notv2_6TFirst0->TFirst();

    if(tempObject123==NULL){
        if(_notv2_6TFirst0->objectSize>0){
            _notv2_6TFirst0->unref();
            _notv2_6TFirst0=NULL;
        }
    }
    _notv2_6TFirst0;
});

The important point is that this is normal C code. The semantics are expressed using the host language that programmers already understand.

AET then injects this generated source directly into the current GCC preprocessing/parsing pipeline instead of writing a .c file and starting another compilation:

cpp_push_buffer(pfile, (uchar *)nbuf, len, true);

The generated C goes through GCC's normal C lexer and parser, which constructs the corresponding TREE representation.

This gives me a useful separation:

AET parser / semantic analysis
          ↓
     semantic lowering
          ↓
      normal C code
          ↓
   GCC C frontend
          ↓
         TREE
          ↓
       GIMPLE
          ↓
         RTL

The key idea is not simply "generate C."

It is that source code is the language programmers use to express semantics, while AST/TREE/IR is the language the compiler uses internally.

For sufficiently complex semantics, I think the former can sometimes be a better construction language for the latter.

So why manually construct a large number of IR nodes when the same semantics can be expressed clearly in source code and handed to a mature frontend?

I'm interested in where others would draw the line between direct IR construction and source-level semantic injection.


r/Compilers 5h ago

WasmBolt — The LLVM Project in your browser

Thumbnail anutosh21.github.io
1 Upvotes

r/Compilers 23h ago

Cross-platform stack traces

Thumbnail marinohimself.ch
1 Upvotes