in Courses

Essentials of Interpretation

Available coupons:

How programming languages work under the hood? What’s the difference between compiler and interpreter? What is a virtual machine, and JIT-compiler? And what about the difference between functional and imperative programming?

There are so many questions when it comes to implementing a programming language!


The problem with “compiler classes” in school is they usually are presented as some “hardcore rocket science” which is only for advanced engineers.

Moreover, classic compiler books start from the least significant topic, such as Lexical analysis, going right away deep down to the theoretical aspects of formal grammars. And by the time of implementing a first Tokenizer module, students simply lose an interest to the topic, not having a chance to actually start implementing a programing language itself. And all this is spread to a whole semester of messing with tokenizers and BNF grammars, without understanding an actual semantics of programming languages.


I believe we should be able to build and understand a full programming language semantics, end-to-end, in 4-6 hours — with a content going straight to the point, showed in live coding sessions as pair-programming, and described in a comprehensible way.

In the Essentials of Interpretations class we focus specifically on runtime semantics, and build an interpreter for a programming language very similar to JavaScript or Python.

Implementing a programing language would also make your practical usage level of other programming languages more professional.

You can watch preview lectures, and also enroll to the full course, covering implementation of an interpreter from scratch, in animated and live-annotated format. See details below what is in the course.

– or –

This class is for any curious engineer, who would like to gain skills of building complex systems (and building a programming language is really a pretty advanced engineering task!), and obtain a transferable knowledge for building such systems.

If you are interested specifically in compilers, interpreters, and source code transformation tools, then this class is also for you.

The only pre-requisite for this class is basic data structures and algorithms: trees, lists, traversal.

Since we build a language very similar in semantics to JavaScript or Python (the two most popular programming languages today) we use specifically JavaScript — its elegant multi-paradigm structure which combines functional programming, class-based, and prototype-based OOP fits ideal for that.

Many engineers are familiar with JavaScript so it should be easier to start coding right away. However in implementation we don’t rely on too specific JS constructs, and the code from the course should be easily portable to TypeScript, Python, Java, C++, Rust, and any other language of your taste.

The main features of these lectures are:

  • Concise and straight to the point. Each lecture is self-sufficient, concise, and describes information directly related to the topic, not distracting on unrelated materials or talks.
  • Animated presentation combined with live-editing notes. This makes understanding of the topics easier, and shows how (and when at time) the object structures are connected. Static slides simply don’t work for a complex content.
  • Live coding session end-to-end with assignments. The full source code, starting from scratch, and up to the very end is presented in the class

The course is divided into four parts, in total of 18 lectures, and many sub-topics in each lecture. Below is the table of contents and curriculum.

In this part we describe different compilation and interpretation pipelines, see the difference between JIT-compilers and AOT-compilers, talk about what is a Virtual machine and Bytecode-interpreter, and how it differs from an AST-interpreter, show examples of native code, and LLVM IR, and other topics.

  • Lecture 1: Parsers, ASTs, Interpreters and Compilers
    • Introduction and course overview
    • Parsing pipeline
    • Tokenizer, tokens
    • Abstract Syntax Trees (AST)
    • Static/Compile time vs. Runtime
    • Interpreters vs. Compilers
    • AST-interpreters (recursive)
    • Bytecode-interpreters
    • Ahead-of-time (AOT) compilers
    • Just-in-time (JIT) compilers
    • Transpilers

  • Lecture 2: AST Interpreters and Virtual Machines
    • AST interpreters
    • AST explorer
    • JavaScript AST example
    • Bytecode interpreters
    • Stack machine vs. Register machine
    • Stack VM bytecode evaluation example
    • Compiler explorer
    • Java bytecode example
    • Python bytecode example
    • Register VM bytecode evaluation example

  • Lecture 3: Compilers: AOT, JIT, Transpiler
    • Ahead-of-time (AOT) compiler
    • Just-in-time (JIT) compiler
    • LLVM
    • Intermediate representation (IR)
    • Bytecode
    • Clang
    • x64 Assembly
    • AST-transformer (Transpiler)

In this part we start building our programming language, and consider basic expressions, such as numbers, strings, talk about variables, scopes, and lexical environments, control structures, and touching parser generator.

  • Lecture 4: Eva programming language
    • AST formats
    • S-expression
    • Eva programming language
    • Eval — the core of an interpreter
    • Statement vs. Expression
    • Closures
    • Lambda functions
    • IILE: Immediately-invoked lambda expressions

  • Lecture 5: Self-evaluating expressions
    • Eval — the core of an interpreter
    • Self-evaluating expressions
    • Numbers and Strings
    • TDD (Test-driven development)
    • Addition operation

  • Lecture 6: Variables and Environments
    • Recursive nature of the interpreter
    • Environment: repository of variables
    • Environment Record
    • Define, Assign, Lookup
    • The Global Environment

  • Lecture 7: Blocks: expression groups and Nested Scopes
    • Blocks: groups of expressions
    • Block scope
    • Identifier resolution
    • Scope chain traversal
    • Variable assignment

  • Lecture 8: Control flow: If and While expressions
    • Program control-flow
    • Branches: if-expression
    • Cycles: while-loops

  • Lecture 9: Back to parsers: S-expression to AST
    • S-expressions
    • BNF (Backus-Naur form) grammars
    • Syntax tool: language-agnostic parser generator
    • Atoms and Lists
    • LALR(1) parser creation

In this part we start talking and implementing function abstraction, and function calls. We describe concept of closures, lambda function, and IILEs (Immediately-invoked lambda expressions). In addition, we touch topics of Call-stack, recursion, and syntactic sugar.

  • Lecture 10: Built-in and Native functions
    • Built-in functions
    • Native functions
    • Function calls
    • Global environment

  • Lecture 11: User-defined functions, Activation Records and Closures
    • User-defined functions
    • Closures: capturing environment
    • Function calls
    • Activation Environments and Activation Records
    • Static scope vs. Dynamic scope
    • Free variables

  • Lecture 12: Lambda functions and Functional programming
    • Lambda functions
    • Anonymous function expressions
    • Callbacks
    • IILE: Immediately-involved lambda expressions
    • Function declaration
    • Syntactic sugar

  • Lecture 13: Call-stack and Recursive calls
    • Call-stack
    • Recursive calls
    • Heap-environments
    • Execution context
    • Closures
    • Tail calls

  • Lecture 14: Syntactic sugar: Switch, For, Inc, Dec operators
    • Transpilers
    • Nicer syntax, same semantics
    • Switch-expression
    • For-loops
    • JIT-translation

The final part of the course is devoted to the object-oriented support in our language. We describe the class-based, and prototype-based approaches, implement concept of classes, instance and modules.

  • Lecture 15: Object-oriented Eva: Classes
    • Object-oriented programming
    • Class-based semantics
    • Prototype-based semantics
    • Named environments
    • Instances
    • New expression
    • Property access

  • Lecture 16: Class inheritance and Super calls
    • Class inheritance
    • Child and Parent classes
    • Super calls

  • Lecture 17: Code isolation: Modules and Imports
    • Module expressions
    • Named environments
    • First-class module objects
    • Import and export expressions
    • Property access

  • Lecture 18: Final executable and specification
    • Eva interpreter
    • CLI support
    • Evaluating expressions and files
    • Further data structures
    • Objects, prototypes, lists
    • Eva specification
    • Instructions format, examples and spec
    • Building a Virtual Machine

I hope you’ll enjoy the class, and will be glad to discuss any questions and suggestion in comments.

Write a Comment

Comment

  1. was following this class on your youtube channel and have been waiting for full contents. Thank you, sir, and congrats!

  2. @Udeepta Gupta, thanks, glad it’s useful, and glad to see more people interested in deeper engineering topics.

  3. awesome! when the class is coming on Udemy? seems registrations on Teachable are limited?

  4. @meyhong.tai, thanks, yes, Udemy launch should be in a week or so, and I have created some coupons for Teachable version, so there should be some more registrations now.

  5. thank you Dmitry, just enrolled!

    kind request: could you record lessons on threads and operating systems, thanks!

  6. I took you garbage collectors class in the past, and this was great! going to enroll to compilers, thank your for hard work, sir

  7. I’m half way through, awesome class! one constructive feedback: could you please reduce speed of the code session, so it’s easier to follow? other than that, fantastic content!