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.
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.
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.
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.
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.
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++.
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.
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.
Here are some more extreme tests.
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!
Top comments (5)
This looks interesting, and I applaud your efforts, creating a new programming language is not easy. I would encourage you to look even more outside the box, and dream of new paradigms. Ask questions: what are the most overused or abused features today, and how can I improve the situation? What other ways to program can we come up with, something completely "out there"?
Thank you, it means a lot! You also make a very good point. My current goal is to have the foundation of the language laid out before I get into parsing grammar. I will take these questions into account.
Good luck!
These are fascinating repos, and I'll consider them when I get into parsing. Thank you! I agree, I'm also not a fan of the C++ approach.
Thank you once again, much appreciated!
This is nice! Another c-based minimal language that I have found interesting is Zig.