Compiler progress update (17-Jan-2020)

It will be nearly two months since the 0.5.1 release and there is a few of new things done. So let's take a look at new features in 0.5.2 upcoming compiler version.

New features

Build system

The biggest new feature almost done is integrated compiler build system. The basic idea is get rid of CMake or similar build tools required by larger C/C++ projects. One of the goals is also keep programmer focus on one language syntax, so I decided to basically use BL program to setup and compile BL programs.

Every BL project is consist of one or more Assembly modules containing source code units. Compiler will take all of them and produce desired output or just execute them in compile-time. There are lot of possible options telling the compiler what to do with passed input. We can specify those options directly from command line but it's not an optimal solution for larger and more complicated projects. The build system provides simple API to manipulate assemblies, units and it's compile options. The build entry point or build program is a special kind of Assembly only executed in compile-time when compilation starts. In the build entry we can add and setup new assemblies and push them into compilation queue.

Minimal build entry code in build.bl file can look like this:

build :: fn () #build_entry {
    // Create new executable named 'MyProgram'.
    exe :: add_executable("MyProgram");
    
    // Add 'main.bl' source file into the 'MyProgram' assembly.
    add_unit(exe, "src/main.bl");
}

To invoke build entry we just type blc -b or blc -build in command line. The compiler will automatically take build.bl file and produce new executable MyProgram (containing main.bl unit) after successful execution of the build entry procedure.

You can find more information about build system API here.

New API documentation

One of the most important things is documentation describing how to use language standard API. Previous version made with emacs's org-mode was not optimal and did not support context search, so I decided to use MkDocs documentation generator to produce better looking and more user friendly web page.

Documentation content can be generated from source code comments now, by one shell script, using simple BL parser I made. I hope this will lead to more up-to-date language web presentation.

Future development ideas

Static if

This is basically equivalent to the #ifdef or #if C preprocessor. Sometimes we want include or exclude parts of code based on compilation target or options. This is definitely needed feature but not so easy to implement.

Syntax should look like this:

    IS_WINDOWS :: true;
#if IS_WINDOWS {
    // do something only on windows
} else {
    // do something if we are not on windows
} 

Namespaces

Biscuit Language does support only #private file scopes for now, to also reduce possibility of name collision, but maybe we can do better with namespaces. One idea is have namespace defined for whole file.

/***************** foo.bl *****************/
#namespace Foo // file scoped namespace
bar1 :: fn () {}
bar2 :: fn () {}
/******************************************/

/**************** main.bl *****************/
Foo.bar1();
Foo.bar2();
/******************************************/

We can probably support also nesting of namespaces (something like #namespace Foo.Bar) but I'm not sure about that. Biscuit will probably never support C++ like syntax for namespaces with explicitly defined blocks namespace Foo { ... }.

Pros

  • Less typing.
  • Less name collisions.
  • Better code organization into "modules".

Cons

  • ???

Questions

  • Should we support nested namespaces?
  • Is file scoped namespace declaration a good idea?

Using operator

Related to namespaces but not only to them is using operator. The idea behind using is reduce necessary typing by importing nested scopes into the current scope. By using Foo, where Foo is enum, we import every variant of the Foo into current scope, so there is no need to use Foo. as prefix to access it's inner variants.

Concept of using operator I consider to implement should support namespaces, enums and also structs.

Example of using with namespace:

/***************** foo.bl *****************/
#namespace Foo
bar1 :: fn () {}
bar2 :: fn () {}
/******************************************/

/**************** main.bl *****************/
main :: fn () s32 {
    // This will make all members of namespace 'Foo'
    // visible from current scope.
    using Foo;
    bar1();
    bar2();

    return 0;
}
/******************************************/

Example of using with enum:

Foo :: enum {
   A;
   B;
}

main :: fn () s32 {
    using Foo;
    A;
    B;

    return 0;
}

Example of using with struct types:

Foo :: struct {
    i: s32;
    j: s32;
}

main :: fn () s32 {
    foo: Foo;
    
    // This will make all members of 'foo'
    // visible from current scope.
    using foo;
    i = 10;
    j = 20;
    return 0;
}

Pros

  • Less typing.

Cons

  • Not so explicit.
  • Can introduce symbol name collisions and hiding.

Questions

  • Support only local-scoped using or enable using even in global scope?
  • What to do in case of name collision?
  • Should be scope imported by using preferred over local scope?

Conclusion

Feel free to leave any ideas in comment section.

Author: Martin Dorazil

Created: 2020-01-17 Fri 14:49

Validate