Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
64271b3
initial commit of wasm-compiler
jonasongg Sep 18, 2025
b4900eb
change type tags to be compile-time construct
jonasongg Sep 18, 2025
be48e79
consolidate arithOp functions, add compareOp functions
jonasongg Sep 18, 2025
00447e7
add string compare function
jonasongg Sep 18, 2025
c55d98d
change expr switch case to if else
jonasongg Sep 20, 2025
6c3aa1b
implement basic assignment
jonasongg Sep 23, 2025
9d2d23b
add support for function declarations
Sep 24, 2025
292ef81
change arithmetic and comparison tags to objects
Sep 24, 2025
0694c5c
WIP: begin implementing functions
Sep 24, 2025
c3347b1
begin implementing functions
Sep 24, 2025
5a92e3c
add support for None, prevent implict function return
jonasongg Sep 24, 2025
d33a586
add support for return statements
jonasongg Sep 24, 2025
d3666d8
add support for function parameters, add print built-in function
jonasongg Sep 25, 2025
b5fdbe3
add support for local variables
Sep 26, 2025
561a23b
initial attempt at closures
Oct 3, 2025
8490358
WIP: heap allocated variables + lexical addressing
jonasongg Oct 7, 2025
d8fe699
heap allocated variables + lexical addressing
Oct 8, 2025
43b895c
add check for unbound variables
Oct 8, 2025
ff9581c
WIP: nonlocal statement, wasm types
jonasongg Oct 13, 2025
4874c68
WIP wasm types
Oct 14, 2025
430f1bf
fix environment bug
jonasongg Oct 16, 2025
459cf1b
wasm types fluent for numerics
jonasongg Oct 16, 2025
8a1eb23
WIP wasm block types fluent
Oct 17, 2025
942edb6
add error messages
Oct 22, 2025
7a8e5f8
add nonlocal statement
Oct 22, 2025
7f35144
add pairs
Oct 22, 2025
4377cbb
implicit return + WIP builder generators
jonasongg Oct 23, 2025
414ab02
Merge remote-tracking branch 'refs/remotes/origin/wasm-compiler' into…
Oct 24, 2025
a3f1cbd
add builder, wat generator
Oct 24, 2025
4e997cb
change blockType helper
Oct 24, 2025
ab337f9
remove unused files
jonasongg Oct 24, 2025
3509e21
Merge remote-tracking branch 'refs/remotes/origin/wasm-compiler' into…
jonasongg Oct 24, 2025
d1919b5
add type to import
jonasongg Oct 30, 2025
58e3ac2
add set_head, set_tail, fix build-in fx return env bug
jonasongg Oct 30, 2025
3f03332
fix another environment bug
jonasongg Nov 5, 2025
71b1253
Merge branch 'main' into wasm-compiler
jonasongg Nov 6, 2025
a9c55e9
begin integration with conductor
jonasongg Nov 6, 2025
760b339
rename instr to op
jonasongg Nov 6, 2025
21cb217
add constraint for wasm labels
jonasongg Nov 6, 2025
4c1f569
add select to typed-builder
jonasongg Nov 6, 2025
1407052
add load narrow
jonasongg Nov 6, 2025
d84b333
move wasm-util to its own package
jonasongg Nov 8, 2025
ec72626
change to only use one apply function
jonasongg Nov 8, 2025
7c5dc0d
add native functions up to preapply
jonasongg Nov 8, 2025
2c90419
use builder as type instead of strings, change blocktype
Nov 11, 2025
ccb5b97
add apply func to builder
jonasongg Nov 11, 2025
8a7706e
Merge remote-tracking branch 'refs/remotes/origin/wasm-compiler' into…
jonasongg Nov 11, 2025
669ed70
finish builder constants
jonasongg Nov 11, 2025
768d905
keep one variable for native functions
jonasongg Nov 11, 2025
94a6898
native functions naming consistency
jonasongg Nov 12, 2025
101a865
WIP: builder generator
jonasongg Nov 12, 2025
c8b173a
finish builder generator
Nov 12, 2025
48358e7
fix native function bugs
Nov 12, 2025
fe0760e
change comparison and arith functions to use buildBrTableBlocks
jonasongg Nov 13, 2025
943bca5
clarify visitCallExpr
jonasongg Nov 13, 2025
124800f
fix builderGenerator imports
Nov 19, 2025
e2656fc
change allocEnv to use memory.fill
Nov 19, 2025
ec27f74
remove baseGenerator
Nov 19, 2025
d4dc862
add tests, remove ratWatGenerator
jonasongg Nov 19, 2025
a2bd637
add back wasm-util
jonasongg Nov 19, 2025
e751027
fix npm wasm script
jonasongg Nov 19, 2025
1d50498
remove unused code
jonasongg Nov 19, 2025
cb521ec
Merge remote-tracking branch 'upstream/main' into wasm-compiler
jonasongg Nov 20, 2025
b30f072
fix apply environment bug
Nov 20, 2025
67006ae
fix misc bugs
jonasongg Nov 20, 2025
1acc9ee
add WasmRaw, generate block type, support labels as numbers
jonasongg Nov 20, 2025
ac3869b
fix bug from using one apply function
jonasongg Nov 20, 2025
0cc98ee
make WasmRaw subtype of WasmInstruction subtypes
Nov 21, 2025
a13224e
add comments to constants
Nov 21, 2025
13d090d
make bool 0 or 1
Nov 24, 2025
70f6ff4
add bool operator support, fix WasmIntTest type
Nov 24, 2025
015a3b0
add ternary expression
Nov 25, 2025
7c8b3df
add if statement
Nov 25, 2025
d52f956
add lambda expressions
Nov 26, 2025
5a4aaee
add pass statement
Nov 27, 2025
91d9928
fix type for wabt
Nov 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"build": "rollup -c --bundleConfigAsCjs",
"start": "npm run build && node dist/index.js",
"jsdoc": "./scripts/jsdoc.sh",
"test": "jest"
"test": "jest",
"wasm": "ts-node src/wasm-compiler/index.ts"
},
"keywords": [
"Python",
Expand Down Expand Up @@ -49,6 +50,7 @@
"@sourceacademy/conductor": "^0.2.3",
"@types/estree": "^1.0.0",
"fast-levenshtein": "^3.0.0",
"mathjs": "^14.4.0"
"mathjs": "^14.4.0",
"wabt": "^1.0.37"
}
}
23 changes: 23 additions & 0 deletions src/conductor/PyWasmEvaluator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// This file is adapted from:
// https://github.com/source-academy/conductor
// Original author(s): Source Academy Team

