Trending

#PLdev

Latest posts tagged with #PLdev on Bluesky

Latest Top
Trending

Posts tagged #PLdev

Video

Fun stuff is happening

#playdate #pldev #badlang

2 0 0 0
Video

Do you ever wake up and think? "wouldn't it be fun to make a sample player for the #PlayDate console in your own programming language?" #PLDev #badlang

2 0 0 0

Is there are a working _interactive_ low-level Language Server Protocol client anywhere?

I'm very specifically looking to poke at an existing implementation to see how it works in context, not make my own (plenty of tooling for that, somehow!)

:boost_requested:

#programming #pldev

2 1 0 0
A Short Survey of Compiler Backends As an amateur compiler developer, one of the decisions I struggle with is deciding choosing the compiler backends. Unlike the 80’s when people had to target various machine architectures directly, now there are many mature options available. This is a short and very incomplete survey of some of the popular and interesting options. ### Contents 1. Machine Code / Assembly 2. Intermediate Representations 3. Other High-level Languages 4. Virtual Machines / Bytecode 5. WebAssembly 6. Meta-tracing Frameworks 7. Unconventional Backends 8. Conclusion ## Machine Code / Assembly A compiler can always directly output machine code or assembly targeted for one or more architectures. A well-known example is the Tiny C Compiler. It’s known for its speed and small size, and it can compile and run C code on the fly. Another such example is Turbo Pascal. You could do this with your compiler too, but you’ll have to figure out the intricacies of the _Instruction set_ of each architecture (ISA) you want to target, as well as, concepts like register allocation. ## Intermediate Representations Most modern compilers actually don’t emit machine code or assembly directly. They lower the source code down to a language-agnostic _Intermediate representation_ (IR) first, and then generate machine code for major architectures (x86-64, ARM64, etc.) from it. The most prominent tool in this space is LLVM. It’s a large, open-source compiler-as-a-library. Compilers for many languages such as Rust, Swift, C/C++ (via Clang), and Julia use LLVM as an IR to emit machine code. An alternative is the GNU C compiler (GCC), via its GIMPLE IR, though no compilers seem to use it directly. GCC can be used as a library to compile code, much like LLVM, via libgccjit. It is used in Emacs to _Just-in-time_ (JIT) compile Elisp. Cranelift is another new option in this space, though it supports only few ISAs. For those who find LLVM or GCC too large or slow to compile, minimalist alternatives exist. QBE is a small backend focused on simplicity, targeting “70% of the performance in 10% of the code”. It’s used by the language Hare that prioritizes fast compile times. Another option is libFIRM, which uses a graph-based SSA representation instead of a linear IR. ## Other High-level Languages Sometimes you are okay with letting other compilers/runtimes take care of the heavy lifting. You can transpile your code to a another established high-level language and leverage that language’s existing compiler/runtime and toolchain. A common target in such cases is C. Since C compilers exist for nearly all platforms, generating C code makes your language highly portable. This is the strategy used by Chicken Scheme and Vala. Or you could compile to C++ instead, like Jank, if that’s your thing. Another ubiquitous target is JavaScript (JS), which is one of the two options (other being WebAssembly) for running code natively in a web browser or one of the JS runtimes (Node, Deno, Bun). Multiple languages such as TypeScript, PureScript, Reason, ClojureScript, Dart and Elm transpile to JS. Nim interestingly, can transpile to C, C++ or JS. A more niche approach is to target a Lisp dialect. Compiling to Chez Scheme, for example, allows you to leverage its macro system, runtime, and compiler. The Idris 2 and Racket use Chez Scheme as their primary backends. ## Virtual Machines / Bytecode This is a common choice for application languages. You compile to a portable bytecode for a _Virtual machine_ (VM). VMs generally come with features like _Garbage collection_ , _JIT compilation_ , and security sandboxing. The Java Virtual Machine (JVM) is probably the most popular one. It’s the target for many languages including Java, Kotlin, Scala, Groovy, and Clojure. Its main competitor is the Common Language Runtime, originally developed by Microsoft, which is targeted by languages such as C#, F#, and Visual Basic.NET. Another notable VM is the BEAM, originally built for Erlang. The BEAM VM isn’t built for raw computation speed but for high concurrency, fault tolerance, and reliability. Recently, new languages such as Elixir and Gleam have been created to target it. Finally, this category also includes MoarVM—the spiritual successor to the Parrot VM—built for the Raku (formerly Perl 6) language, and the LuaJIT VM for Lua, and other languages that transpile to Lua, such as MoonScript and Fennel. ## WebAssembly WebAssembly (Wasm) is a relatively new target. It’s a portable binary instruction format focused on security and efficiency. Wasm is supported by all major browsers, but not limited to them. The _WebAssembly System Interface_ (WASI) standard provides APIs for running Wasm in non-browser and non-JS environments. Wasm is now targeted by many languages such as Rust, C/C++, Go, Kotlin, Scala, Zig, and Haskell. ## Meta-tracing Frameworks _Meta-tracing Frameworks_ are a more complex category. These are not the backend you target in your compiler, instead, you use them to build a custom JIT compiler for your language by specifying an interpreter for it. The most well-known example is PyPy, an implementation of Python, created using the RPython framework. Another such framework is GraalVM/Truffle, a polyglot VM and meta-tracing framework from Oracle. Its main feature is zero-cost interoperability: code from GraalJS, TruffleRuby, and GraalPy can all run on the same VM, and can call each other directly. ## Unconventional Backends Move past the mainstream, and you’ll discover a world of unconventional and esoteric compiler backends. Developers pick them for academic curiosity, artistic expression, or to test the boundaries of viable compilation targets. * Brainfuck: An esoteric language with only eight commands, Brainfuck is _Turing-complete_ and has been a target for compilers as a challenge. People have written compilers for C, Haskell and Lambda calculus. * Lambda calculus: Lambda calculus is a minimal programming languages that expresses computation solely as functions and their applications. It is often used as the target of educational compilers because of its simplicity, and its link to the fundamental nature of computation. Hell, a subset of Haskell, compiles to Simply typed lambda calculus. * SKI combinators: The SKI combinator calculus is even more minimal than lambda calculus. All programs in SKI calculus can be composed of only three combinators: S, K and I. MicroHs compiles a subset of Haskell to SKI calculus. * JSFuck: Did you know that you can write all possible JavaScript programs using only six characters `[]()!+`? Well, now you know. * Postscript: Postscript is also a Turing-complete programming language. Your next compiler could target it! * Regular Expressions? Lego? Cellular automata? ## Conclusion I’m going to write a compiler from C++ to JSFuck. If you have any questions or comments, please leave a comment below. If you liked this post, please share it. Thanks for reading!

