Skip to content

Commit ed27f86

Browse files
committed
✨ feat: fuse decompiler
Signed-off-by: FurryR <awathefox@gmail.com>
1 parent c955d77 commit ed27f86

4 files changed

Lines changed: 41 additions & 10 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ jobs:
7878
"scratch-fuse/serializer"
7979
"scratch-fuse/builtins"
8080
)
81-
81+
8282
for repo in "${REPOS[@]}"; do
8383
echo "Triggering workflow for $repo..."
8484
curl -L \

specification.md

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,15 @@ Letter = UnicodeLetterCategory ;
5656
### Keywords
5757

5858
```ebnf
59-
Keyword = "fn" | "let" | "global" | "if" | "else" | "while" | "for" | "loop"
59+
Keyword = "fn" | "let" | "global" | "if" | "else" | "while" | "for" | "loop"
6060
| "return" | "true" | "false" | "once" | "namespace" ;
6161
```
6262

6363
### Operators
6464

6565
```ebnf
66-
Operator = ".." | "+" | "-" | "*" | "/" | "%"
67-
| "=" | "==" | "!=" | "<" | ">" | "<=" | ">="
66+
Operator = ".." | "+" | "-" | "*" | "/" | "%"
67+
| "=" | "==" | "!=" | "<" | ">" | "<=" | ">="
6868
| "&&" | "||" | "!" | "."
6969
| "->" | "+=" | "-=" | "*=" | "/=" | "%=" | "..="
7070
| "++" | "--" ;
@@ -164,6 +164,7 @@ HatBlock = Expression BlockStatement ;
164164
```
165165

166166
Examples:
167+
167168
```fuse
168169
event.start { /* statements */ }
169170
event.keyPressed("space") { /* statements */ }
@@ -273,8 +274,8 @@ FactorExpression = UnaryExpression ( ("*" | "/" | "%") UnaryExpression )* ;
273274
274275
UnaryExpression = ( ("+" | "-" | "!") UnaryExpression ) | CallExpression ;
275276
276-
CallExpression = PrimaryExpression ( "(" ArgumentList? ")" [ BlockStatement ]
277-
| "[" Expression "]"
277+
CallExpression = PrimaryExpression ( "(" ArgumentList? ")" [ BlockStatement ]
278+
| "[" Expression "]"
278279
| "." Identifier )* ;
279280
280281
PrimaryExpression = Literal
@@ -321,6 +322,7 @@ The FUSE program structure allows only the following at the top level:
321322
### Type System
322323

323324
FUSE uses a simple type system:
325+
324326
- `void`: No return value
325327
- `any`: Any Scratch value (string, number, boolean)
326328
- `bool`: Boolean values (`true` or `false`)
@@ -342,16 +344,19 @@ The `@export` decorator is used to export Scratch blocks.
342344
### Operators
343345

344346
#### Arithmetic Operators
347+
345348
- `+`: Addition
346349
- `-`: Subtraction
347350
- `*`: Multiplication
348351
- `/`: Division
349352
- `%`: Modulo
350353

351354
#### String Operators
355+
352356
- `..`: String concatenation
353357

354358
#### Comparison Operators
359+
355360
- `==`: Equal
356361
- `!=`: Not equal
357362
- `<`: Less than
@@ -360,21 +365,25 @@ The `@export` decorator is used to export Scratch blocks.
360365
- `>=`: Greater than or equal
361366

362367
#### Logical Operators
368+
363369
- `&&`: Logical AND
364370
- `||`: Logical OR
365371
- `!`: Logical NOT
366372

367373
#### Assignment Operators
374+
368375
- `=`: Assignment
369376
- `+=`, `-=`, `*=`, `/=`, `%=`, `..=`: Compound assignment
370377

371378
#### Increment/Decrement
379+
372380
- `++`: Increment by 1
373381
- `--`: Decrement by 1
374382

375383
### Control Flow
376384

377385
#### If-Else
386+
378387
```fuse
379388
if (condition) {
380389
// statements
@@ -384,20 +393,23 @@ if (condition) {
384393
```
385394

386395
#### While Loop
396+
387397
```fuse
388398
while (condition) {
389399
// statements
390400
}
391401
```
392402

393403
#### For Loop
404+
394405
```fuse
395406
for (init; condition; update) {
396407
// statements
397408
}
398409
```
399410

400411
#### Infinite Loop
412+
401413
```fuse
402414
loop {
403415
// statements
@@ -407,11 +419,13 @@ loop {
407419
### Function Calls
408420

409421
Functions can be called with arguments:
422+
410423
```fuse
411424
functionName(arg1, arg2, arg3)
412425
```
413426

414427
Some Scratch blocks can have a "then" block:
428+
415429
```fuse
416430
someBlock(args) {
417431
// then statements
@@ -421,6 +435,7 @@ someBlock(args) {
421435
### Member Access
422436

423437
Access namespace members or object properties:
438+
424439
```fuse
425440
namespace.property
426441
object.method(args)
@@ -505,7 +520,7 @@ fn processArray() once -> void {
505520
### exportal Blocks
506521

507522
```fuse
508-
@export("custom block [arg1] and [arg2]")
523+
@export("custom block [arg1] and [arg2]")
509524
fn customBlock(arg1: any, arg2: any) once -> any {
510525
return arg1 + arg2
511526
}
@@ -533,8 +548,8 @@ Target = FunctionDeclaration | VariableDeclaration ;
533548
HatBlock = Expression BlockStatement ;
534549
535550
(* Statements *)
536-
Statement = VariableDeclaration | AssignmentStatement | IncrementStatement
537-
| IfStatement | WhileStatement | ForStatement | LoopStatement
551+
Statement = VariableDeclaration | AssignmentStatement | IncrementStatement
552+
| IfStatement | WhileStatement | ForStatement | LoopStatement
538553
| ReturnStatement | BlockStatement | ExpressionStatement | NoopStatement ;
539554
540555
AssignmentStatement = Expression AssignmentOperator Expression Eol ;

src/lexer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ const operators = new Set([
5050
'>=',
5151
'&&',
5252
'||',
53+
'&',
54+
'|',
5355
'!',
5456
'.',
5557
'->',

src/parser.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,20 @@ export class Parser {
487487
if (this.matchOperator('!', '-', '+')) {
488488
const op = this.previous().value
489489
const operand = this.parseUnary()
490+
if (operand.type === 'Literal' && (op === '+' || op === '-')) {
491+
// Constant folding for unary + and -
492+
if (typeof (operand as LiteralExpression).value === 'number') {
493+
const foldedValue =
494+
op === '-' ? -(operand as LiteralExpression).value : +(operand as LiteralExpression).value
495+
return {
496+
type: 'Literal',
497+
value: foldedValue,
498+
raw: foldedValue.toString(),
499+
line: operand.line,
500+
column: operand.column
501+
} as LiteralExpression
502+
}
503+
}
490504
return {
491505
type: 'UnaryExpression',
492506
operator: op,
@@ -1393,7 +1407,7 @@ export function toSource(node: ASTNode, indent = 2, semi = false): string {
13931407
const args = call.arguments
13941408
.map(arg => toSourceImpl(arg, level))
13951409
.join(`,${sp}`)
1396-
let result = `${callee}(${args})`
1410+
let result = `${callee}${call.arguments.length === 0 && level === 0 ? `` : `(${args})`}`
13971411
if (call.then) {
13981412
result += `${sp}${toSourceImpl(call.then, level)}`
13991413
}

0 commit comments

Comments
 (0)