home.social

#badlang — Public Fediverse posts

Live and recent posts from across the Fediverse tagged #badlang, aggregated by home.social.

  1. Ok I think I found a good name for my programming language. It's short and sweet and I haven't seen it used anywhere for other PL projects:

    The Oni programming language

    Named after the evil japanese yokai. Seems in-theme with the previous "badlang" name.

    I've acquired oni-lang.com and will be updating my repos to use the new name soon. Perhaps this is a good opportunity to start adding a website and documentation.

    #PLDev #badlang #onilang

  2. Yesterday I had the horrible realization that multiple people seems to have created programming languages called BadLang. To this end I think it’s probably time for me to choose a definitive name for my language. We floated the name of Badlands. But I need to ponder this a bit more. #pldev #badlang

  3. Made a little RMS/Peak meter that averages the measurement across N audio frames.

    #badlang #pldev #PlayDate

  4. Having a lot of fun with this, I sense a new toy project incoming :)

    This is using the wavreader from the badlang standard library with a custom playdate IO.Reader and a simple sample playback DSP code. All written in my own little language.

    #badlang #pldev #playdate

  5. Without too much trouble I managed to run Badlang code on the Playdate. Just had to override the panic function to use the pd system log and to create some wrapper functions.

    I also added a custom allocator, meaning I can use most of the relevant stuff from the standard library. Here is shown a directory list, a file being read (and the written) and timing information. Additionally I can draw using the system drawing functions (for text and sprites) and directly on the framebuffer (as seen on the grid behind).

    Perhaps I’ll have a bit more fun with this soon :)

    #badlang #pldev

  6. Started exploring Result::(Error, Val) types and implemented a `tryor` operator (??). The previous `try` operator (?) would unwrap or return the default zeroed value for the current function. With this new operator we can perform some extra action before returning and give our desired return type.

    Equivalent to:

    let a = funcall() ?? ret_expr
    let a = {
    let tmp = funcall()
    if not tmp.ok() then return ret_expr
    tmp.val()
    }

    Since `ret_expr` is an expression, you could log a message before returning or something like that.

    Pretty happy with this approach, I don't like to just blindly propagate an error, it needs to get handled somewhere or transform across type boundaries, which this should be able to handle.

    #badlang #pldev

  7. Back home. Been doing some light programming on the side, namely bugfixing, adding support for typed enums (still only integer types, but this way you can stuff enums into structs and arrays and control their size) and exploring adding type aliases.

    My initial implementation is super simple, just literally an alias so any function that takes the original type would also take the alias and vice-versa. Starting adding a more complex implementation where aliases are new types that could be casted back and forth between the original and alias implementation. This would become a hard typecheck failure if an alias is used instead of the original type and would enable having specific methods for aliased types.

    Unsure if the complexity is worth the cost for this particular feature. Thoughts?

    #badlang #pldev

  8. Following along Beej's networking guide [1] and implementing unix sockets bindings for Badlang. I thought it would be fun to make a simple HTTP server with this!

    The C sockets API is not very ergonomic so I'm planing some improvements to it, but gotta play a bit more with it first.

    [1]: beej.us/guide/bgnet/html/split

    #badlang #pldev

  9. Added some basic multi-threading primitives wrapping over threads.h

    #badlang #pldev

  10. Hello folks, I've updated the README of #badlang and would love to have some feedback (boost welcome).

    Still need to work on the documentation and language reference but I'm trying to touch on the general summary of the project.

    Let me know what you think!

    git.badd10de.dev/badlang/about

    #pldev

  11. I'm pretty happy with the current language at the moment, there may be a couple of extra small features I will consider adding before doing an official release. Most of the work now will go towards adding some stdlib stuff, and keep playing around with it, finding rough edges and having fun using it!

    For now I've made it so #! is also a comment, that way I can use source files directly as scripts which I think it's pretty neat.

    I've also added some initial tracing allocators to be able to log in allocations and de-allocations and added some basic logging functionality with a date and prefix tag.

    #badlang #pldev

  12. I was thinking on embedding libtcc to be able to use TCC to run .bad files as if they were scripts.

    But what if instead I just provide a simple bash script that serves the same function if installed alongside the badc and tcc executables? This keeps badc entirely dependency free other than libc, and that could also be removed. A fully static executable build it's already possible with musl, so it would be nice to be able to just provide a binary and the stdlib for releases.

    #badlang #pldev

  13. Back from my trip to BCN and back again to work on the compiler.

    Did some code cleanup and finally added type inference for struct, union and choice type literals.

    Naturally, type inference is not always possible in which case we can always use polytype annotations as before, but this is much more convenient for when it is.

    #badlang #pldev

  14. I added the following compiler directives:

    #flag to set a compiler flag, like a #define in c but without value

    #def set a compiler flag with a compile time string value.

    #get gets a compile time flag value

    This in combination with a —def parameter on the compiler enables me to finally have a compile time default path for the stdlib, so that I can do make install and the compiled binary will fetch the path of the system stdlib instead of the dev path.

    I may expand this in the future for other constants, but this is sufficient for now. I would like to keep comptime stuff at a minimum.

    #badlang #pldev

  15. Today I expanded on the direct to backend compiler directives:

    #emit puts the given string directly on the source code as a LinearOp
    #funattr adds function attributes to the current function
    #global puts the string into the top of the generated file
    #local puts the string into the top of the current function

    With these in place you can do things like adding linear assembly (useful to insert optimization fences or other shenanigans), hookup instrumentation, and to configure your functions as you would with a C compiler (add always_inline, force loop unrolls, put a function into a given section, etc.). I think these form a base that could work for most or all backends I can think of, so they are not limited to the current C one.

    #badlang #pldev

  16. Today I expanded on the direct to backend compiler directives:

    #emit puts the given string directly on the source code as a LinearOp
    #funattr adds function attributes to the current function
    #global puts the string into the top of the generated file
    #local puts the string into the top of the current function

    With these in place you can do things like adding linear assembly (useful to insert optimization fences or other shenanigans), hookup instrumentation, and to configure your functions as you would with a C compiler (add always_inline, force loop unrolls, put a function into a given section, etc.). I think these form a base that could work for most or all backends I can think of, so they are not limited to the current C one.

    #badlang #pldev

  17. Today I expanded on the direct to backend compiler directives:

    #emit puts the given string directly on the source code as a LinearOp
    #funattr adds function attributes to the current function
    #global puts the string into the top of the generated file
    #local puts the string into the top of the current function

    With these in place you can do things like adding linear assembly (useful to insert optimization fences or other shenanigans), hookup instrumentation, and to configure your functions as you would with a C compiler (add always_inline, force loop unrolls, put a function into a given section, etc.). I think these form a base that could work for most or all backends I can think of, so they are not limited to the current C one.

    #badlang #pldev

  18. Today I expanded on the direct to backend compiler directives:

    #emit puts the given string directly on the source code as a LinearOp
    #funattr adds function attributes to the current function
    #global puts the string into the top of the generated file
    #local puts the string into the top of the current function

    With these in place you can do things like adding linear assembly (useful to insert optimization fences or other shenanigans), hookup instrumentation, and to configure your functions as you would with a C compiler (add always_inline, force loop unrolls, put a function into a given section, etc.). I think these form a base that could work for most or all backends I can think of, so they are not limited to the current C one.

    #badlang #pldev

  19. Today I expanded on the direct to backend compiler directives:

    #emit puts the given string directly on the source code as a LinearOp
    #funattr adds function attributes to the current function
    #global puts the string into the top of the generated file
    #local puts the string into the top of the current function

    With these in place you can do things like adding linear assembly (useful to insert optimization fences or other shenanigans), hookup instrumentation, and to configure your functions as you would with a C compiler (add always_inline, force loop unrolls, put a function into a given section, etc.). I think these form a base that could work for most or all backends I can think of, so they are not limited to the current C one.

    #badlang #pldev

  20. Since yesterday I was looking at some tooling and it's integration with my language I started pondering if it would make sense to add some command line arguments to add instrumentation to functions, like so:

    badc --inst-all-fun AAA
    --inst-fun-with-prefix foo BBB
    --inst-fun-with-suffix foo CCC
    --inst-fun-matching foo DDD

    This could be used to add timers or profiler hooks to the beginning of a function, and since we have `defer`, also to the end if we wanted to.

    #pldev #badlang

  21. Now that I have a generic map implementation, I can finally use it to replace the previous Map::(Str, U32) with a Map::(Type, U32). This avoids the creation of unnecessary temporary strings that I was using for type uniqueness determination.

    As a result, the semantic analysis now only uses a whooping 0.7MBs of temporary memory instead of 180MB that it was using previously. It's also about 14% faster but I was mainly looking for the reduction in memory usage.

    #badlang #pldev

  22. Checking out this wonderful GDB frontend[1] by @nakst

    Because I can emit line directives in debug mode I'm able to step through my code, set breakpoints and look and registers.

    I wonder if there is something similar to #line but for registering locals or function names, otherwise my codegen locals look like _l0, _l1, _t0, etc. Still, pretty useful already!

    [1] github.com/nakst/gf

    #badlang #pldev

  23. Taking some time to fix some bugs and do a pass of consistency and documentation over the current stdlib. Also started the implementation of a generic Map::(K, V) data structure.

    In the current compiler I'm using specific implementations for IntMaps and StrMaps but they are just specialization with a lot of code shared. The new implementation also supports iterators that can be used on foreach loops.

    #badlang #pldev

  24. Yo dawg I heard you like assembly so I put an assembly in your assembly so that you can assembly while you assembly.

    AKA: Experimenting with building a fully freestanding binary from badlang for x86_64, emitting C code directly that emits ASM.

    #badlang #pldev

  25. Yesterday I did some vim magic to update all of my Raylib bindings to follow the same style convention as the rest of the codebase. May be a minor thing, but it's really nice not to have to depend on the style convention of the library provider IMO as consistency is very important to me.

    #badlang #pldev

  26. Migrated all of the IO writing to the new IO.Writer formatting. Also added a few more formatting options for std/fmt and an IO.FileWriter implementation of IO.Writer.

    Additionally, finally I addressed the issues with unused expressions being typechecked (for example, if we are not assigning the result of an if expression, there is no need for both branches to have to have the same type. This also applies for match expressions.

    #badlang #pldev

  27. Now that I have a usable std/fmt library I decided to move the backend output to use it, that way I can finally start implementing a direct to file output (-o file.c) instead of relying on stdout.

    As a nice side effect, the new implementation ends up being 30% faster, which is quite substantial!

    #badlang #pldev

  28. Adding float, hex and padded hex to std/fmt.

    Another cool thing here is that anyone could extend the formatter for their own applications by doing this anywhere in their scopes:

    namespace Fmt {
    methods Formatter { ... }
    }

    So custom structs formatting or serializers should be easy to build with this design.

    #badlang #pldev

  29. Here is a proof of concept for the stdlib formatting functionality. No varargs, no macros, no interfaces. Instead, a Formatter struct is used in a monadic way, being passed in the chain until a formatting delimiter is detected.

    Here I'm using {}, but I may swap it to a single character instead (% maybe?) and do all the formatting in methods instead? So for example for floating point you could have a methods like this:

    fun float(fmt: @Formatter, f: F64, precision: Int)

    Which will use N digits of precision for it. The same could be done for string padding and other such things.

    #badlang #pldev

  30. Experimenting with implementing my own buffered IO implementation on top of the write syscall. I'm going with Zig's current approach for IO where one would pass an IO Writer vtable around with some context information added.

    Starting at a bufsize of 128 my implementation is faster that calling printf("%s.*"...), becoming 7-8x faster with larger buffer sizes (4 to 8K).

    Pretty happy with this!

    #badlang #pldev

  31. I started working on some standard library stuff and got sidetrack since I had to fix some bugs in the behaviour of nested namespaces and methods on namespaced types.

    #badlang #pldev

  32. Last #DecemberAdventure day, but work won't stop after today, have a really long trip ahead still, and will celebrate new year's on the plane.

    In the meantime, I used the new `#emit` directives to move all the stdlib specific code from the backend into std and added the option to compile without main to create standalone lib code that could run on any target with a crt. I also added raw string literals that extend until (and including) the newline.

    I would like to fully get rid of the need for libc, but I'm not familiar enough with macos syscalls to start writing assembly for those, would probably do that on my linux machine after I'm back home.

    #pldev #badlang

  33. Some more #DecemberAdventure work from the bus:

    - Improved codegen to avoid generating code for unused functions.
    - Added the `#if` compiler directive for conditional compilation based on a given --flag.
    - Added the `#error` compiler directive to ensure we have a way to signal a compilation error in some path (for example, unimplemented library functions for a given OS and such).
    - Added the `#emit` compiler directive to be able to generate code directly on the backend verbatim. Now #badlang is a C macro assembler lol.

    Here is everything together.

    #pldev

  34. Finally adding struct literals. Initially I was going to use a prefix to denote compoun literals, like `#Vec(x = 1, y = 2)` but I found them aesthetically unappealing.

    So alas, we overload the parenthesis syntax a bit (though I was already doing this for sum type literals anyway).

    Also going with parens instead of curly braces. Technically parens mean grouping in the language, so it's somewhat consistent with other use cases.

    #PLDev #badlang

  35. Finally adding struct literals. Initially I was going to use a prefix to denote compoun literals, like `#Vec(x = 1, y = 2)` but I found them aesthetically unappealing.

    So alas, we overload the parenthesis syntax a bit (though I was already doing this for sum type literals anyway).

    Also going with parens instead of curly braces. Technically parens mean grouping in the language, so it's somewhat consistent with other use cases.

    #PLDev #badlang

  36. Finally adding struct literals. Initially I was going to use a prefix to denote compoun literals, like `#Vec(x = 1, y = 2)` but I found them aesthetically unappealing.

    So alas, we overload the parenthesis syntax a bit (though I was already doing this for sum type literals anyway).

    Also going with parens instead of curly braces. Technically parens mean grouping in the language, so it's somewhat consistent with other use cases.

    #PLDev #badlang

  37. Finally adding struct literals. Initially I was going to use a prefix to denote compoun literals, like `#Vec(x = 1, y = 2)` but I found them aesthetically unappealing.

    So alas, we overload the parenthesis syntax a bit (though I was already doing this for sum type literals anyway).

    Also going with parens instead of curly braces. Technically parens mean grouping in the language, so it's somewhat consistent with other use cases.

    #PLDev #badlang

  38. Finally adding struct literals. Initially I was going to use a prefix to denote compoun literals, like `#Vec(x = 1, y = 2)` but I found them aesthetically unappealing.

    So alas, we overload the parenthesis syntax a bit (though I was already doing this for sum type literals anyway).

    Also going with parens instead of curly braces. Technically parens mean grouping in the language, so it's somewhat consistent with other use cases.

    #PLDev #badlang