Skip to content

Commit

Permalink
Added / Skipped Closure tests (#16)
Browse files Browse the repository at this point in the history
* Skipped / Added Closure tests

* Removed the accidental file I made in vim haha!
  • Loading branch information
torch2424 committed Aug 13, 2020
1 parent 666d0ca commit acd7952
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 6 deletions.
10 changes: 10 additions & 0 deletions tests/compiler/closure-common-js-patterns.json
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit acd7952

Please sign in to comment.