I did a short survey of #compiler backends: abhinavsarkar.net/notes/2025-compiler-back...

#compilers #programming #pldev #langdev #blogging

1 3 0 0
Syntax Reference | Ohm This document describes the syntax of the Ohm language, which is a variant of parsing expression grammars (PEGs). If you have experience with PEGs, the Ohm syntax will mostly look familiar, but there ...

I’m tempted to write my programming language with a simplified ohm grammar engine, so that you can extend the language directly.

ohmjs.org/docs/syntax-...

#PLdev #KonaScript

1 0 0 0

After several rewrite, and the implementation of a typed AST (instead of having to evaluate any expression at least twice), I added imports (or "remixes") of Miku lang files. I need to think about other languages (i.e. C lib for instance) now #PLDev

0 0 0 0
Preview
Code in Miku lang, generated C and output Code in Miku lang, generated C and output. GitHub Gist: instantly share code, notes, and snippets.

Just one more compiler...
I've made a language based on music (because Hatsune Miku) but it's basically Java in a trench coat.
and I've implemented enough to be able to write small programs. #PLDev gist.github.com/minirop/061a...

4 1 1 0

I started working on a small programming language that compiles to Lua so that I can work on a Play date game.

I didn’t have to start from scratch! I had written quite a bit las year when working on Kona. #PLdev

0 0 0 0
Preview
'Hello world' in Bismuth This is the third in a series of posts about a virtual machine I’m developing as a hobby project called Bismuth. I’ve talked a lot about Bismuth, mostly on social media, but I don’t think I’ve done a ...

New Bismuth VM blog post, detailing the life cycle of a hello world program for Bismuth from high level Bronze code to text-based IR, transpiled C, binary IR, and finally bytecode: enikofox.com/posts/hello-...

#BismuthVM #PLDev

