Sea (a compiled language)
fuzzyastrocat (672)

Hello everyone! This is my first post, so if it's boring I apologize :D

Just wanted to share a little compiled language I made called Sea. It's called Sea because, well, Sea shares many things in common with C. I chose C to mimic because this was my first compiled language — given that C is so low-level, I figured I wouldn't have to do too much work translating to x86.

A quick overview of the language

In case any of you want to try it out, here's a quick overview of the syntax/semantics.

To start, we'll take the simple "hello, world" program:

    import "stdlib.sea";
    int function main {
            println("Hello, world!");

Here we immediately see a few differences between C and Sea:

  • Import is not a preprocessor routine, it's a keyword
  • Functions are defined as <type> function <name>
  • Functions automatically return their last expression — to suppress this, the last expression can be void;
  • Arguments in functions are declared differently — instead of putting arguments between parentheses, they are written as null declarations on the following line:
    int function my_function
            int my_arg_1;
            int my_arg_2;
            // some code

Control flow (if, else, while) is implemented as a "postfix operator":

    1 == 2
            :then {
                    println("Whoa, math broke"); // And no, this won't get printed :D

A for-loop can be emulated with a block scope and a while:

    {int i = 0; i < 5
            :while {
                    printf("%d", i);

These control flow constructs can be extended — an excerpt taken from the stdlib:

    int::isZero {
            :else {

$int represents the int in question, and $() represents execution of the block given to the control statement. We could "call" this like so:

         :isZero {
                 println("Hey math works again!");

Sea has support for ints, chars, pointers, strings (char*), and moderate support for floats. If you want to see more about the language, peruse stdlib.sea and the tests (and oldtests, though some of those are outdated) folders in the repl.

EDIT: stdlib.sea uses what might be a confusing doc notation, so let me explain that here.


Sea comments behave just like C comments:

    // This
    /* will
    */ // Evaluated

However, there is a doc notation (used by SeaLib to generate simple HTML docs for a file). It is the following:

    The header must be the first line of the file (outside of line or block comments).  It gives  a description of the file to follow. // This line is the file info

    [[your_function]] // Descriptor doc — gives info about a function
    A cool function I just wrote for demo purposes

    void function your_function {
            println("Hello, world!");

    // Add more functions with their descriptor docs

SeaLib translates that to the following:

And yes, that file would actually run (aside from saying "entry point main is not defined"). Doc headers are ignored (along with the line after) just like normal comments.


"That's neat — but why are you posting it here right now?"

Unfortunately, I'm going to abandon Sea (in favor of a newer language, Curta). Why? Two things:

  • As the language became more complex, I noticed a few things I had done not-quite-nicely in the compiler were becoming difficult to manage. I was faced with either using bad tools or buying (re-coding) new tools.
  • I was actually wrong about translating from a C-like language to x86 being easy. While the actual conversions themselves are not difficult, finding the proper x86 commands can be very difficult! For instance, there is no power function for the SSE floating point system — and all the tools I needed to make a power function were either nonexistent or difficult to implement.

So Sea will probably remain in its current state [for the rest of time].

In the aforementioned newer language (Curta), I am learning from my mistakes — it will compile to C++, with the added benefit that it will work on some embedded systems (most notably the Arduino). Stay tuned!

EDIT: Curta is now here:

You are viewing a single comment. View All
fuzzyastrocat (672)

@DynamicSquid Here's a little bit of advanced Haskell:

Say you wanted to be able to turn anything into an uppercase name. You could write a name function like so:

name :: String -> String
name x = map toUpper x

But wait a minute — notice how x is at the end of both name x and map toUpper x? That means we can get rid of it — ie,

name :: String -> String
name = map toUpper

main :: IO()
main = putStrLn $ name "squid" -- This works, it prints correctly

But why? The best way to understand this is currying:

  • map, when called with 0 arguments (written out) creates a function that takes one argument
    • ...that creates a function that takes one argument
      • ...which takes the first argument and maps it over the second.

So by saying map toUpper, we're partially applying map. It doesn't have the last argument yet (the thing to map over), so it doesn't do anything. It's just a function that, when you give it the final argument, will then apply the map. It's a bit confusing at first, but I'd suggest researching it since this is something used extensively in Haskell. It's also the basis of Point-free Programming. To learn more about currying, check out the wikipedia article.