Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/elamaunt/gdshrapt

GDShrapt is object-oriented one-pass parser of GDScript programming language.
https://github.com/elamaunt/gdshrapt

converter csharp csharp-library dot-net gdscript gdshrapt godot godot-engine godot-engine-editor lexer library parser plugin reader rewriter shrapt tool translator

Last synced: 27 days ago
JSON representation

GDShrapt is object-oriented one-pass parser of GDScript programming language.

Awesome Lists containing this project

README

        

# GDShrapt

GDShrapt is an object-oriented one-pass parser of GDScript 2.0. Now the main goal is a production-ready parser, lexical analyzer.
The project written in C# and free to use.
GDScript is the main language of [Godot Engine](https://github.com/godotengine/godot)

**The project is created on personal initiative and on enthusiasm.**

## GDShrapt.Reader

GDShrapt.Reader allows to build a lexical tree or generate a new code from scratch.

### How to install

Currently the latest **4.3.0-alpha version** from [Nuget](https://www.nuget.org/packages/GDShrapt.Reader).

Installation from Nuget console:
```
Install-Package GDShrapt.Reader -Version 4.2.0-alpha
```
## Capabilities, plan and what can be parsed

| Capability | Is completed |
| ------------- | ------------- |
| One pass parsing | YES |
| Lexical tree structure | YES |
| Class declaration parsing | YES |
| Methods declaration parsing | YES |
| Enums parsing | YES |
| Atributes declaration parsing | YES |
| Variables declaration parsing | YES |
| Export block parsing | YES |
| Arrays parsing | YES |
| Dictionary parsing | YES |
| 'Match' statement parsing | YES |
| 'For' statement parsing | YES |
| 'While' statement parsing | YES |
| 'If-Elif-Else' statement parsing | YES |
| 'Yield' statement parsing | YES |
| Ternar 'If' expression parsing | YES |
| Signals parsing | YES |
| Strings parsing | YES |
| Numbers parsing | YES |
| Methods calls parsing | YES |
| Single operators parsing | YES |
| Dual operators parsing | YES |
| Static types parsing | YES |
| Expressions priority sorting | YES |
| Basic tokenization managment | YES |
| Save formatting while parsing | YES |
| Save comments while parsing | YES |
| Moving from tokens to parent | YES |
| NodePath and GetNode short syntax parsing | YES |
| Inner class parsing | YES |
| Tree walking and node visiting | YES |
| Syntax cloning | YES |
| Syntax factory | YES |
| Syntax errors managment and properly handling | IN PLAN |
| Code formatting | IN PLAN |
| Custom formatter | IN PLAN |
| Tree diff tool | IN PLAN |

## Last updates

#### 4.3.0-alpha
Improved intendation and space tokens parsing.
Now it works similar to Godot.

#### 4.2.0-alpha
Reworked attributes parsing.
Improved properties and intendation tokens parsing.
Fixed comma bugs.
Added new methods for attributes enumeration.

#### 4.1.4-alpha
Fixed dictionary with assignment parsing

#### 4.1.3-alpha
Fixed statics parsing

#### 4.1.2-alpha
Fixed lambda intendation parsing

#### 4.1.1-alpha
Fixed properties parsing
Fixed guard condition parsing
Minor improvements.

## Reading samples

### Parse class

GDScript input:

```gdscript
tool
class_name HTerrainDataSaver
extends ResourceFormatSaver

const HTerrainData = preload("./ hterrain_data.gd")

func get_recognized_extensions(res):
if res != null and res is HTerrainData:
return PoolStringArray([HTerrainData.META_EXTENSION])
return PoolStringArray()

func recognize(res):
return res is HTerrainData

func save(path, resource, flags):
resource.save_data(path.get_base_dir())
```

Parser usage:

```csharp
// Initialize a reader instance
var reader = new GDScriptReader();

// Parse the raw code
var @class = reader.ParseFileContent(code); // returns instance of type GDClassDeclaration

// Get 'extends' atribute information
Console.WriteLine(@class.Extends.Type.Sequence); // outputs base class name "ResourceFormatSaver"

// Get 'class_name' atribute information
Console.WriteLine(@class.ClassName.Type.Sequence); // outputs current class name "HTerrainDataSaver"

// Check 'tool' atribute
Console.WriteLine(@class.IsTool); // outputs true

// Enumerates all class variables
foreach(GDVariableDeclaration variable in @class.Variables)
{
Console.WriteLine(method.Identifier.Sequence); // outputs variables's name
}

// Enumerates all class methods
foreach(GDMethodDeclaration method in @class.Methods)
{
Console.WriteLine(method.Identifier.Sequence); // outputs method's name

// Enumerates all method statements
foreach(GDStatement st in method.Statements)
{
// ... your code
}
}
```

### Get comments from GDScript code

```csharp
var @class = reader.ParseFileContent(code);

// Add 'using System.Linq;'
var comments = @class.AllTokens
.OfType()
.Select(x => x.ToString()) // Convert token to string
.ToArray();
```

## Tree building samples or GDScript runtime generation

GDShrapt supports many styles to simplify a code generation process. Just use the GD static class to create a token or a node.

### Short style

```csharp
// Build a custom class. Safe code generation. Dont control a code style
var declaration = GD.Declaration.Class(
GD.List.Atributes(
GD.Atribute.Tool(),
GD.Atribute.ClassName("Generated"),
GD.Atribute.Extends("Node2D")),

GD.Declaration.Const("my_constant", GD.Expression.String("Hello World")),
GD.Declaration.OnreadyVariable("parameter", GD.Expression.True()),

GD.Declaration.Method("_start",
GD.Expression.Call(GD.Expression.Identifier("print"), GD.Expression.String("Hello world"))
)
);

declaration.UpdateIntendation(); // Auto update tabs (recursively)

var code = declaration.ToString(); // Get the string representation
```

The result is code like:

```gdscript
tool
class_name Generated
extends Node2D

const my_constant = "Hello World"

onready var parameter = true

func _start():
print("Hello world")
```

### Methods chain style

```csharp
// Build a custom class. Full tokens control, but unsafe for exceptions
var declaration = GD.Declaration.Class()
.AddAtributes(x => x
.AddToolAtribute()
.AddNewLine()
.AddClassNameAtribute("Generated")
.AddNewLine()
.AddExtendsAtribute("Node2D"))
.AddNewLine()
.AddNewLine()
.AddMembers(x => x
.AddVariable("a")
.AddNewLine()
.AddConst("message", GD.Expression.String("Hello"))
.AddNewLine()
.AddNewLine()
.AddMethod(x => x
.AddFuncKeyword()
.AddSpace()
.Add("_start")
.AddOpenBracket()
.AddCloseBracket()
.AddStatements(x => x
.AddNewLine()
.AddNewLine()
.AddIntendation()
.AddCall(GD.Expression.Identifier("print"), GD.Expression.String("Hello world"))
.AddNewLine()
.AddNewLine()
.AddIntendation()
.AddPass())));

declaration.UpdateIntendation(); // Auto update tabs (recursively)

var code = declaration.ToString(); // Get the string representation
```

### Tokens list style

```csharp
// Build a custom class. Full tokens control but unsafe for types
var declaration = GD.Declaration.Class(
GD.List.Atributes(
GD.Atribute.Tool(),
GD.Syntax.NewLine,
GD.Atribute.ClassName("Generated"),
GD.Syntax.NewLine,
GD.Atribute.Extends("Node2D")),

GD.Syntax.NewLine,
GD.Syntax.NewLine,

GD.Declaration.Variable(
GD.Keyword.Const,
GD.Syntax.OneSpace,
GD.Syntax.Identifier("my_constant"),
GD.Syntax.OneSpace,
GD.Syntax.Assign,
GD.Syntax.OneSpace,
GD.Syntax.String("Hello World")),

GD.Syntax.NewLine,
GD.Syntax.NewLine,

GD.Declaration.Variable(
GD.Keyword.Onready,
GD.Syntax.OneSpace,
GD.Keyword.Var,
GD.Syntax.OneSpace,
GD.Syntax.Identifier("parameter"),
GD.Syntax.OneSpace,
GD.Syntax.Assign,
GD.Syntax.OneSpace,
GD.Expression.True()),

GD.Syntax.NewLine,
GD.Syntax.NewLine,

GD.Declaration.Method(
GD.Keyword.Func,
GD.Syntax.OneSpace,
GD.Syntax.Identifier("_start"),
GD.Syntax.OpenBracket,
GD.Syntax.CloseBracket,
GD.Syntax.Colon,

GD.Syntax.NewLine,
GD.Syntax.Intendation(1),
GD.Expression.Call(
GD.Expression.Identifier("print"),
GD.Syntax.OpenBracket,
GD.List.Expressions(GD.Expression.String("Hello world")),
GD.Syntax.CloseBracket)));

var code = declaration.ToString(); // Get the string representation
```

### Custom style initialization

```csharp
// The sample of a For statement initizalization with a predefined style. It is how the GD.Statement.For method works.
// You must know the 'form' to use this format.
// For example a code line like "[1] = GD.Syntax.Space()" will insert a space token BEFORE the first static point in the nodes form.
// In the code below the first point of the For statement is the iterator's variable name.
public static GDForStatement For(GDIdentifier variable, GDExpression collection, GDExpression body) => new GDForStatement()
{
ForKeyword = new GDForKeyword(),
[1] = GD.Syntax.Space(),
Variable = variable,
[2] = GD.Syntax.Space(),
InKeyword = new GDInKeyword(),
[3] = GD.Syntax.Space(),
Collection = collection,
Colon = new GDColon(),
[5] = GD.Syntax.Space(),
Expression = body
};
```

You may use a combination of the styles.

### Calculating properties

```csharp

GDSyntaxToken token = null; // any token

token.StartLine // calculate the start line of the token in the code
token.EndLine // calculate the end line of the token in the code
token.Length // calculate the length of the token
token.StartColumn // calculate the start column in the line
token.EndColumn // calculate the end column in the line
token.NewLinesCount // calculate new line characters in the token.

token.ClassMember // find the nearest class member from parents
token.MainClassDeclaration // find the main class contains the token
token.Parents // enumerate all parents of the token
```

For more samples see the [tests](src/GDShrapt.Reader.Tests/ParsingTests.cs).