Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closures: Added tests from the current closures PR #1393

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions tests/compiler/closure-common-js-patterns.json
@@ -0,0 +1,10 @@
{
"asc_flags": [
"--runtime full",
"--use ASC_RTRACE=1"
],
"stderr": [
"AS100: Not implemented: Closures",
"AS100: Not implemented: Closures"
]
}
183 changes: 183 additions & 0 deletions tests/compiler/closure-common-js-patterns.ts
@@ -0,0 +1,183 @@
// NOTE torch2424 6/15/20: This test has a lot of errors skipped. Closures is currently a WIP

// Common use cases / concepts for closures, as covered in articles like:
// https://medium.com/@dis_is_patrick/practical-uses-for-closures-c65640ae7304
// https://stackoverflow.com/questions/2728278/what-is-a-practical-use-for-a-closure-in-javascript
// https://softwareengineering.stackexchange.com/questions/285941/why-would-a-program-use-a-closure
// https://medium.com/@prashantramnyc/what-is-an-iife-in-javascript-24baf0febf08

// Currently, IIFEs and simple Function Factories work
// But my advanced Function Factory Pub Sub, and weird function namespacing does not
// Due to runtime and/or compilation errors :)

// IIFE (Immediately Invoked function expressions)
// Used for encapsulating data usually

// Simple IIFE
let myData = ((): boolean => {
return true;
})();

assert(myData == true);

// Constructor IIFE?
// Don't know why someone wouldn't just use their class, but yeah

class IIFEReturn {
myBool: boolean
myFunc: (x: i32) => i32
}

let myInstanceThing = ((): IIFEReturn => {
return {
myBool: true,
myFunc: (x: i32) => {
return x + 1;
}
};
})();

assert(myInstanceThing.myBool == true);
assert(myInstanceThing.myFunc(24) == 25);

// Function Factories
// Closures that create specific functions

// Simple function that will change depending on input
type generatedFunc = () => i32;
let myFactory = (x: i32): generatedFunc => {
let myFunc = (): i32 => {
return 24 + x;
};

return myFunc;
};

let generatedPlusOne: generatedFunc = myFactory(1);
let generatedPlusTwo: generatedFunc = myFactory(2);

// For some reason, couldn't do
// Cannot invoke an expression whose type lacks a call signature. Type 'closure-common-js-patterns/myFactory' has no compatible call signatures.
// assert(myFactory(1)() == 25);
assert(generatedPlusOne() == 25);
assert(generatedPlusTwo() == 26);

// I often will use this for like Pub/Sub stuff

type SubFunc = () => void;
type UnSubFunc = () => void;
let subscriptions = new Array<SubFunc>();
let globalSubVar: i32 = 0;

function subscribe(funcToCallOnPub: SubFunc): UnSubFunc {
subscriptions.push(funcToCallOnPub);
return (): void => {
let funcIndex = subscriptions.indexOf(funcToCallOnPub);
subscriptions.splice(funcIndex, 1);
};
}

function publish(): void {
for(let i = 0; i < subscriptions.length; i++) {
// Can't call directly? Get a Type error
// ERROR TS2757: Type '() => void' has no call signatures.
// Noticed some other weird type errors if I don't declare the function type
// But I also am meh at typescripte signatures haha!
// subscriptions[i]();

let subFunc = subscriptions[i];
subFunc();
}
}

let plusOne = (): void => {
globalSubVar += 1;
};

let plusTwo = (): void => {
globalSubVar += 1;
};


let unsubPlusOne: () => void = subscribe(plusOne);
let unsubPlusTwo: () => void = subscribe(plusTwo);

assert(globalSubVar == 0);
assert(subscriptions.length == 2);

publish();

assert(globalSubVar == 3);
assert(subscriptions.length == 2);

unsubPlusOne();

assert(globalSubVar == 3);
assert(subscriptions.length == 1);

publish();

assert(globalSubVar == 5);
assert(subscriptions.length == 1);

unsubPlusTwo();

assert(globalSubVar == 5);
assert(subscriptions.length == 0);

publish();

assert(globalSubVar == 5);
assert(subscriptions.length == 0);


