add script for extracting EBNF grammar from doccomments
This commit is contained in:
parent
6e27474da4
commit
3271ca514c
520
grammar.md
520
grammar.md
|
@ -1,63 +1,145 @@
|
||||||
# Grammar of the Shulkerscript language
|
# Grammar of the Shulkerscript language
|
||||||
|
|
||||||
## Table of contents
|
## Program
|
||||||
|
|
||||||
### Program
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Program: Namespace Declaration*;
|
Program:
|
||||||
|
Namespace
|
||||||
|
Declaration*
|
||||||
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Namespace
|
## Declaration
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Namespace: 'namespace' StringLiteral;
|
Declaration:
|
||||||
|
Function
|
||||||
|
| Import
|
||||||
|
| TagDeclaration
|
||||||
|
| ('pub'? VariableDeclaration ';')
|
||||||
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
### StringLiteral
|
## Namespace
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
StringLiteral: '"' TEXT '"';
|
Namespace:
|
||||||
|
'namespace' StringLiteral ';' ;
|
||||||
```
|
```
|
||||||
|
|
||||||
### MacroStringLiteral
|
## Function
|
||||||
```ebnf
|
|
||||||
MacroStringLiteral: '`' ( TEXT | '$(' [a-zA-Z0-9_]+ ')' )* '`';
|
|
||||||
```
|
|
||||||
|
|
||||||
### AnyStringLiteral
|
|
||||||
```ebnf
|
|
||||||
AnyStringLiteral: StringLiteral | MacroStringLiteral;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Declaration
|
|
||||||
```ebnf
|
|
||||||
Declaration: FunctionDeclaration | Import | TagDeclaration;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Import
|
|
||||||
```ebnf
|
|
||||||
Import: 'from' StringLiteral 'import' Identifier;
|
|
||||||
```
|
|
||||||
|
|
||||||
### TagDeclaration
|
|
||||||
```ebnf
|
|
||||||
TagDeclaration: 'tag' StringLiteral ('of' StringLiteral)? 'replace'? '[' (StringLiteral (',' StringLiteral)*)? ']';
|
|
||||||
```
|
|
||||||
|
|
||||||
### FunctionDeclaration
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Function:
|
Function:
|
||||||
Annotation* 'pub'? 'fn' Identifier '(' ParameterList? ')' Block
|
Annotation* 'pub'? 'fn' Identifier '(' FunctionParameterList? ')' Block
|
||||||
;
|
|
||||||
ParameterList:
|
|
||||||
Identifier (',' Identifier)* ','?
|
|
||||||
;
|
;
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Annotation
|
## Import
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Annotation: '#[' Identifier ('=' StringLiteral)? ']';
|
Import:
|
||||||
|
'from' StringLiteral 'import' ('*' | Identifier (',' Identifier)*) ';'
|
||||||
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Statement
|
## TagDeclaration
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
TagDeclaration:
|
||||||
|
'tag' ('<' StringLiteral '>')? StringLiteral 'replace'? '[' (StringLiteral (',' StringLiteral)*)? ']'
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## VariableDeclaration
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
VariableDeclaration:
|
||||||
|
SingleVariableDeclaration
|
||||||
|
| ArrayVariableDeclaration
|
||||||
|
| ScoreVariableDeclaration
|
||||||
|
| TagVariableDeclaration
|
||||||
|
| ComptimeValueDeclaration
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## StringLiteral
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
StringLiteral:
|
||||||
|
'"' TEXT '"';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Annotation
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Annotation:
|
||||||
|
'#[' AnnotationAssignment ']'
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Block
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Block:
|
||||||
|
'{' Statement* '}'
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## FunctionParameterList
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
FunctionParameterList:
|
||||||
|
FunctionArgument (',' FunctionArgument)* ','?
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## ArrayVariableDeclaration
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
ArrayVariableDeclaration:
|
||||||
|
('int' | 'bool') identifier '[' integer ']' VariableDeclarationAssignment?
|
||||||
|
```
|
||||||
|
|
||||||
|
## ComptimeValueDeclaration
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
ComptimeValueDeclaration:
|
||||||
|
'val' identifier VariableDeclarationAssignment?
|
||||||
|
```
|
||||||
|
|
||||||
|
## ScoreVariableDeclaration
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
ScoreVariableDeclaration:
|
||||||
|
'int' ('<' StringLiteral '>')? identifier '[' AnyStringLiteral? ']' VariableDeclarationAssignment?
|
||||||
|
```
|
||||||
|
|
||||||
|
## SingleVariableDeclaration
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
SingleVariableDeclaration:
|
||||||
|
('int' | 'bool') identifier VariableDeclarationAssignment?
|
||||||
|
```
|
||||||
|
|
||||||
|
## TagVariableDeclaration
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
TagVariableDeclaration:
|
||||||
|
'bool' identifier '[' AnyStringLiteral? ']' VariableDeclarationAssignment?
|
||||||
|
```
|
||||||
|
|
||||||
|
## AnnotationAssignment
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
AnnotationAssignment:
|
||||||
|
Identifier AnnotationValue
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Statement
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Statement:
|
Statement:
|
||||||
Block
|
Block
|
||||||
|
@ -65,115 +147,345 @@ Statement:
|
||||||
| Conditional
|
| Conditional
|
||||||
| Grouping
|
| Grouping
|
||||||
| DocComment
|
| DocComment
|
||||||
|
| ExecuteBlock
|
||||||
| Semicolon
|
| Semicolon
|
||||||
| Run
|
|
||||||
;
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Block
|
## FunctionArgument
|
||||||
```ebnf
|
|
||||||
Block: '{' Statement* '}';
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Run:
|
FunctionArgument:
|
||||||
'run' Expression ';'
|
FunctionVariableType Identifier
|
||||||
;
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Conditional
|
## VariableDeclarationAssignment
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
VariableDeclarationAssignment:
|
||||||
|
'=' Expression
|
||||||
|
```
|
||||||
|
|
||||||
|
## AnyStringLiteral
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
AnyStringLiteral: StringLiteral | MacroStringLiteral ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## AnnotationValue
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
AnnotationValue:
|
||||||
|
'=' Expression
|
||||||
|
| '(' AnnotationAssignment ( ',' AnnotationAssignment )* ')'
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conditional
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Conditional:
|
Conditional:
|
||||||
'if' ParenthizedCondition Block ('else' Block)?
|
'if' Parenthized
|
||||||
;
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Condition
|
## ExecuteBlock
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Condition:
|
ExecuteBlock:
|
||||||
PrimaryCondition
|
(ExecuteBlockHead ExecuteBlockTail)
|
||||||
BinaryCondition
|
| (Conditional Block Else)
|
||||||
;
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
#### PrimaryCondition
|
## Grouping
|
||||||
```ebnf
|
|
||||||
PrimaryCondition:
|
|
||||||
ConditionalPrefix
|
|
||||||
| ParenthesizedCondition
|
|
||||||
| AnyStringLiteral
|
|
||||||
;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ConditionalPrefix
|
|
||||||
```ebnf
|
|
||||||
ConditionalPrefix:
|
|
||||||
ConditionalPrefixOperator PrimaryCondition
|
|
||||||
;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ConditionalPrefixOperator
|
|
||||||
``` ebnf
|
|
||||||
ConditionalPrefixOperator: '!';
|
|
||||||
```
|
|
||||||
|
|
||||||
#### BinaryCondition
|
|
||||||
``` ebnf
|
|
||||||
BinaryCondition:
|
|
||||||
Condition ConditionalBinaryOperator Condition
|
|
||||||
;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ConditionalBinaryOperator
|
|
||||||
``` ebnf
|
|
||||||
ConditionalBinaryOperator:
|
|
||||||
'&&'
|
|
||||||
| '||'
|
|
||||||
;
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ParenthizedCondition
|
|
||||||
```ebnf
|
|
||||||
ParenthizedCondition:
|
|
||||||
'(' Condition ')'
|
|
||||||
;
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Grouping
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Grouping:
|
Grouping:
|
||||||
'group' Block
|
'group' Block
|
||||||
;
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Expression
|
## Semicolon
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Semicolon:
|
||||||
|
SemicolonStatement ';'
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## FunctionVariableType
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
FunctionVariableType:
|
||||||
|
'macro' | 'int' | 'bool'
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expression
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Expression:
|
Expression:
|
||||||
Primary
|
Primary | Binary ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## MacroStringLiteral
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
MacroStringLiteral:
|
||||||
|
'`' ( TEXT | '$(' [a-zA-Z0-9_]+ ')' )* '`';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Else
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Else:
|
||||||
|
'else' Block
|
||||||
;
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Primary
|
## ExecuteBlockHead
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
ExecuteBlockHead:
|
||||||
|
Conditional
|
||||||
|
| Align
|
||||||
|
| Anchored
|
||||||
|
| As
|
||||||
|
| AsAt
|
||||||
|
| At
|
||||||
|
| Facing
|
||||||
|
| In
|
||||||
|
| On
|
||||||
|
| Positioned
|
||||||
|
| Rotated
|
||||||
|
| Store
|
||||||
|
| Summon
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## ExecuteBlockTail
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
ExecuteBlockTail:
|
||||||
|
ExecuteBlock
|
||||||
|
| Block
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## SemicolonStatement
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
SemicolonStatement:
|
||||||
|
(Expression | VariableDeclaration | Assignment | ReturnStatement)
|
||||||
|
';'
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Binary
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Binary:
|
||||||
|
Expression BinaryOperator Expression
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Primary
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
Primary:
|
Primary:
|
||||||
FunctionCall
|
Identifier
|
||||||
| AnyStringLiteral
|
| Prefix
|
||||||
|
| Parenthesized
|
||||||
|
| Indexed
|
||||||
|
| Integer
|
||||||
|
| Boolean
|
||||||
|
| StringLiteral
|
||||||
|
| FunctionCall
|
||||||
|
| MemberAccess
|
||||||
|
| MacroStringLiteral
|
||||||
| LuaCode
|
| LuaCode
|
||||||
|
```
|
||||||
|
|
||||||
|
## Align
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Align:
|
||||||
|
'align' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Anchored
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Anchored:
|
||||||
|
'anchored' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## As
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
As:
|
||||||
|
'as' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## AsAt
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
AsAt:
|
||||||
|
'asat' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## At
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
At:
|
||||||
|
'at' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Facing
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Facing:
|
||||||
|
'facing' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## In
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
In:
|
||||||
|
'in' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## On
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
On:
|
||||||
|
'on' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Positioned
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Positioned:
|
||||||
|
'positioned' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rotated
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Rotated:
|
||||||
|
'rotated' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Store
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Store:
|
||||||
|
'store' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Summon
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Summon:
|
||||||
|
'summon' '(' AnyStringLiteral ')' ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Assignment
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Assignment:
|
||||||
|
AssignmentDestination '=' Expression
|
||||||
|
```
|
||||||
|
|
||||||
|
## ReturnStatement
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
ReturnStatement:
|
||||||
|
`return` Expression ;
|
||||||
|
```
|
||||||
|
|
||||||
|
## BinaryOperator
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
BinaryOperator:
|
||||||
|
'+'
|
||||||
|
| '-'
|
||||||
|
| '*'
|
||||||
|
| '/'
|
||||||
|
| '%'
|
||||||
|
| '=='
|
||||||
|
| '!='
|
||||||
|
| '<'
|
||||||
|
| '<='
|
||||||
|
| '>'
|
||||||
|
| '>='
|
||||||
|
| '&&'
|
||||||
|
| '||'
|
||||||
;
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
### FunctionCall
|
## FunctionCall
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
FunctionCall:
|
FunctionCall:
|
||||||
Identifier '(' (Expression (',' Expression)*)? ')'
|
Identifier '(' (Expression (',' Expression)*)? ')'
|
||||||
;
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
### LuaCode
|
## Indexed
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Indexed:
|
||||||
|
PrimaryExpression '[' Expression ']'
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## LuaCode
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
LuaCode:
|
LuaCode:
|
||||||
'lua' '(' (Expression (',' Expression)*)? ')' '{' (.*?)* '}'
|
'lua' '(' (Expression (',' Expression)*)? ')' '{' (.*?)* '}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## MemberAccess
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
MemberAccess:
|
||||||
|
Primary '.' Identifier
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parenthesized
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Parenthesized:
|
||||||
|
'(' Expression ')'
|
||||||
;
|
;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Prefix
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
Prefix:
|
||||||
|
PrefixOperator Primary
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## AssignmentDestination
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
AssignmentDestination:
|
||||||
|
Identifier
|
||||||
|
| Identifier '[' Expression ']'
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
## PrefixOperator
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
PrefixOperator:
|
||||||
|
'!' | '-' | 'run'
|
||||||
|
;
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
from collections import defaultdict, deque
|
||||||
|
|
||||||
|
ebnf_blocks = []
|
||||||
|
rule_defs = {}
|
||||||
|
rule_deps = defaultdict(set)
|
||||||
|
|
||||||
|
ebnf_fence_start = re.compile(r"^\s*///\s*```\s*ebnf\s*$")
|
||||||
|
ebnf_fence_end = re.compile(r"^\s*///\s*```\s*$")
|
||||||
|
doc_comment_prefix = re.compile(r"^\s*///\s?(.*)$")
|
||||||
|
|
||||||
|
rule_start_pattern = re.compile(r"^\s*([A-Za-z_]\w*)\s*:")
|
||||||
|
rule_ref_pattern = re.compile(r"\b([A-Za-z_]\w*)\b")
|
||||||
|
|
||||||
|
|
||||||
|
def find_project_root() -> Path | None:
|
||||||
|
current = Path.cwd()
|
||||||
|
while current != current.parent:
|
||||||
|
cargo_toml = current / "Cargo.toml"
|
||||||
|
if cargo_toml.exists():
|
||||||
|
text = cargo_toml.read_text(encoding="utf-8")
|
||||||
|
if re.search(r'(?m)^\s*name\s*=\s*"shulkerscript"\s*$', text):
|
||||||
|
return current
|
||||||
|
current = current.parent
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
root_dir = find_project_root()
|
||||||
|
if not root_dir:
|
||||||
|
raise SystemExit(
|
||||||
|
"Could not find Cargo.toml of package 'shulkerscript' in this or any parent directory."
|
||||||
|
)
|
||||||
|
|
||||||
|
if Path.cwd() != root_dir:
|
||||||
|
os.chdir(root_dir)
|
||||||
|
print(f"Changed working directory to {root_dir}")
|
||||||
|
|
||||||
|
previous_rules = set()
|
||||||
|
|
||||||
|
with open("grammar.md", "r", encoding="utf-8") as f:
|
||||||
|
rule_header_pattern = re.compile(r"## (\w+)")
|
||||||
|
for line in f:
|
||||||
|
m = rule_header_pattern.match(line)
|
||||||
|
if m:
|
||||||
|
previous_rules.add(m.group(1))
|
||||||
|
|
||||||
|
for path in Path(".").rglob("*.rs"):
|
||||||
|
with path.open(encoding="utf-8") as f:
|
||||||
|
in_block = False
|
||||||
|
current_block_lines = []
|
||||||
|
|
||||||
|
for line in f:
|
||||||
|
if not in_block and ebnf_fence_start.match(line):
|
||||||
|
in_block = True
|
||||||
|
current_block_lines = []
|
||||||
|
continue
|
||||||
|
if in_block:
|
||||||
|
if ebnf_fence_end.match(line):
|
||||||
|
block_text = "\n".join(current_block_lines)
|
||||||
|
|
||||||
|
ebnf_blocks.append(block_text)
|
||||||
|
|
||||||
|
current_rule_name = None
|
||||||
|
current_rule_lines = []
|
||||||
|
for ln in current_block_lines:
|
||||||
|
m = rule_start_pattern.match(ln)
|
||||||
|
if m:
|
||||||
|
if current_rule_name:
|
||||||
|
full_def = "\n".join(current_rule_lines)
|
||||||
|
rule_defs[current_rule_name] = full_def
|
||||||
|
refs = set(rule_ref_pattern.findall(full_def))
|
||||||
|
refs.discard(current_rule_name)
|
||||||
|
rule_deps[current_rule_name].update(refs)
|
||||||
|
current_rule_name = m.group(1)
|
||||||
|
current_rule_lines = [ln]
|
||||||
|
else:
|
||||||
|
if current_rule_name:
|
||||||
|
current_rule_lines.append(ln)
|
||||||
|
|
||||||
|
if current_rule_name:
|
||||||
|
full_def = "\n".join(current_rule_lines)
|
||||||
|
|
||||||
|
rule_defs[current_rule_name] = full_def
|
||||||
|
refs = set(rule_ref_pattern.findall(full_def))
|
||||||
|
refs.discard(current_rule_name)
|
||||||
|
rule_deps[current_rule_name].update(refs)
|
||||||
|
|
||||||
|
in_block = False
|
||||||
|
continue
|
||||||
|
|
||||||
|
m = doc_comment_prefix.match(line)
|
||||||
|
if m:
|
||||||
|
current_block_lines.append(m.group(1))
|
||||||
|
|
||||||
|
if "Program" not in rule_defs:
|
||||||
|
raise SystemExit("Root rule 'Program' not found in EBNF definitions")
|
||||||
|
|
||||||
|
visited = set()
|
||||||
|
order = []
|
||||||
|
queue = deque(["Program"])
|
||||||
|
|
||||||
|
while queue:
|
||||||
|
rule = queue.popleft()
|
||||||
|
if rule not in visited and rule in rule_defs:
|
||||||
|
visited.add(rule)
|
||||||
|
order.append(rule)
|
||||||
|
for dep in sorted(rule_deps[rule]):
|
||||||
|
if dep not in visited:
|
||||||
|
queue.append(dep)
|
||||||
|
|
||||||
|
unused_rules = sorted(set(rule_defs.keys()) - visited)
|
||||||
|
|
||||||
|
if len(unused_rules) > 0:
|
||||||
|
print(
|
||||||
|
f"Appending {len(unused_rules)} unused rules to the end: {', '.join(unused_rules)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
order.extend(unused_rules)
|
||||||
|
|
||||||
|
with open("grammar.md", "w", encoding="utf-8") as out:
|
||||||
|
out.write("# Grammar of the Shulkerscript language\n\n")
|
||||||
|
|
||||||
|
for rule in order:
|
||||||
|
out.write(f"## {rule}\n\n```ebnf\n{rule_defs[rule]}\n```\n\n")
|
||||||
|
|
||||||
|
print(f"Wrote grammar.md with {len(order)} rules.")
|
||||||
|
added_rules = set(rule_defs.keys()) - previous_rules
|
||||||
|
if len(added_rules) > 0:
|
||||||
|
print(f"Added rules for: {', '.join(added_rules)}")
|
||||||
|
removed_rules = previous_rules - set(rule_defs.keys())
|
||||||
|
if len(removed_rules) > 0:
|
||||||
|
print(f"Removed rules for: {', '.join(removed_rules)}")
|
|
@ -310,6 +310,11 @@ impl Debug for Boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a hardcoded string literal value in the source code.
|
/// Represents a hardcoded string literal value in the source code.
|
||||||
|
///
|
||||||
|
/// ```ebnf
|
||||||
|
/// StringLiteral:
|
||||||
|
/// '"' TEXT '"';
|
||||||
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct StringLiteral {
|
pub struct StringLiteral {
|
||||||
|
@ -344,6 +349,11 @@ impl SourceElement for StringLiteral {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a hardcoded macro string literal value in the source code.
|
/// Represents a hardcoded macro string literal value in the source code.
|
||||||
|
///
|
||||||
|
/// ```ebnf
|
||||||
|
/// MacroStringLiteral:
|
||||||
|
/// '`' ( TEXT | '$(' [a-zA-Z0-9_]+ ')' )* '`';
|
||||||
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct MacroStringLiteral {
|
pub struct MacroStringLiteral {
|
||||||
|
|
|
@ -36,7 +36,7 @@ use super::{
|
||||||
/// Declaration:
|
/// Declaration:
|
||||||
/// Function
|
/// Function
|
||||||
/// | Import
|
/// | Import
|
||||||
/// | Tag
|
/// | TagDeclaration
|
||||||
/// | ('pub'? VariableDeclaration ';')
|
/// | ('pub'? VariableDeclaration ';')
|
||||||
/// ;
|
/// ;
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -99,10 +99,10 @@ impl Declaration {
|
||||||
///
|
///
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// Function:
|
/// Function:
|
||||||
/// Annotation* 'pub'? 'fn' Identifier '(' ParameterList? ')' Block
|
/// Annotation* 'pub'? 'fn' Identifier '(' FunctionParameterList? ')' Block
|
||||||
/// ;
|
/// ;
|
||||||
///
|
///
|
||||||
/// ParameterList:
|
/// FunctionParameterList:
|
||||||
/// FunctionArgument (',' FunctionArgument)* ','?
|
/// FunctionArgument (',' FunctionArgument)* ','?
|
||||||
/// ;
|
/// ;
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -143,7 +143,7 @@ impl SourceElement for Binary {
|
||||||
///
|
///
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// Expression:
|
/// Expression:
|
||||||
/// Primary | Binary
|
/// Primary | Binary ;
|
||||||
/// ```
|
/// ```
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
@ -171,6 +171,7 @@ impl SourceElement for Expression {
|
||||||
/// Identifier
|
/// Identifier
|
||||||
/// | Prefix
|
/// | Prefix
|
||||||
/// | Parenthesized
|
/// | Parenthesized
|
||||||
|
/// | Indexed
|
||||||
/// | Integer
|
/// | Integer
|
||||||
/// | Boolean
|
/// | Boolean
|
||||||
/// | StringLiteral
|
/// | StringLiteral
|
||||||
|
@ -307,7 +308,7 @@ impl SourceElement for Indexed {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// PrefixOperator:
|
/// PrefixOperator:
|
||||||
/// '!' | '-'
|
/// '!' | '-' | 'run'
|
||||||
/// ;
|
/// ;
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
|
|
@ -20,6 +20,13 @@ use crate::{
|
||||||
use super::declaration::Declaration;
|
use super::declaration::Declaration;
|
||||||
|
|
||||||
/// Program is a collection of declarations preceeded by a namespace selector.
|
/// Program is a collection of declarations preceeded by a namespace selector.
|
||||||
|
///
|
||||||
|
/// ```ebnf
|
||||||
|
/// Program:
|
||||||
|
/// Namespace
|
||||||
|
/// Declaration*
|
||||||
|
/// ;
|
||||||
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
pub struct ProgramFile {
|
pub struct ProgramFile {
|
||||||
|
|
|
@ -42,6 +42,7 @@ use super::{expression::Expression, Annotation, AnyStringLiteral};
|
||||||
/// | Conditional
|
/// | Conditional
|
||||||
/// | Grouping
|
/// | Grouping
|
||||||
/// | DocComment
|
/// | DocComment
|
||||||
|
/// | ExecuteBlock
|
||||||
/// | Semicolon
|
/// | Semicolon
|
||||||
/// ;
|
/// ;
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -175,7 +176,7 @@ impl SourceElement for Block {
|
||||||
/// Grouping:
|
/// Grouping:
|
||||||
/// 'group' Block
|
/// 'group' Block
|
||||||
/// ;
|
/// ;
|
||||||
/// ````
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
pub struct Grouping {
|
pub struct Grouping {
|
||||||
|
@ -245,7 +246,7 @@ impl Semicolon {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// SemicolonStatement:
|
/// SemicolonStatement:
|
||||||
/// (Expression | VariableDeclaration | Assignment)
|
/// (Expression | VariableDeclaration | Assignment | ReturnStatement)
|
||||||
/// ';'
|
/// ';'
|
||||||
/// ;
|
/// ;
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -318,6 +319,7 @@ impl ReturnStatement {
|
||||||
/// | ArrayVariableDeclaration
|
/// | ArrayVariableDeclaration
|
||||||
/// | ScoreVariableDeclaration
|
/// | ScoreVariableDeclaration
|
||||||
/// | TagVariableDeclaration
|
/// | TagVariableDeclaration
|
||||||
|
/// | ComptimeValueDeclaration
|
||||||
/// ;
|
/// ;
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
|
|
|
@ -73,6 +73,7 @@ impl SourceElement for ExecuteBlock {
|
||||||
/// | Store
|
/// | Store
|
||||||
/// | Summon
|
/// | Summon
|
||||||
/// ;
|
/// ;
|
||||||
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, EnumAsInner, From)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, EnumAsInner, From)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
@ -120,6 +121,7 @@ impl SourceElement for ExecuteBlockHead {
|
||||||
/// ExecuteBlock
|
/// ExecuteBlock
|
||||||
/// | Block
|
/// | Block
|
||||||
/// ;
|
/// ;
|
||||||
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, EnumAsInner, From)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, EnumAsInner, From)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
|
@ -217,8 +219,7 @@ impl SourceElement for Else {
|
||||||
///
|
///
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// As:
|
/// As:
|
||||||
/// 'as' '(' AnyStringLiteral ')'
|
/// 'as' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
@ -263,8 +264,8 @@ impl As {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// Align:
|
/// Align:
|
||||||
/// 'align' '(' AnyStringLiteral ')'
|
/// 'align' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
pub struct Align {
|
pub struct Align {
|
||||||
|
@ -309,8 +310,7 @@ impl Align {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// Anchored:
|
/// Anchored:
|
||||||
/// 'anchored' '(' AnyStringLiteral ')'
|
/// 'anchored' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
@ -354,8 +354,7 @@ impl Anchored {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// AsAt:
|
/// AsAt:
|
||||||
/// 'asat' '(' AnyStringLiteral ')'
|
/// 'asat' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
@ -399,8 +398,7 @@ impl AsAt {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// At:
|
/// At:
|
||||||
/// 'at' '(' AnyStringLiteral ')'
|
/// 'at' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
@ -444,8 +442,7 @@ impl At {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// Facing:
|
/// Facing:
|
||||||
/// 'facing' '(' AnyStringLiteral ')'
|
/// 'facing' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
@ -489,8 +486,7 @@ impl Facing {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// In:
|
/// In:
|
||||||
/// 'in' '(' AnyStringLiteral ')'
|
/// 'in' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
@ -534,8 +530,7 @@ impl In {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// On:
|
/// On:
|
||||||
/// 'on' '(' AnyStringLiteral ')'
|
/// 'on' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
@ -579,8 +574,7 @@ impl On {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// Positioned:
|
/// Positioned:
|
||||||
/// 'positioned' '(' AnyStringLiteral ')'
|
/// 'positioned' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
@ -624,8 +618,7 @@ impl Positioned {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// Rotated:
|
/// Rotated:
|
||||||
/// 'rotated' '(' AnyStringLiteral ')'
|
/// 'rotated' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
@ -669,8 +662,7 @@ impl Rotated {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// Store:
|
/// Store:
|
||||||
/// 'store' '(' AnyStringLiteral ')'
|
/// 'store' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
@ -714,8 +706,7 @@ impl Store {
|
||||||
/// Syntax Synopsis:
|
/// Syntax Synopsis:
|
||||||
/// ```ebnf
|
/// ```ebnf
|
||||||
/// Summon:
|
/// Summon:
|
||||||
/// 'summon' '(' AnyStringLiteral ')'
|
/// 'summon' '(' AnyStringLiteral ')' ;
|
||||||
/// ;
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
|
||||||
|
|
Loading…
Reference in New Issue