AntlrDenter 0.1.0
dotnet add package AntlrDenter --version 0.1.0
NuGet\Install-Package AntlrDenter -Version 0.1.0
<PackageReference Include="AntlrDenter" Version="0.1.0" />
<PackageVersion Include="AntlrDenter" Version="0.1.0" />
<PackageReference Include="AntlrDenter" />
paket add AntlrDenter --version 0.1.0
#r "nuget: AntlrDenter, 0.1.0"
#:package AntlrDenter@0.1.0
#addin nuget:?package=AntlrDenter&version=0.1.0
#tool nuget:?package=AntlrDenter&version=0.1.0
ANTLR-Denter: Python-like indentation tokens for ANTLR4 C# Hosts
This project adds INDENT and DEDENT tokens for autogenerated ANTLR4 parsers for Python-like scopes. This defines a DenterHelper that can be added to an ANTLR4 grammar.
This repository is a fork of yshavit's ANTLR-Denter project since the original repo is no longer maintained. This fork aims to maintain a C#-specific library using the official Antlr4.Runtime.Standard and support work with RenDisco.
Overview
This is a plugin that is spliced into an ANTLR grammar's lexer, and allows that lexer to make use of INDENT and DEDENT to represent Python-like scope entry and termination.
Features
Using INDENT and DEDENT tokens in a parser
When DenterHelper injects DEDENT tokens, it will prefix any string of them with a single NL. A single NL is also inserted before the EOF token if there are no DEDENTs to insert (that is, if the last line of the source file is not indented). A NL is not inserted before an INDENT, since indents always imply a newline before them (and thus make the newline token meaningless).
For example, given this input;
hello
world
universe
dolly
Would be parsed as;
"hello"
INDENT
"world"
INDENT
"universe"
NL
DEDENT
DEDENT
"dolly"
NL
<eof>
This approach lets you define expressions, single-line statements, and block statements naturally.
- Expressions in your parser grammar should not end in newlines. This makes compound expressions work naturally.
- Single-line statements in your grammar should end in newlines. For example, an assignment expression might be
identifier '=' expression NL. - Blocks are bookended by INDENT and DEDENT, without mentioning extra newlines:
block: INDENT statement+ DEDENT.- You should not include a newline before the INDENT
- An
ifwould be something likeif expression ':' block. (Note the lack ofNLafter the:.)
In the example above, universe and dolly represent simple expressions, and you can imagine that the grammar would contain something like statement: expression NL | helloBlock;.
Handling and asserting indentation
The DenterHelper processor asserts correct indentation on DEDENT. Take the following example:
someStatement()
if foo():
if bar():
fooAndBar()
bogusLine()
bogusLine() does not dedent to the indentation of any valid scope - lacking indentation to qualify as part of the if foo():'s scope and too indented to share a scope with someStatement(). In Python this is expressed as an IndentationError.
The DenterHelper processor handles this by inserting two tokens: a DEDENT followed immediately by an INDENT (the total sequence here would actually be two DEDENTs followed by an INDENT, since bogusLine() is twice-dedented from fooAndBar()). The rationale is that the line has dedented to its parent, and then indented.
As a consequence, the DenterHelper processor will also assert correct indentation for all lines where an INDENT is not expected. Take the following example in a Python-like grammar of two method calls:
someStatement()
bogusLine()
This would be illegal due to no INDENTs being expected after someStatement().
Usage
In an ANTLR grammar definition MyGrammar.g4, use the following.
tokens { INDENT, DEDENT }
@lexer::header {
using AntlrDenter.DenterHelper;
}
@lexer::members {
private DenterHelper denter;
public override IToken NextToken()
{
if (denter == null)
{
denter = DenterHelper.Builder()
.Nl(NL)
.Indent(MyGrammarParser.INDENT)
.Dedent(MyGrammarParser.DEDENT)
.PullToken(base.NextToken);
}
return denter.NextToken();
}
}
NL: ('\r'? '\n' ' '*); #For tabs just switch out ' '* with '\t'*
Note the injected code is dedented with respect to the @lexer::members block. This is so that it has the proper formatting in the resulting C# Lexer file.
Acknowledgements
Many thanks to yshavit for developing the original ANTLR-Denter, and tejacques for their Deque implementation.
Related Work
- The original ANTLR-Denter.
- ANTLR4, the language toolkit.
- kaby76's Antlr4BuildTasks, which has been used for further reading on C# and .NET with ANTLR.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Antlr4.Runtime.Standard (>= 4.13.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 240 | 12/15/2024 |