Buffing A 50 Year Old Programming Language

Alex - Jun 6 - - Dev Community

Hello, everyone! Today, I'm excited to take you on a journey through the fascinating world of programming languages and compilers. We'll be exploring a new language I'm developing called "Mantle" (or simply "M"). But before we get into the nitty-gritty, let's discuss the architecture of Mantle and what I aim to achieve with it.

The Inspiration Behind Mantle

I've been immersed in programming with C and C++ for a considerable time, primarily working on 3D computer graphics using Vulkan. My initial exploration into programming began with C++, which I grew to love for its high-level constructs and powerful memory management capabilities. However, I often found C++ to be overly complex. I gradually developed a preference for C. C's simplicity, with its minimal abstraction over assembly, provided a clearer understanding of how the hardware operates.

Yet, I frequently found myself torn between C and C++ when starting new projects. Each language has its strengths and weaknesses, and I wanted to create one that blends the best aspects of both. Thus, Mantle was born.

The Design Philosophy of Mantle

Today I will just briefly show you an overview of what I think Mantle can look like.

Organizing Code: Namespaces

One of the challenges in C is the lack of a robust mechanism for code organization, leading to messy codebases. Mantle addresses this by incorporating namespaces from C++, allowing for better code grouping and organization.

Namespaces

Defining Interfaces: Protocols

Mantle introduces the concept of “protocols". Protocols define requirements, such as functions and variables, that must be implemented by adopting types. This brings us to the “prototype” keyword, which acts as a placeholder for types specified when the protocol is adopted. This design encourages composition over inheritance, promoting flexible and modular code.

Protocols

Creating Classes: Blueprints

In Mantle, “blueprints” are akin to classes in other languages. Blueprints support public and private members, constructors, and destructors for managing resources. Unlike C++, Mantle distinguishes between structs and blueprints. Structs are used for grouping related variables, while blueprints facilitate object-oriented programming.

Blueprints

Extending Functionality: Extensions

To extend a blueprint's functionality for specific parts of the code, Mantle uses the “extension” keyword. This allows functions to be associated with a blueprint only within a particular file, providing modular and context-specific extensions.

Extensions

Extensions

Eliminating Redundancy: Generics

Generics are a powerful feature in Mantle, enabling the definition of functions, blueprints, structs, and variables with types specified later. This reduces code repetition and enhances flexibility.

Generics

Powerful Preprocessing: Macros

In Mantle, macros are defined with the “macro” keyword, leveraging generics for powerful code inclusion before compilation. This concept builds on the preprocessor directives of C and C++.

Macros

Core Concepts: Pointers and Optionals

Mantle incorporates pointers and optionals as core language features. If you have ever programmed in Swift or have used the std::optional<T> in C++ you might be quite familiar with this. Optionals represent values that may or may not be present, providing a type-safe way to handle absent values. Pointers, on the other hand, store memory addresses, enabling direct memory manipulation.

Building Mantle: The Lexical Analyzer

With an understanding of Mantle's design, let's dive into building the language, starting with Lexical Analysis, or lexing. Lexing transforms raw source code into tokens, which are the fundamental syntax elements.

Defining Token Types

We'll begin by defining the types of tokens Mantle will recognize:

  • Keywords: Data types, control flow constructs, data structures, and reserved words.
  • Operators: Arithmetic, relational, pointer, bitwise, and assignment operators.
  • Punctuators: Parentheses, curly brackets, square brackets, commas, etc.
  • Identifiers: Names given to variables, functions, and types.
  • End of File: Marks the end of the source file.

These tokens will evolve as the language matures and its functionality is refined.

The Lexing Process

Next, we'll write a lexer that processes a file, identifies tokens, and stores information for error handling, such as the token's position in the source file. Once identified, tokens are categorized and queued for further processing.

Lexing

Testing the Lexer

To test our lexer, we'll hardcode a function that processes tokens and generates assembly code. For example, writing a "return" statement followed by a value, passing this file through our lexer, and generating assembly code will validate our lexer's functionality.

Testing

Here are some more extreme tests.

Testing

Testing

Conclusion

We've successfully laid the groundwork for Mantle and developed a basic lexer. There's much more to explore and build, but I hope you've enjoyed this initial exploration into the process. If you found this interesting, feel free to connect with me and to share any suggestions.

You can find the project on my github. I also made a discord server.

If you have some feedback/suggestions let me know in the comments! Thanks for joining me on this journey, and I'll see you in the next time!

.