import { BasicEvaluator, IRunnerPlugin } from "@sourceacademy/conductor/runner";
import { compileToWasmAndRun } from "../wasm-compiler/compile";

export default class PyEvaluator extends BasicEvaluator {
constructor(conductor: IRunnerPlugin) {
super(conductor);
}

async evaluateChunk(chunk: string): Promise<void> {
try {
const result = await compileToWasmAndRun(chunk);
this.conductor.sendOutput(result);
} catch (error) {
this.conductor.sendOutput(
`Error: ${error instanceof Error ? error.message : error}`
);
}
}
}
153 changes: 153 additions & 0 deletions src/tests/wasm-compiler.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { compileToWasmAndRun } from "../wasm-compiler";

describe("Environment tests", () => {
it("captures outer variable by reference (mutation after definition visible)", async () => {
const pythonCode = `
def outer():
x = 1
def inner():
return x
x = 2
return inner()
outer()
`;
const result = await compileToWasmAndRun(pythonCode);
expect(result).toEqual([0, BigInt(2)]);
});

it("inner variable shadows outer variable", async () => {
const pythonCode = `
def outer():
x = 5
def inner():
x = 7
return x
return inner()
outer()
`;
const result = await compileToWasmAndRun(pythonCode);
expect(result).toEqual([0, BigInt(7)]);
});

it("inner function reads variable from outer scope", async () => {
const pythonCode = `
def outer():
x = 5
def inner():
return x
return inner()
outer()
`;
const result = await compileToWasmAndRun(pythonCode);
expect(result).toEqual([0, BigInt(5)]);
});

it("reassignment in outer scope after defining inner is visible to inner", async () => {
const pythonCode = `
def outer():
x = 1
def inner():
return x
x = 9
return inner()
outer()
`;
const result = await compileToWasmAndRun(pythonCode);
expect(result).toEqual([0, BigInt(9)]);
});

it("nested closure can access variable from grandparent scope", async () => {
const pythonCode = `
def grandparent():
a = 10
def parent():
b = 5
def child():
return a + b
return child
return parent

f = grandparent()
g = f()
g()
`;
const result = await compileToWasmAndRun(pythonCode);
expect(result).toEqual([0, BigInt(15)]);
});

it("each call to outer creates a new environment", async () => {
const pythonCode = `
def make_number(n):
def get():
return n
return get

a = make_number(3)
b = make_number(10)
a() + b()
`;
const result = await compileToWasmAndRun(pythonCode);
expect(result).toEqual([0, BigInt(13)]);
});

it("function returned from outer retains access to outer variable", async () => {
const pythonCode = `
def outer():
x = 7
def inner():
return x
return inner

f = outer()
f()
`;
const result = await compileToWasmAndRun(pythonCode);
expect(result).toEqual([0, BigInt(7)]);
});

it("returned function reflects reassignment in outer before return", async () => {
const pythonCode = `
def outer():
x = 3
def inner():
return x
x = 8
return inner

f = outer()
f()
`;
const result = await compileToWasmAndRun(pythonCode);
expect(result).toEqual([0, BigInt(8)]);
});

it("different closures capture independent variables", async () => {
const pythonCode = `
def make_adder(n):
def add(x):
return n + x
return add

add1 = make_adder(1)
add2 = make_adder(5)
add1(3) + add2(3)
`;
const result = await compileToWasmAndRun(pythonCode);
expect(result).toEqual([0, BigInt(12)]);
});

it("reusing same closure multiple times uses same environment", async () => {
const pythonCode = `
def outer():
x = 4
def inner():
return x
return inner

f = outer()
f() + f()
`;
const result = await compileToWasmAndRun(pythonCode);
expect(result).toEqual([0, BigInt(8)]);
});
});
11 changes: 11 additions & 0 deletions src/wasm-compiler/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"printWidth": 80,
"overrides": [
{
"files": "constants.ts",
"options": {
"printWidth": 120
}
}
]
}
Loading