Skip to content

Instantly share code, notes, and snippets.

@timyates
Created February 14, 2012 16:08
Show Gist options
  • Select an option

  • Save timyates/1827794 to your computer and use it in GitHub Desktop.

Select an option

Save timyates/1827794 to your computer and use it in GitHub Desktop.
Closure Composition to run a stream of tokens
// This will tag our closures so that we know to just push them on the Stack
def fnMethod = { c ->
c.getMetaClass().isFn = { -> true }
c
}
// Define our operations
def ops = [
fn_add: fnMethod( { a, b, Object... remaining -> [ a + b, *remaining ] } ),
fn_sub: fnMethod( { a, b, Object... remaining -> [ a - b, *remaining ] } ),
fn_div: fnMethod( { a, b, Object... remaining -> [ a / b, *remaining ] } ),
fn_mul: fnMethod( { a, b, Object... remaining -> [ a * b, *remaining ] } ),
fn_dup: fnMethod( { a, Object... remaining -> [ a, a, *remaining ] } ),
]
// Written as a category method on List
class StackRunnerCategory {
public static Closure compile( List program ) {
List stack = program.collect { instr ->
// if this is an op, return as-is, otherwise wrap in a closure which adds
// itself into the program state
if( instr.respondsTo( 'isFn' ) ) {
instr
}
else {
{ Object... remaining -> [ *remaining, instr ].flatten() }
}
}
// Then, compose all these closures into one...
stack.drop( 1 ).inject( stack.head() ) { a, b -> b << a }
}
}
// take 1, duplicate it ([1,1])
// add these together ([2])
// add 4 to the stack ([2,4])
// Then multiply ([8])
def prg = [ 1, ops.fn_dup, ops.fn_add, 4, ops.fn_mul ]
use( StackRunnerCategory ) {
// Convert our program to a single closure
def code = prg.compile()
// Then, print out the result of calling it
println code()
}
def prg = [ 1, 4, ops.fn_dup, ops.fn_add, ops.fn_mul ]
@timyates

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment