Evalyte

Modules, namespaces and symbol table - The Cely Programming Language

Namespaces & Symbol table

I implemented a namespace feature to support other features like modules and classes, it works by putting exported symbols at the top level of a symbol table making them available everywhere in the project.

The symbol table contains 2 categories of symbols:

  • namespaces: it’s basically a map (namespace) of maps (symbols).
  • local scopes: it’s an array of maps (symbols) that push a new scope each time we enter a block (a.k.a scope) and pop it when it ends.

When using an identifier like add we first look backward into the local scopes and if nothing is found we look into the special __global__ namespace, however if the identifier was math.add we would have looked directly into the math namespace.

Modules

NOTE

My “module” feature is really basic and not as advanced as with other languages.

A module is kind of namespace and can be declared at the file unit level:

module math;

func add(a: i32, b: i32): i32 {
	return a + b;
}

it affects the whole file and must be the first statement, at the moment all top-level symbols are exported by default, there is no “export” keyword for now.

A module can be used everywhere in the project without needing to import it explicitly, it may be a strange or bad choice, but it works for what I’m doing currently and I made room to implement explicit imports/exports if needed.

To use something from another module, I just used the dot character:

math.add(4, 8);

Multiple files support

Now that we have modules, we can split the code between multiple files and make libraries/modules. For now it’s pretty simple, we just need to specify the project root directory and all files ending with the .ce extension will be included, it also includes files in subdirectory recursively.

Because all the order of file inclusion is not guaranteed I needed a way to find an “entry point”, I decided to use the traditional main function. The minimum code for a program is now:

func main(): i32 {
	return 0;
}