Skip to content

Instantly share code, notes, and snippets.

@shesek
Created December 7, 2011 21:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shesek/1444629 to your computer and use it in GitHub Desktop.
Save shesek/1444629 to your computer and use it in GitHub Desktop.
CS stuff
_ = require 'underscore'
{Assign, Value, Literal, Access, Block, Class, Op, Obj, Arr, For, Index, Call, Return, If, Throw} = nodes = require '../nodes'
exports.originals = originals = {}
exports.codeblock = codeblock = (block) ->
return block unless block?
if typeof block is 'function'
block = new Literal (str = block.toString()).substring str.indexOf('{')+1, str.length - 1
else if _.isString block
new Literal block
else if _.isObject block and (Object.getPrototypeOf block) is Object.prototype
# Plain object
new Literal JSON.stringify block
else if typeof block is 'object'
block
else
console.log 'cannot convert', block
throw new Error 'Cannot convert to a codeblock'
LL = do ->
cache = {}
(str) -> cache[str] ||= new Literal str
invoke = (fn, args) ->
if 0 < _.size fn.prototype
ret = fn.apply (obj=Object.create fn.prototype), args
if _.isObject ret then ret else obj
else
fn args...
exports.wrap = wrap = (node, callback) ->
orig = nodes[node]
originals[node] ||= orig
nodes[node] = ->
return ret if (ret = invoke callback, arguments)?
invoke orig, arguments
exports.wrapif = wrapif = (node, tester, fn) -> wrap node, ->
fn arguments... if tester arguments...
exports.addfunc = addfunc = (name, fn) ->
wrapif 'Call',
(variable) -> variable instanceof Value and variable.base instanceof Literal and variable.base.value is name
(variable, args) -> codeblock fn args...
addfunc '$$', (expr) -> eval expr.compile()
push_statement = (statement) -> (func) -> func.body.push statement; func
# Used like so: `foo = void (a,b) -> c`
addfunc '$void', push_statement new Return
## Unrelated to `void`, but nice additions too
# `foo = chain (a, b) -> c` - Adds an `return this` to the end of function
addfunc '$chain', push_statement LL 'this'
# When the first argument passed to a function can be an error (common in nodejs environment), the following
# is quite common: `fs.readFile path, (err, data) -> throw err if err; ...`. This can be written as
# `fs.readFile path, throwif (data) ->` instead, which is compiled into the same thing
addfunc '$throwif', do ->
_err = new Value LL 'err'
_throw = new If _err, new Throw _err
(func) ->
func.params.unshift _err
func.body.unshift _throw
func
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment