From 14a463b64d7cbadd476cf9ada06307a0951e1648 Mon Sep 17 00:00:00 2001 From: imteekay Date: Wed, 19 Jul 2023 21:31:59 -0300 Subject: [PATCH 1/7] * --- .../en/index.mdx | 193 ++++++++++++++++++ .../en/metadata.json | 23 +++ 2 files changed, 216 insertions(+) create mode 100644 content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx create mode 100644 content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json diff --git a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx new file mode 100644 index 00000000..65eee1ac --- /dev/null +++ b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx @@ -0,0 +1,193 @@ + + +This is the 4th post of the **[TypeScript Compiler Series](https://www.notion.so/series/the-typescript-compiler)**. Before, we had an [overview of the TypeScript architecture](https://www.notion.so/a-high-level-architecture-of-the-typescript-compiler), [how it uses the closure technique](https://www.notion.so/javascript-scope-closures-and-the-typescript-compiler), a [deep dive into the compiler and its features](https://www.notion.so/a-deep-dive-into-the-typescript-compiler-miniature), and [how to implement string literals in the compiler](https://iamtk.co/implementing-string-literals-for-the-typescript-compiler). + +Now we are going to learn how to implement empty statements and use the semicolon as the statement ender for the compiler. + +This post will be pretty similar to the string literals one. We'll see some examples and go through all the steps of the compiler to implement these features. + +--- + +The example for empty statements is pretty simple, take a look at it: + +```tsx +var x: number = 1; +var y: number = 2; +``` + +The semicolon in this case is an empty statement. At that time, semicolons were treated as separators, so every time the parser reached a semicolon, it separated the piece as a statement and continued parsing the following statements. These are the separated pieces: + +- `var x: number = 1;` +- `;` +- `var y: number = 2;` + +What we need to do now is get the second piece and transform it into an `EmptyStatement`. + +According to the [ECMAScript spec](https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-empty-statement), the `;` token is the syntax for empty statements. + +Let's see what it would look like in the AST structure: + +```tsx +[ + { + kind: 'Var', + name: { + kind: 'Identifier', + text: 'x', + }, + typename: { + kind: 'Identifier', + text: 'number', + }, + init: { + kind: 'Literal', + value: 1, + }, + }, + { + kind: 'EmptyStatement', + }, + { + kind: 'Var', + name: { + kind: 'Identifier', + text: 'y', + }, + typename: { + kind: 'Identifier', + text: 'number', + }, + init: { + kind: 'Literal', + value: 2, + }, + }, +]; +``` + +We have three nodes or three statements in this case. The first one is the variable declaration for `x`, the second is the `EmptyStatement`, and the last one is the variable declaration for `y`. + +Looking at this, we pretty much get a sense of what we should do to implement this feature in the compiler. But before going into the implementation, let's see how we should output the JS code. + +That source code will generate this JS + +```tsx +var x = 1; +var y = 2; +``` + +In a string format, it would look like this: + +```tsx +'var x = 1;\n;\nvar y = 2;\n'; +``` + +## `Lexer`: building tokens + +As we've seen in the previous posts of the series, we already are handling the semicolon `;` token. + +```tsx +case ';': + token = Token.Semicolon; + break; +``` + +This is what we have and all we need to do to handle semicolons. Having it already implemented, let's go to the parser. + +## `Parser`: building AST nodes + +I think this is the most important part of this implementation. But it is actually pretty simple. Whenever the compiler is reading a `Semicolon` token, we should create and return a node representation for the `EmptyStatement`. + +The first step is to create the `EmptyStatement` type: + +```diff +export enum Node { + Identifier, + NumericLiteral, + Assignment, + ExpressionStatement, + Var, + Let, + TypeAlias, + StringLiteral, ++ EmptyStatement, + VariableStatement, + VariableDeclarationList, + VariableDeclaration, +} +``` + +We also need to add it to the list of possible statements: + +```tsx +type EmptyStatement = { + kind: Node.EmptyStatement; +}; + +export type Statement = + | ExpressionStatement + | TypeAlias + | EmptyStatement + | VariableStatement; +``` + +Now all we need to do is to create the AST node when the compiler is reading the semicolon token. + +```tsx +if (tryParseToken(Token.Semicolon)) { + return { kind: Node.EmptyStatement }; +} +``` + +Here it's! If the current token is the `Semicolon`, the compiler just needs to create and return the `EmptyStatement` AST node. Different from the other nodes, this one doesn't have anything else besides the `kind`. + +## `Binder`: storing symbols + +In the binder, the compiler usually stores symbols like variable or type declarations. As it's an empty statement and we don't need to resolve to get the “declaration” of it nor its type, we don't need to store anything here. + +Let's go to the type checker. + +## `Type Checker`: checking empty statements + +## Final words + +In this piece of content, my goal was to show the whole implementation of string literals: + +- What's required to implement in each phase of the compiler (lexer, parser, type checker, and emitter) +- How to handle regular, unterminated, and escaped strings + +I hope it can be a nice source of knowledge to understand more about the TypeScript compiler and compilers in general. This is part of my last 3 months I've been studying, researching, and working on the TS compiler miniature. + +This is a [series](/series/the-typescript-compiler) of posts about compilers and if you didn't have the chance to see the previous two posts, take a look at them: + +- [A High Level Architecture of the TypeScript compiler](/a-high-level-architecture-of-the-typescript-compiler) +- [JavaScript scope, Closures, and the TypeScript compiler](/javascript-scope-closures-and-the-typescript-compiler) +- [A Deep Dive into the TypeScript Compiler Miniature](/a-deep-dive-into-the-typescript-compiler-miniature) + +For additional content on compilers and programming language theory, have a look at the [Programming Language Design](/tags/programming-language-design) tag and the [Programming Language Research](https://github.com/imteekay/programming-language-research) repo. + +## Resources + +### TS Compiler + +- [TypeScript codebase](https://github.com/microsoft/typescript?utm_source=iamtk.co&utm_medium=referral&utm_campaign=tk_newsletter) +- [How the TypeScript Compiler Compiles](https://www.youtube.com/watch?v=X8k_4tZ16qU&utm_source=iamtk.co&utm_medium=referral&utm_campaign=tk_newsletter) +- [mini-typescript](https://github.com/imteekay/mini-typescript) +- [TypeScript Compiler Manual](https://sandersn.github.io/manual/Typescript-compiler-implementation.html?utm_source=iamtk.co&utm_medium=referral&utm_campaign=tk_newsletter) +- [A High Level Architecture of the TypeScript compiler](/a-high-level-architecture-of-the-typescript-compiler) +- [JavaScript scope, Closures, and the TypeScript compiler](/javascript-scope-closures-and-the-typescript-compiler) +- [A Deep Dive into the TypeScript Compiler Miniature](/a-deep-dive-into-the-typescript-compiler-miniature) + +--- + +### PRs & Helped the implementation + +- [Ecmascript SingleEscapeCharacter](https://262.ecma-international.org/13.0/#prod-SingleEscapeCharacter) +- [Clarification on String literals issue](https://github.com/sandersn/mini-typescript/issues/15) +- [Implementing String literals](https://github.com/imteekay/mini-typescript-fork/pull/4) +- [Handling unterminated strings](https://github.com/imteekay/mini-typescript-fork/pull/12) +- [Fix string literal test](https://github.com/imteekay/mini-typescript-fork/pull/14) + +--- + + diff --git a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json new file mode 100644 index 00000000..e08b0920 --- /dev/null +++ b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json @@ -0,0 +1,23 @@ +{ + "title": "Building EmptyStatement and Semicolon as statement ender for the TypeScript compiler", + "description": "Understanding how empty statement and semicolon as statement ender are implemented in the TypeScript compiler", + "date": "2023-07-21", + "tags": [ + { + "href": "/tags/typescript", + "name": "typescript" + }, + { + "href": "/tags/programming-language-design", + "name": "programming_language_design" + } + ], + "coverImage": { + "src": "/implementing-string-literals-for-the-typescript-compiler/cover.jpg", + "width": "640", + "height": "426", + "alt": "lights in the tree in the dark", + "authorHref": "https://unsplash.com/@jarispics", + "authorName": "Jari Hytönen" + } +} From 6550da62966e7829a0a44d48f7d6418f17b00241 Mon Sep 17 00:00:00 2001 From: imteekay Date: Thu, 20 Jul 2023 07:31:19 -0300 Subject: [PATCH 2/7] * --- .../en/index.mdx | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx index 65eee1ac..6961cb89 100644 --- a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx +++ b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx @@ -149,6 +149,35 @@ Let's go to the type checker. ## `Type Checker`: checking empty statements +As we created a new AST node for statements, we need to return a new type for it in the type checking process. This is the new type for empty statements: + +```tsx +const empty: Type = { id: 'empty' }; +``` + +And when the compiler is checking the empty statement, we just need to return this new type. + +```tsx +case Node.EmptyStatement: + return empty; +``` + +## Transforming and emitting JS + +In the transformation process, we don't need to do anything extra in terms of transformation, it should just return the actual empty statement. + +```tsx +case Node.EmptyStatement: + return [statement]; +``` + +The emitting process is pretty similar. When handling the emit for empty statements, the compiler will return an empty string so it doesn't return anything. + +```tsx +case Node.EmptyStatement: + return ''; +``` + ## Final words In this piece of content, my goal was to show the whole implementation of string literals: From b351af2d8b7e530b460d184b766ff2d4036308c3 Mon Sep 17 00:00:00 2001 From: imteekay Date: Thu, 20 Jul 2023 07:32:30 -0300 Subject: [PATCH 3/7] * --- .../en/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json index e08b0920..0fafa556 100644 --- a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json +++ b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json @@ -1,5 +1,5 @@ { - "title": "Building EmptyStatement and Semicolon as statement ender for the TypeScript compiler", + "title": "Building EmptyStatement and Semicolon as a statement ender for the TypeScript compiler", "description": "Understanding how empty statement and semicolon as statement ender are implemented in the TypeScript compiler", "date": "2023-07-21", "tags": [ From 56802af4c23b15b735d48696140990b98e165517 Mon Sep 17 00:00:00 2001 From: imteekay Date: Thu, 20 Jul 2023 15:49:49 -0300 Subject: [PATCH 4/7] * --- .../en/index.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx index 6961cb89..f69b8dc1 100644 --- a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx +++ b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx @@ -178,6 +178,10 @@ case Node.EmptyStatement: return ''; ``` +That's it! We've finished the implementation of empty statements. To complement this feature, we are going to also implement semicolons as a statement ender. + +The process will look very similar to what we did for empty statements: examples, AST nodes, JS output, and the whole compiler steps. + ## Final words In this piece of content, my goal was to show the whole implementation of string literals: From 6ff7bb59acf73cb088692790f6290a528c9c7195 Mon Sep 17 00:00:00 2001 From: imteekay Date: Thu, 20 Jul 2023 16:30:08 -0300 Subject: [PATCH 5/7] * --- .../en/index.mdx | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx index f69b8dc1..5a3f33ad 100644 --- a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx +++ b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx @@ -182,6 +182,170 @@ That's it! We've finished the implementation of empty statements. To complement The process will look very similar to what we did for empty statements: examples, AST nodes, JS output, and the whole compiler steps. +Before, we were using semicolons as separators, but now we are going to use semicolons as statement enders. So, every time we parse a new statement, we expect a “terminator”, in this case, a semicolon. + +As semicolons are optional in JavaScript, it doesn't break the parser if after the statement is parsed, it doesn't have a semicolon as the terminator. If it does, it just moves the pointer to the next token. + +In general, this change is more like a refactoring than a new feature of the language. The behavior shouldn't change. + +Let's see an example: + +```tsx +var x = 1; +var y = 2; +var z = 3; +x;y;z; +``` + +For this example, we generate these AST nodes + +```tsx +[ + { + "kind": "Var", + "name": { + "kind": "Identifier", + "text": "x" + }, + "init": { + "kind": "NumericLiteral", + "value": 1 + } + }, + { + "kind": "Var", + "name": { + "kind": "Identifier", + "text": "y" + }, + "init": { + "kind": "NumericLiteral", + "value": 2 + } + }, + { + "kind": "Var", + "name": { + "kind": "Identifier", + "text": "z" + }, + "init": { + "kind": "NumericLiteral", + "value": 3 + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "Identifier", + "text": "x" + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "Identifier", + "text": "y" + } + }, + { + "kind": "ExpressionStatement", + "expr": { + "kind": "Identifier", + "text": "z" + } + } +] +``` + +Nothing new here, we just have three variable declarations and three expressions for each variable declared. + +The JS output is pretty much the same as the source code: + +```tsx +var x = 1; +var y = 2; +var z = 3; +x; +y; +z; +``` + +Or in a string format, it should look like this: + +```tsx +"var x = 1;\nvar y = 2;\nvar z = 3;\nx;\ny;\nz;\n" +``` + +As we’re refactoring the compiler, we are going to modify only the parser and the emitter. So all of the other steps won't change. We don't need to do anything for the lexer, the binder, the type checker, and the transformer. + +## `Parser`: parsing statement enders + +As we've seen before, every time the parser parses a new statement, it needs to parse the terminator, in this case, the semicolon (`;`). And we also know the parser won't break if the terminator is not there because semicolons are optional in JavaScript. + +The algorithm for this is pretty simple. This is what we need to do: + +- Parse a statement +- Parse the terminator (terminator is optional) +- Peek if the next token is not the “end of file” (`EOF`) token. If not, loop and continue the same algorithm + +Here it's: + +```tsx +function parseStatements( + element: () => T, + terminator: () => boolean, + peek: () => boolean, +) { + const list = []; + while (peek()) { + list.push(element()); + terminator(); + } + return list; +} +``` + +Every time it parses a new statement, it pushes it to the list. At the end of the function, it just returns the list of statements (AST nodes). + +And this is who it's used: + +```tsx +parseStatements( + parseStatement, + () => tryParseToken(Token.Semicolon), + () => lexer.token() !== Token.EOF, +) +``` + +- `element` → `parseStatement` +- `terminator` → `tryParseToken` for semicolon +- `peek` → is the current token the `Token.EOF`? + +I really liked this design and how it simplifies the parsing. + +## `Emitter`: emitting JS code + +Before, semicolons were handled as separators, so the emitting phase was done by just joining the statements with the `';\n'` string and that was fine. + +But now that semicolons are terminators, we should always have this `';\n'` string at the end of each statement in the JS output. + +Before, the emitting code was like this: + +```tsx +statements.map(emitStatement).join(';\n'); +``` + +Joining was enough. But now we should move this string to the end of each statement. One way of doing that is to just concatenate it to the end of the emitted statement in the mapping, and then join the statements: + +```tsx +statements + .map((statement) => `${emitStatement(statement)};\n`) + .join(''); +``` + +That way, all statements finish with the semicolon and a line break. + ## Final words In this piece of content, my goal was to show the whole implementation of string literals: From 29644b725feeb2d718fe86adae57d6f8b59f58ae Mon Sep 17 00:00:00 2001 From: imteekay Date: Thu, 20 Jul 2023 16:36:27 -0300 Subject: [PATCH 6/7] * --- .../en/index.mdx | 17 +++++++++-------- .../en/index.mdx | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx index 5a3f33ad..745eab31 100644 --- a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx +++ b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/index.mdx @@ -348,10 +348,10 @@ That way, all statements finish with the semicolon and a line break. ## Final words -In this piece of content, my goal was to show the whole implementation of string literals: +In this piece of content, my goal was to show the whole implementation of empty statements and use semicolons as statement enders: - What's required to implement in each phase of the compiler (lexer, parser, type checker, and emitter) -- How to handle regular, unterminated, and escaped strings +- How to refactor the parser to handle semicolons as terminators I hope it can be a nice source of knowledge to understand more about the TypeScript compiler and compilers in general. This is part of my last 3 months I've been studying, researching, and working on the TS compiler miniature. @@ -360,6 +360,7 @@ This is a [series](/series/the-typescript-compiler) of posts about compilers and - [A High Level Architecture of the TypeScript compiler](/a-high-level-architecture-of-the-typescript-compiler) - [JavaScript scope, Closures, and the TypeScript compiler](/javascript-scope-closures-and-the-typescript-compiler) - [A Deep Dive into the TypeScript Compiler Miniature](/a-deep-dive-into-the-typescript-compiler-miniature) +- [Implementing StringLiterals for the TypeScript Compiler](/implementing-string-literals-for-the-typescript-compiler) For additional content on compilers and programming language theory, have a look at the [Programming Language Design](/tags/programming-language-design) tag and the [Programming Language Research](https://github.com/imteekay/programming-language-research) repo. @@ -374,16 +375,16 @@ For additional content on compilers and programming language theory, have a look - [A High Level Architecture of the TypeScript compiler](/a-high-level-architecture-of-the-typescript-compiler) - [JavaScript scope, Closures, and the TypeScript compiler](/javascript-scope-closures-and-the-typescript-compiler) - [A Deep Dive into the TypeScript Compiler Miniature](/a-deep-dive-into-the-typescript-compiler-miniature) +- [Implementing StringLiterals for the TypeScript Compiler](/implementing-string-literals-for-the-typescript-compiler) --- -### PRs & Helped the implementation +### PRs & What helped the implementation -- [Ecmascript SingleEscapeCharacter](https://262.ecma-international.org/13.0/#prod-SingleEscapeCharacter) -- [Clarification on String literals issue](https://github.com/sandersn/mini-typescript/issues/15) -- [Implementing String literals](https://github.com/imteekay/mini-typescript-fork/pull/4) -- [Handling unterminated strings](https://github.com/imteekay/mini-typescript-fork/pull/12) -- [Fix string literal test](https://github.com/imteekay/mini-typescript-fork/pull/14) +- [EmptyStatement](https://github.com/imteekay/mini-typescript-fork/pull/2) +- [Fix empty statement in the transformer](https://github.com/imteekay/mini-typescript-fork/pull/10) +- [Semicolon as statement ender](https://github.com/imteekay/mini-typescript-fork/pull/7) +- [ECMAScript EmptyStatement spec](https://tc39.es/ecma262/multipage/ecmascript-language-statements-and-declarations.html#sec-empty-statement) --- diff --git a/content/implementing-string-literals-for-the-typescript-compiler/en/index.mdx b/content/implementing-string-literals-for-the-typescript-compiler/en/index.mdx index dd7d5e4c..42a570a8 100644 --- a/content/implementing-string-literals-for-the-typescript-compiler/en/index.mdx +++ b/content/implementing-string-literals-for-the-typescript-compiler/en/index.mdx @@ -470,7 +470,7 @@ For additional content on compilers and programming language theory, have a look --- -### PRs & Helped the implementation +### PRs & What helped the implementation - [Ecmascript SingleEscapeCharacter](https://262.ecma-international.org/13.0/#prod-SingleEscapeCharacter) - [Clarification on String literals issue](https://github.com/sandersn/mini-typescript/issues/15) From 500cfbf0a73e2792f34b2c3a8d006a2ce131b784 Mon Sep 17 00:00:00 2001 From: imteekay Date: Thu, 20 Jul 2023 16:45:57 -0300 Subject: [PATCH 7/7] * --- .../en/metadata.json | 12 ++++++------ .../cover.jpg | Bin 0 -> 21655 bytes 2 files changed, 6 insertions(+), 6 deletions(-) create mode 100644 public/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/cover.jpg diff --git a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json index 0fafa556..2345f36d 100644 --- a/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json +++ b/content/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/en/metadata.json @@ -1,7 +1,7 @@ { "title": "Building EmptyStatement and Semicolon as a statement ender for the TypeScript compiler", "description": "Understanding how empty statement and semicolon as statement ender are implemented in the TypeScript compiler", - "date": "2023-07-21", + "date": "2023-07-23", "tags": [ { "href": "/tags/typescript", @@ -13,11 +13,11 @@ } ], "coverImage": { - "src": "/implementing-string-literals-for-the-typescript-compiler/cover.jpg", + "src": "/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/cover.jpg", "width": "640", - "height": "426", - "alt": "lights in the tree in the dark", - "authorHref": "https://unsplash.com/@jarispics", - "authorName": "Jari Hytönen" + "height": "360", + "alt": "bare tree lot", + "authorHref": "https://unsplash.com/@kefiijrw", + "authorName": "Sergey Nikolaev" } } diff --git a/public/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/cover.jpg b/public/building-emptystatement-and-semicolon-as-statement-ender-for-the-typescript-compiler/cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..74041cefcc4cfa024fb9af57aadd626eb8e5c77e GIT binary patch literal 21655 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