// TODO (torch2424 6/15/20): Uncomment this test once closures is fully implemented
/*

// Namespacing private functions
// Again, kind of weird, they should probably just make a class, but it's another interesting test

class Chunk {
totalSize: i32;
usedSize: i32;
write: (size: i32) => void;
}

let getChunk = (): Chunk => {
let chunk: Chunk = {
totalSize: 1024,
usedSize: 0,
write: (x: i32): void => {}
};

let growChunk = (): void => {
chunk.totalSize += 1024;
}

let allocateForChunk = (amount: i32): void => {
if (chunk.usedSize + amount <= chunk.totalSize) {
chunk.usedSize += amount;
} else {
// growChunk(chunk);
// allocateForChunk(chunk, amount);
}
}

chunk.write = (x: i32) => {
allocateForChunk(x);
}

return chunk;

}

let myChunk: Chunk = getChunk();

assert(myChunk.totalSize == 1024);
assert(myChunk.usedSize == 0);

myChunk.write(1025);

assert(myChunk.totalSize == 2048);
assert(myChunk.usedSize == 1025);
*/
Empty file.
9 changes: 9 additions & 0 deletions tests/compiler/closure-limitations-runtime.json
@@ -0,0 +1,9 @@
{
"asc_flags": [
"--runtime full"
],
"stderr": [
"AS100: Not implemented: Closures"
],
"skipInstantiate": true
}
7 changes: 7 additions & 0 deletions tests/compiler/closure-limitations-runtime.ts
@@ -0,0 +1,7 @@
export function exportedClosureReturns(): (value: i32) => i32 {
var $local0 = 0;
return function inner(value: i32): i32 {
return $local0;
};
}
exportedClosureReturns();
Empty file.
11 changes: 11 additions & 0 deletions tests/compiler/closure-limitations.json
@@ -0,0 +1,11 @@
{
"asc_flags": [
"--runtime none"
],
"stderr": [
"AS100: Not implemented: Closures",
"AS100: Not implemented: Closures",
"AS100: Not implemented: Closures",
"EOF"
]
}
22 changes: 22 additions & 0 deletions tests/compiler/closure-limitations.ts
@@ -0,0 +1,22 @@
function closureWrites(): (value: i32) => i32 {
var $local0 = 0;
return function inner(value: i32) {
$local0 = $local0 + 1;
return $local0;
};
}
closureWrites();

function inScopeNestedCalls(): (value: i32) => i32 {
var x = 0;
var f = (): i32 => {
return x;
};
var p = (value: i32): i32 => {
return f();
};
return p;
}
inScopeNestedCalls();

ERROR("EOF");
12 changes: 8 additions & 4 deletions tests/compiler/closure.json
@@ -1,11 +1,15 @@
{
"asc_flags": [
"--runtime none"
"--runtime full",
"--use ASC_RTRACE=1"
],
"stderr": [
"AS100: Not implemented: Closures",
"AS100: Not implemented: Closures",
"Cannot find name '$local0'.",
"EOF"
"TS2304: Cannot find name '$local0'.",
"AS100: Not implemented: Closures",
"AS100: Not implemented: Closures",
"AS100: Not implemented: Closures",
"AS100: Not implemented: Closures"
]
}
}
65 changes: 63 additions & 2 deletions tests/compiler/closure.ts
@@ -1,3 +1,5 @@
// NOTE torch2424 6/15/20: This test has a lot of errors skipped. Closures is currently a WIP

function testParam($local0: i32, $local1: i32): (value: i32) => i32 {
return function inner(value: i32) {
return $local1; // closure
Expand All @@ -16,9 +18,68 @@ testVar();
function testLet(): (value: i32) => i32 {
let $local0 = 0;
return function inner(value: i32) {
return $local0; // closure
return $local0;
};
}
testLet();

ERROR("EOF");
function passItAround(arg: i32): usize {
return runClosure(createClosure(arg));
}
passItAround(1);

function runInline(arg: i32, foo: i32, bar: i32): i32 {
return ((): i32 => { return arg + foo + bar; } )();
}
runInline(1,1,1);

function fallOutOfScope(arg: i32): i32 {
var releaseMe = createClosure(arg);
return 10;
}
fallOutOfScope(1);

function createClosure(arg: i32): (x3: i32) => i32 {
var closure = (x3: i32): i32 => { return arg + x3; };
return closure;
}

function complexCreateClosure(arg: i32): (x3: i32) => i32 {
var foo = 2;
var bar = 3;
var baz = 4;
var f = (x1: i32): i32 => { return foo + bar - baz; };
var g = (x2: i32): i32 => { return (bar - baz) + foo; };
foo = 7;
bar = 11;
return g;
}

function runClosure(closureToRun: (x3: i32) => i32): i32 {
return closureToRun(1);
}

// Ensure that non-closures do not abort upon returning
export function returnOverBoundary(): () => i32 {
return function(): i32 { return 6; };
}
returnOverBoundary();

// KNOWN BUGS (torch2424: 6/15/20 - As of the original Closures PR)

// Causes a memory leak, copyFunction is properly released
const func = (i: i32): i32 => i;
let copyFunction: (i: i32) => i32 = func;

// Also causes a memory leak
function nestedExecutionTest(arg: i32): i32 {
var x = 7;
var f = complexCreateClosure(arg);
var g = (fn: (x3: i32) => i32): i32 => {
var first = fn(arg);
return x;
};
return g(f);
}
nestedExecutionTest(1);

Empty file.