Understand the fundamentals of programming languages and dive deep into how they operate beneath the surface. Explore the distinctions between compilers and interpreters, learn about virtual machines and JIT-compilers, and comprehend the differences between functional and imperative programming. Many questions surface when implementing a programming language, and traditional "compiler classes" often present them as complex, advanced topics — something only for expert engineers.
Course Description
Traditional compiler textbooks often start with less engaging topics like Lexical Analysis and delve into theoretical aspects of formal grammars. By the time students implement their first Tokenizer module, they may lose interest without having the chance to create a full programming language. This course takes a different approach, focusing on building a comprehensive understanding of programming language semantics in just 4-6 hours using a practical, live coding session format.
In the Essentials of Interpretations class, we concentrate specifically on runtime semantics and create an interpreter for a language similar to JavaScript or Python. By implementing a programming language, you'll enhance your understanding and application of other programming languages.
Who is this class for?
This class suits curious engineers eager to learn about building complex systems, such as programming languages. If you're interested in compilers, interpreters, and source code transformation tools, this course is for you. The only prerequisite is a basic understanding of data structures and algorithms — trees, lists, and traversal.
Tools and Implementation
We implement a language with semantics akin to JavaScript or Python, using JavaScript for its versatile, multi-paradigm structure, suitable for this endeavor. While JavaScript is prevalent and easy to pick up, the code from this course is transferable to TypeScript, Python, Java, C++, Rust, and many more languages.
Course Highlights
- Concise and to the point lectures. Self-contained and focused on relevant topics without digressing into unrelated discussions.
- Animated presentations and live-editing notes. Enhance comprehension and demonstrate the interconnectedness of object structures, more effectively than static slides.
- Comprehensive live coding sessions. From the basics to the final implementation, experience coding through assignments and complete resources provided in the class.
Course Structure and Content
The course consists of four parts, spanning 18 lectures with various sub-topics. Refer to the curriculum for detailed descriptions of each lecture.
Part 1: Compilers Crash Course
This section explores various compilation and interpretation pipelines, comparing JIT-compilers with AOT-compilers, and discussing Virtual machines, Bytecode-interpreters, AST-interpreters, and examples of native code and LLVM IR.
Part 2: Interpreters - Basic Expressions and Variables
Begin building the programming language by handling basic expressions like numbers and strings, understanding variables, scopes, lexical environments, control structures, and parser generators.
Part 3: Functions and Functional Programming
Explore and implement function abstractions and calls, understanding closures, lambda functions, and IILEs. This section also covers the Call-stack, recursion, and syntactic sugar.
Part 4: Object-Oriented Programming
Focus on incorporating object-oriented support in our language, discussing class-based and prototype-based approaches, and implementing concepts like classes, instances, and modules.
Course Requirements
- Basic understanding of data structures and algorithms
- Familiarity with graphs, trees, and traversal
Who Should Enroll?
- Engineers curious about the inner workings of programming languages
What You'll Learn
- Build a programming language from scratch
- Understand Interpreters and Compilers
- Differentiate AOT, JIT-compilers and Transpilers
- Work with AST-interpreters and Virtual Machines
- Explore Bytecode, LLVM, and Stack-machines
- Master First-class functions, Lambdas, and Closures
- Understand the Call-stack and Activation Records
- Implement OOP: Classes, Instances, and Prototypes
- Create Modules and Abstractions