Skip to content

Commit d826c65

Browse files
committed
Add a stub documentation that gives a brief overview of AST analysis
1 parent 6e414c6 commit d826c65

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

docs/analysing_ast.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Analyzing student code with the GDScript AST
2+
3+
The app uses a custom version of the Godot engine that exposes the GDScriptParser's parse tree.
4+
5+
## Access
6+
7+
1. Create a `GDScriptErrorChecker`
8+
2. Call `set_source()` and provide the source code. The code should be a valid, parsable class.
9+
3. Provided there are no parser, analyzer, or compiler errors, you can then call `get_root_parse_node()`, which returns a `GDClassNode`.
10+
11+
`set_source()` will return `OK` if there are no parser, analyzer, or compiler errors.
12+
13+
If you mean to analyze the parser nodes outside of the scope where you set the checker up, make sure to keep a reference to it. Once the `GDScriptErrorChecker` has its RefCount go to 0, it will clear the parser and all the nodes, and you will get garbage data out of the GDNodes at best.
14+
15+
### Low level access
16+
17+
The most raw way of analyzing student code is to directly access the functions in the root `GDClassNode`, like `get_member(function_name)` to get a `GDFunctionNode`.
18+
19+
See the in-editor documentation for the individual `GDNode` RefCounted objects for the API.
20+
21+
### High level access
22+
23+
The `GDScriptASTAnalyzer` class is available to make accessing data easier without worrying about the API as much.
24+
25+
```gdscript
26+
var checker = GDScriptErrorChecker.new()
27+
checker.set_source(class_code)
28+
var root := _checker.get_root_parse_node()
29+
var analyzer = GDScriptASTAnalyzer.new(root)
30+
```
31+
32+
From there, you can access friendly functions like `analyzer.get_function_named(function_name)` and `analyzer.get_function_parameter_name(function, parameter_index)`.
33+
34+
#### Expression system
35+
36+
If you want to check that the tree has a particular shape and uses particular patterns, you can use the `GDExpr` class' static functions to build a comparator tree.
37+
38+
For example, the expected code is
39+
40+
```gdscript
41+
func run():
42+
var health = 100
43+
44+
if health > 5:
45+
print("health is greater than five.")
46+
```
47+
48+
To verify it, I can thus write an expression against it:
49+
50+
```gdscript
51+
func test_statement_is_true() -> String:
52+
var run_function := _analyzer.get_function_named("run")
53+
54+
# suites are the bodies of functions, loops, match branches, etc
55+
if not GDExpr.suite(
56+
# if
57+
GDExpr.if_block(
58+
# health > 5
59+
GDExpr.bin_op(
60+
GDExpr.identifier("health"),
61+
GDExpr.literal(5),
62+
GDBinaryOpNode.OP_COMP_GREATER
63+
)
64+
)
65+
).matches(run_function):
66+
return tr("The comparison is not correct. Did you use the right comparison?")
67+
return ""
68+
```

0 commit comments

Comments
 (0)