76 22 2 0
pin hsource as psource {
    pin hdest as pdest {
        while unsigned(height > 0) {
            let srcend = srcoff + widthMinusOne;
        
            while unsigned(srcoff <= srcend) {
                let v = ploadu8(psource, srcoff);
                if v: pstorei8(pdest, destoff, v);
                srcoff = srcoff + 1;
                destoff = destoff + 1;
            }

            srcoff = srcoff + srcstep;
            destoff = destoff + deststep;
            
            height = height - 1;
        }
    }
}

pin hsource as psource { pin hdest as pdest { while unsigned(height > 0) { let srcend = srcoff + widthMinusOne; while unsigned(srcoff <= srcend) { let v = ploadu8(psource, srcoff); if v: pstorei8(pdest, destoff, v); srcoff = srcoff + 1; destoff = destoff + 1; } srcoff = srcoff + srcstep; destoff = destoff + deststep; height = height - 1; } } }

now that handle pinning is implemented in my VM i can use it to speed up my VM's blit routine

this is Bronze code, which is converted to my VM's intermediate representation, which is then transpiled to C so i can integrate it into my VM :3

and now the core of my VM is finally done! \o/

#PLDev

30 1 1 0

VM development update: I have done a bunch of rewriting to make things more secure and also have now paved the way for types larger than 32 bits

#PLDev

24 0 2 0

suppose i should do an update here on my VM. it now has try/catch/finally with a fixed format for exception objects which are automatically freed when leaving the catch block

if i can get handle locking/pinning in so i can have direct safe access to pointers i will consider the core done

#PLDev

16 0 1 0
geordi laforge nah yea meme saying

nah: creating new programming languages because it's fun and interesting

yea: creating new programming languages so LLM's won't know how to use them

geordi laforge nah yea meme saying nah: creating new programming languages because it's fun and interesting yea: creating new programming languages so LLM's won't know how to use them

#PLDev

361 48 4 3

If you're getting into #PLDev and writing parsers the first thing you should know is that doing everything in a single pass is fucking hard. Parsing an AST and Doing multiple passes over that (resolving symbols, guaranteeing return values, type checking) is like a bazillion times easier

23 0 0 1

thinking about my #PLDev project. i was gonna make it like C, but now i'm thinking since i have a reusable IR and VM so multiple languages can easily target it, maybe my first language should hew closely to the actual IR?

so i can write "raw" IR but without the lots of parentheses of s-expressions

12 0 1 0

making good progress on my parser, and now i'm thinking of committing some crimes >:3

that being having both `and` and `&&`, and `or` and `||`, where the latter coerces to bool and the former does not and acts like lua >_>

#PLDev

53 2 7 1
expression !(5 - 4 > 3 * 2 == !true) parsed with proper precedence

expression !(5 - 4 > 3 * 2 == !true) parsed with proper precedence

okay, got basic expressions going. a little slower going than i'd like since i'm adapting the crafting interpreters code to C# and building an AST of nodes instead of emitting single pass bytecode

#PLDev

18 0 1 0
Original post on fantastic.earth

For my next #compiler project, I want to write the optimization passes myself, but I don't want to deal with generating machine code for multiple platforms. So tell me #programminglanguages #plt #compilers fedi, what is an IR that I can target that has a non-optimizing compiler to machine code […]

0 0 0 0
Preview
Xenon

My programming language *Xenon* now has a website!
xenonlanguage.github.io
Check it out!
#programming #website #xenon #language #pldev #hashtag #okillstop

0 0 0 1
Badlang code with some conditional expression and the linear IR it produces.

Badlang code with some conditional expression and the linear IR it produces.

Work continues on the self-hosted implementation. A good chunk of the typechecking is done and am currently working on compilation to a linear IR that uses different basic blocks per function but is not on an SSA form. Trying to keep things simple for now.

#PLDev #Badlang

1 0 0 0
Small snippet of code of my simple lisp language:

(let x 1)
(print (switch x
	(case 0 "hello")
	(case 1 "world")
	"nobody"
))

Small snippet of code of my simple lisp language: (let x 1) (print (switch x (case 0 "hello") (case 1 "world") "nobody" ))

Assembly generated from the previous code (without the .data section):

.text
.globl main
main:
	pushq %rbp
	movq %rsp, %rbp
	movl $1, x(%rip)
	movq str1(%rip), %rsi
	leaq str3(%rip), %rdi
	movl $0, %eax
	callq printf
	movl $0, %eax
	leave
	ret

