I Built My Own Programming Language From Scratch - Meet NexPro π
What happens when you stop using programming languages and decide to build one? That was the question that led me to start NexPro - an experimental programming language that I'm building from scratch to understand how programming languages actually work internally. π GitHub: https://github.com/probal2005/NexPro NexPro is still in its early stages, but it already has the foundations of a real language implementation: lexical analysis, parsing, an AST, interpretation, runtime components, a CLI, and tests. This article explains why I started NexPro, how the architecture works, what the syntax looks like, and where I want to take the project next. π§ Why Build Another Programming Language? There are already hundreds of programming languages. So why build another one? For me, the goal wasn't to replace Python, JavaScript, Rust, or any existing language. The goal was to understand what actually happens between this: say "Hello NexPro!" and the computer executing it. When we write code, we usually think: Source Code β Output But internally, there is a lot more happening. A simplified language implementation looks more like: Source Code β βΌ Lexer β βΌ Tokens β βΌ Parser β βΌ AST β βΌ Interpreter β βΌ Runtime β βΌ Output I wanted to build every major part myself. That's how NexPro started. π What Is NexPro? NexPro is an experimental programming language designed around simple and readable syntax. The project currently lives on GitHub: π https://github.com/probal2005/NexPro The language uses the .pa extension for source files. For example: name = "Probal" city = "Kolkata" say name say city The idea is intentionally simple: code β easy to read β easy to understand β easy to execute NexPro isn't trying to compete with established languages yet. Right now, it is a learning project, language-design experiment, and open-source project that I want to grow over time. ποΈ NexPro Architecture One of the most interesting parts of this project is understanding how the individual components communicate. The current architecture can be represented like this: βββββββββββββββββββββββ β NexPro Source β β (.pa) β ββββββββββββ¬βββββββββββ β βΌ βββββββββββββββββββββββ β Lexer β β Source β Tokens β ββββββββββββ¬βββββββββββ β βΌ βββββββββββββββββββββββ β Parser β β Tokens β Structure β ββββββββββββ¬βββββββββββ β βΌ βββββββββββββββββββββββ β AST β β Program Structure β ββββββββββββ¬βββββββββββ β βΌ βββββββββββββββββββββββ β Interpreter β β Execute the AST β ββββββββββββ¬βββββββββββ β βΌ βββββββββββββββββββββββ β Runtime β β Values & Execution β ββββββββββββ¬βββββββββββ β βΌ βββββββββββββββββββββββ β Output β βββββββββββββββββββββββ Each component has a specific responsibility. π 1. The Lexer The first step is lexical analysis. The lexer reads the raw source code and converts it into tokens. For example: say "Hello NexPro!" can conceptually become: SAY STRING("Hello NexPro!") EOF For a variable assignment: name = "Probal" the lexer needs to recognize things such as: IDENTIFIER(name) ASSIGN(=) STRING("Probal") This is the first major transformation: Characters β Tokens The lexer doesn't need to understand the complete meaning of the program. Its job is to identify the building blocks. π³ 2. The Parser Once the lexer produces tokens, the parser takes over. The parser answers a different question: "How are these tokens structured?" For example: name = "Probal" is not just three independent pieces. It represents an assignment. Conceptually, the parser can construct something similar to: Assignment βββ Variable: name βββ Value βββ String: "Probal" This structured representation becomes part of the Abstract Syntax Tree, or AST. π² 3. The AST The AST is one of the most important concepts in a programming language. Instead of executing raw text directly, NexPro represents the program as structured nodes. For example: say 10 + 20 could conceptually become: Say β Binary / \ 10 20 The advantage is that the interpreter doesn't need to repeatedly analyze the original source text. It works with a structured representation of the program. βοΈ 4. The Interpreter After the AST has been created, the interpreter walks through it and executes the nodes. For example: name = "Probal" say name The interpreter can conceptually perform: 1. Create variable "name" 2. Store "Probal" 3. Find variable "name" 4. Retrieve its value 5. Send the value to output So the overall process becomes: Source β Lexer β Tokens β Parser β AST β Interpreter β Runtime β Output This pipeline is the heart of NexPro. π§ͺ A Small NexPro Program Here's a simple example: name = "Probal" city = "Kolkata" say name say city The expected output is: Probal Kolkata The important thing isn't the complexity of this program. The important thing is everything happening underneath it. β Expressions NexPro is also moving toward expression evaluation. For example: a = 10 b = 20 say a + b Conceptually, the parser can represent the expression as: + / \ a b The interpreter then resolves: a β 10 b β 20 10 + 20 β 30 and produces: 30 This is where a programming language starts becoming more interesting. π» Running NexPro The project is designed around a CLI. A NexPro program can be executed with: nexpro run examples/hello.pa For example: say "Hello NexPro!" produces: Hello NexPro! The CLI acts as the interface between the developer and the language implementation. Instead of manually calling the lexer, parser, and interpreter, the developer simply runs a NexPro program. π Project Structure The repository is organized around the language implementation itself. The current project structure includes: NexPro/ β βββ nexpro/ β βββ init.py β βββ cli.py β βββ lexer.py β βββ parser.py β βββ interpreter.py β βββ runtime.py β βββ tokens.py β βββ ast.py β βββ errors.py β βββ version.py β βββ examples/ β βββ hello.pa β βββ variables.pa β βββ tests/ β βββ README.md βββ LICENSE βββ pyproject.toml The GitHub repository currently exposes the main examples , nexpro , and tests directories alongside the project configuration and documentation. The implementation itself is written in Python. That choice was deliberate. Python lets me focus on language implementation concepts without spending most of my time dealing with low-level memory management. π§© Why Python? A natural question is: "If you're creating a programming language, why implement it in Python?" Because the current goal is learning and experimentation. Python gives me useful building blocks: - Easy string manipulation - Dictionaries for environments - Classes for AST nodes - Exceptions for error handling - Simple testing - Fast iteration For an early interpreter, this makes development much faster. Later, I may explore implementing parts of NexPro in another language for performance. π‘οΈ Error Handling A programming language isn't complete if it only handles valid programs. It also needs to explain invalid programs. For example: name = shouldn't simply crash with an obscure Python traceback. Eventually, NexPro should provide language-level errors such as: NexPro Syntax Error Line 1: name = Expected a value after '='. Good error messages are a major part of good developer experience. Improving NexPro's error system is therefore an important part of the roadmap. π§ͺ Testing the Language Programming languages are particularly sensitive to regressions. A small lexer change can break parsing. A parser change can break the interpreter. An AST change can affect multiple features. That's why NexPro includes a test suite. The goal is to test individual components such as: Source Code β βΌ Lexer β βββ Token tests β βΌ Parser β βββ AST tests β βΌ Interpreter β βββ Execution tests As the language grows, I want the test suite to grow with it. πΊοΈ NexPro Roadmap NexPro is still early. There is a lot left to build. My current roadmap looks roughly like this: NexPro β ββββββββββββββββΌβββββββββββββββ β β β βΌ βΌ βΌ Language Tooling Runtime β β β ββ if/else ββ REPL ββ Types ββ loops ββ Formatter ββ Collections ββ functions ββ VS Code ββ Modules ββ arrays ββ Debugger ββ Standard Library ββ objects Near-term goals if / else - Loops - Functions - More operators - Arrays / collections - Better error messages - More comprehensive tests - Improved runtime Medium-term goals - REPL - Modules - Standard library - File operations - Better CLI tooling - Formatter - Documentation - VS Code syntax highlighting Long-term goals I'd like to explore: - A more powerful type system - Package management - Faster execution - Bytecode or compilation - Debugging tools - Language server support - Cross-platform distribution - A proper developer ecosystem Some of these are deliberately ambitious. The roadmap will evolve as the language evolves. π¬ What I'm Learning From Building NexPro Building a programming language has changed how I think about programming. Before starting NexPro, concepts like: Lexer Parser AST Interpreter Runtime could feel abstract. Now they feel much more concrete. When I write: say "Hello" I can think about the entire journey: "say" β Token β Parser β SayNode β Interpreter β Runtime β Hello That mental model is probably the most valuable thing I've gained from this project. π§ NexPro Is Not Finished I want to be very clear about this. NexPro is not a production-ready programming language. It's an evolving project. There will be: - Bugs - Design changes - Breaking changes - Missing features - Experiments that don't work - Architectural decisions that will probably need to be revisited And that's okay. That's part of building a language from scratch. π€ I Want Developer Feedback This project is now at the point where feedback from other developers could be extremely valuable. If you are interested in: - Programming languages - Compilers - Interpreters - Lexers - Parsers - ASTs - Language design - Python - Developer tooling - Open source I'd love to hear your thoughts. Especially: What would you change about the language design? Which feature should I build next? Does the architecture make sense? What am I overlooking? Wou
Comments
No comments yet. Start the discussion.