Assembly generated from the previous code (without the .data section): .text .globl main main: pushq %rbp movq %rsp, %rbp movl $1, x(%rip) movq str1(%rip), %rsi leaq str3(%rip), %rdi movl $0, %eax callq printf movl $0, %eax leave ret

I decided to give QBE (c9x.me/compile/) a shot for real and as a small codegen backend it's nice. This is a small code that compiles and the generated assembly. #PLDev #compiler

1 0 1 0
AST of the self-hosted implementation of a parser and the code that generates it

AST of the self-hosted implementation of a parser and the code that generates it

My self-hosted parser can now fully parse itself

#PLDev #badlang

1 0 1 0
badlang code and the equivalent AST representation, where multiple nodes are connected with nice looking arrows.

badlang code and the equivalent AST representation, where multiple nodes are connected with nice looking arrows.

Still lots to do, but the self-hosted parser is shaping up!

#pldev #badlang

0 0 0 0
a couple of expressions on a badlang program alongside the AST it generates, visualized with graphviz

a couple of expressions on a badlang program alongside the AST it generates, visualized with graphviz

A while ago I saw some amazing threads by @katef.bsky.social on "The Bad Place" where they advocated for printing the internal state of your compiler with graphviz. I was very impressed and been ever since trying to incorporate it in my work. It's back now on the self-hosted compiler #badlang #PLDev

36 5 2 0
raylib.bad\examples - bdl - Bad Diode's Lisp. Experiments with interpreters, compilers and VMs

I have imports on my language... I may have gotten a bit ahead of myself and ported most of Raylib's binding by hand... Definitely better to write some scripts for porting bindings in the future lol.

git.badd10de.dev/bdl/tree/exa...

#PLDev #badlang

1 0 0 0
Video

fun times with cellular automata, on my own programming language, using raylib
#PLDev #badlang

3 0 0 0
Video

Got far enough on my compiler today to be able to write the game of life using raylib. I'm so excited to be able to just link to libraylib.a and have this work without any other dependencies (the magic of compiling to C!). thanks @raysan5.bsky.social for making this amazing library!

#PLDev #badlang

4 1 1 0
badlang code for rule110 along with its output

badlang code for rule110 along with its output

We've have Turing completeness on the the C backend, exciting times!

#PLDev #Badlang

1 0 0 0
choice Result :: T {
    Ok: T
    Err
}

match Result::(Str).Ok("hello") {
    Ok(x) = x
    Err   = "error!"
}

match Result::(Int).Ok(123) {
    Ok(x) = x
    Err   = 4
}

choice Either :: (A B) {
    Left:  A
    Right: B
}

match Either::(Int S8).Left(123) {
    Left(x)  = x
    Right(y) = y
}

choice Result :: T { Ok: T Err } match Result::(Str).Ok("hello") { Ok(x) = x Err = "error!" } match Result::(Int).Ok(123) { Ok(x) = x Err = 4 } choice Either :: (A B) { Left: A Right: B } match Either::(Int S8).Left(123) { Left(x) = x Right(y) = y }

Polymorphic sum types? yes please! time to move on to codegen :)

#PLDev

1 0 0 0
some badlang code and the resulting type table:

struct Single :: T {
    x: T
    y: Int
}

; let err: Single ; This should fail, polymorphic type is not qualified.
let s0: Single::Int
s0
s0.x
; set s0.x = "hi" ; fails
set s0.x = 10     ; succeeds
let s1: Single::F64
s1
s1.x
set s1.x = 2.0  ; succeeds

struct Tuple :: (L R) {
    left: L
    right: R
}

let t0: Tuple::(Int Str)
t0
t0.left
t0.right
let t1: Tuple::(F32 S8)
t1
t1.left
t1.right

some badlang code and the resulting type table: struct Single :: T { x: T y: Int } ; let err: Single ; This should fail, polymorphic type is not qualified. let s0: Single::Int s0 s0.x ; set s0.x = "hi" ; fails set s0.x = 10 ; succeeds let s1: Single::F64 s1 s1.x set s1.x = 2.0 ; succeeds struct Tuple :: (L R) { left: L right: R } let t0: Tuple::(Int Str) t0 t0.left t0.right let t1: Tuple::(F32 S8) t1 t1.left t1.right

I'm also working on my own programming language (badlang), today I did a first implementation of typechecking for polymorphic struct/union types

#PLDev

1 0 1 0