Skip to content

Commit

Permalink
reorganize daonode folders
Browse files Browse the repository at this point in the history
  • Loading branch information
cxm01 committed Nov 26, 2015
1 parent 86ce7a6 commit 0365be0
Show file tree
Hide file tree
Showing 25 changed files with 9,874 additions and 0 deletions.
45 changes: 45 additions & 0 deletions demo/interpreter/expression.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
_ = require('underscore')
{solve, special, vari, dummy, cons, vari, macro} = require("../../lib/interpreter/core")
{print_, getvalue, toString} = require("../../lib/interpreter/builtins/general")
{andp, orp, rule, bind, is_} = require("../../lib/interpreter/builtins/logic")
{begin} = require("../../lib/interpreter/builtins/lisp")
{settext, char, digits, spaces, eoi, literal, number, dqstring, sqstring} = require("../../lib/interpreter/builtins/parser")


exports.expression = (operator) -> rule(null, 'expression', (x)->
op = vari('op'); e1 = vari('e1'); e2 = vari('e2')
[[expr(f, e1, e2)], andp(expression(e1), operator(f), expression(e2))]
)

# use rule. slower
exports.operator = rule(1, 'operator', (x) ->
[ ['+'], literal('+'),
['-'], literal('-'),
['*'], literal('*'),
['/'], literal('/')
])

# use special, speed optimization
exports.operator = special('operator', (solver, cont, x) -> (v) ->
[data, pos] = solver.state
if pos>=data.length then return solver.failcont(false)
c = data[pos]
x = solver.trail.deref(x)
if _.isString(x)
if x is c
solver.state = [data, pos+1]; cont(c)
else solver.failcont(c)
else
if c in "+-*/" then x.bind(c, solver.trail); solver.state = [data, pos+1]; cont(c)
else solver.failcont(c))

# use terminal in parser.coffee
operator = (x) -> is_(charIn("+-*/"))

string = (x) -> orp(is_(x, dqstring), is_(x, sqstring))

exports.atom = rule(1, 'atom', (x) ->
[ [x], number(x),
[x], string(x),
[x], andp(literal('('), spaces, expression(x),literal(')'))
])
43 changes: 43 additions & 0 deletions demo/interpreter/kleene.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{solve, special, vari, dummy, cons, vari, macro} = require("../../lib/interpreter/core")
{print_, getvalue, toString} = require("../../lib/interpreter/builtins/general")
{andp, orp, rule, bind, is_} = require("../../lib/interpreter/builtins/logic")
{begin} = require("../../lib/interpreter/builtins/lisp")
{settext, char, digits, spaces, eoi, memo} = require("../../lib/interpreter/builtins/parser")

exports.flatString = flatString = special(1, 'flatString', (solver, cont, x) ->
solver.cont(x, (v) -> cont(v.flatString?() or 'null')))

exports.kleene = kleene = rule(1, (x) ->
x = vari('x'); y = vari('y')
[ [cons(x, y)], andp(char(x), print_(x), kleene(y)),
[null], print_('end')
])

# wrong implementation, don't work.
leftkleene = rule(0, () ->
x = vari('x')
[ [], andp(leftkleene(), char(x), print_(x)),
[], print_('end')
])

exports.leftkleene = leftkleene = memo(leftkleene)

exports.kleenePredicate = (pred) ->
r = rule(1, (x) ->
x = vari('x'); y = vari('y')
[ [cons(x, y)], andp(pred(x)#, print_(x)
, r(y)),
[null], print_('end')
])
r

#dightsSpaces = macro(1, (x) -> andp(digits, print_('daf'), spaces, print_('adds')))

exports.dightsSpaces = macro(1, (x) ->
andp(is_(x, digits)
# print_('daf'),
, orp(spaces, eoi)
# , print_('adds')
)
)

116 changes: 116 additions & 0 deletions src/builtins/general.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# #### general builtins

core = require "../core"
il = require "../interlang"

fun = core.fun
special = core.special

# console.log(arguments)
exports.print_ = fun(null, 'print',il.jscallable('console.log'))

exports.eq = fun(2, 'eq', il.eq)
exports.ne = fun(2, 'ne', il.ne)
exports.lt = fun(2, 'lt', il.lt)
exports.le = fun(2, 'le', il.le)
exports.gt = fun(2, 'gt', il.gt)
exports.ge = fun(2, 'ge', il.ge)
exports.add = fun(2, 'add', il.add)
exports.sub = fun(2, 'sub', il.sub)
exports.mul = fun(2, 'mul', il.mul)
exports.div = fun(2, 'div', il.div)
exports.and_ = fun(2, 'and_', il.and_)
exports.or_ = fun(2, 'or_', il.or_)
exports.not_ = fun(1, 'not_', il.not_)
exports.lshift = fun(2, 'lshift', il.lshift)
exports.rshift = fun(2, 'rshift', il.rshift)
exports.bitand = fun(2, 'bitand', il.bitand)
exports.bitor = fun(2, 'bitor', il.bitor)
exports.bitnot = fun(1, 'bitnot', il.bitnot)


exports.inc = special(1, 'inc', (compiler, cont, item) ->
il.return(cont.call(il.inc.apply([item.interlang()]))))

exports.suffixinc = special(1, 'suffixinc', (compiler, cont, item) ->
il.return(cont.call(il.suffixinc.apply([item.interlang()]))))

exports.dec = special(1, 'dec', (compiler, cont, item) ->
il.return(cont.call(il.dec.apply([item.interlang()]))))

exports.suffixdec = special(1, 'suffixdec', (compiler, cont, item) ->
il.return(cont.call(il.suffixdec.apply([item.interlang()]))))

###
# x.getvalue
exports.getvalue = special(1, 'getvalue', (compiler, cont, x) ->
compiler.cont(x, (v) -> cont(compiler.trail.getvalue(v))))
# x.length
exports.length = special(1, 'length', (compiler, cont, x) ->
compiler.cont(x, (v) -> cont(v.length)))
# -x
exports.neg = special(1, 'neg', (compiler, cont, x) ->
compiler.cont(x, (v) -> cont(-v)))
# Math.abs(x)
exports.abs = special(1, 'abs', (compiler, cont, x) ->
compiler.cont(x, (v) -> cont(Math.abs(v))))
# x[y]
exports.index = special(2, 'index', (compiler, cont, x, y) ->
ycont = compiler.cont(y, (v) -> cont(x[y]))
xcont = (v) -> x = v; ycont(null)
compiler.cont(x, xcont))
# x[0]
exports.first = exports.head = special(1, 'first', (compiler, cont, x) ->
compiler.cont(x, (v) -> cont(v[0])))
# x[1...]
exports.tail = special(1, 'tail', (compiler, cont, x) ->
compiler.cont(x, (v) -> cont(v[1...])))
# x[1]
exports.second = special(1, 'second', (compiler, cont, x) ->
compiler.cont(x, (v) -> cont(v[1])))
# x[2]
exports.third = special(1, 'third', (compiler, cont, x) ->
compiler.cont(x, (v) -> cont(v[2])))
# x.concat(y)
exports.concat = special(2, 'concat', (compiler, cont, x, y) ->
ycont = compiler.cont(y, (v) -> cont(x.concat(y)))
xcont = (v) -> x = v; ycont(null)
compiler.cont(x, xcont))
# list(args...) return an array
exports.list = special([], 'list', (compiler, cont, args...) ->
compiler.argsCont(args, cont))
# x.push(y)
exports.push = special(2, 'push', (compiler, cont, x, y) ->
ycont = compiler.cont(y, (v) -> cont(x.push(v)))
xcont = (v) -> x = v; ycont(null)
compiler.cont(x, xcont))
# x.push(y), when backtracking here, x.pop()
exports.pushp = special(2, 'pushp', (compiler, cont, x, y) ->
ycont = compiler.cont(y, (v) ->
fc = compiler.failcont
compiler.failcont = (v) -> x.pop(); fc(v)
cont(x.push(v)))
xcont = (v) -> x = v; ycont(null)
compiler.cont(x, xcont))
# x is a free variable? <br/>
# different from logic.freep, this never fail
exports.free = special(1, 'freep', (compiler, cont, x) ->
(v) -> cont(compiler.trail.deref(x) instanceof Var))
# toString: x.toString
exports.toString = special(1, 'toString', (compiler, cont, x) ->
compiler.cont(x, (v) -> cont(v?.toString?() or JSON.stringify(v))))
###
189 changes: 189 additions & 0 deletions src/builtins/lisp.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
# #### lisp builtins
# lispt.coffee doesn't know trail, failcont, state and the like.
# lisp knows cont only.

_ = require('underscore')
core = require "../core"
il = require "../interlang"
general = require "./general"

special = core.special
macro = core.macro

debug = core.debug

# aka lisp's quote, like in lisp, 'x==x, quote(x) === x
exports.quote = special(1, 'quote', (compiler, cont, exp) ->
il.return(cont.call(exp)))

# aka lisp's eval, solve(eval_(quote(x))) means solve(x),
exports.eval_ = special(1, 'eval', (compiler, cont, exp) ->
v = compiler.vari('v')
compiler.cont(exp, il.clamda(v, compiler.cont(v, cont))))

exports.assign = special(2, 'assign', (compiler, cont, item, exp) ->
v = compiler.vari('v')
compiler.cont(exp, il.clamda(v, il.assign(item.interlang(), v), il.return(cont.call(v)))))

# aka lisp's begin, same as logic.andp
exports.begin = special(null, 'begin', (compiler, cont, exps...) -> compiler.expsCont(exps, cont))

if_fun = (compiler, cont, test, then_, else_) ->
v = compiler.vari('v')
compiler.cont(test, il.clamda(v, il.if_(v, compiler.cont(then_, cont), compiler.cont(else_, cont))))

# lisp style if. <br/>
# different from logic.ifp, when test fail, it do not run else_ clause.
exports.if_ = if_ = special([2,3], 'if_', if_fun)

iff_fun = (compiler, cont, clauses, else_) ->
length = clauses.length
if length is 0 then throw new exports.TypeError(clauses)
else if length is 1
[test, then_] = clauses[0]
if_fun(compiler, cont, test, then_, else_)
else
[test, then_] = clauses[0]
v = compiler.vari('v')
compiler.cont(test, il.clamda(v, il.if_(v, compiler.cont(then_, cont),
iff_fun(compiler, cont, clauses[1...], else_))))

#iff [ [test1, body1], <br/>
# [test2, body2] <br/>
# ] <br/>
# else_

exports.iff = special(-2, 'iff', iff_fun)

# lisp style block
exports.block = block = special(null, 'block', (compiler, cont, label, body...) ->
if not _.isString(label) then (label = ''; body = [label].concat(body))

exits = compiler.exits[label] ?= []
exits.push(cont)
defaultExits = compiler.exits[''] ?= [] # if no label, go here
defaultExits.push(cont)
continues = compiler.continues[label] ?= []
f = compiler.vari('block'+label)
fun = il.clamda(compiler.vari('v'), null)
continues.push(f)
defaultContinues = compiler.continues[''] ?= [] # if no label, go here
defaultContinues.push(f)
fun.body = compiler.expsCont(body, cont)
exits.pop()
if exits.length is 0 then delete compiler.exits[label]
continues.pop()
if continues.length is 0 then delete compiler.continues[label]
defaultExits.pop()
defaultContinues.pop()
il.begin(
il.assign(f, fun),
il.return(f.apply([null]))))

# break a block
exports.break_ = break_ = special([0, 1,2], 'break_', (compiler, cont, label='', value=null) ->
if value != null and not _.isString label then throw new TypeError([label, value])
if value is null and not _.isString label then (value = label; label = '')
exits = compiler.exits[label]
if not exits or exits==[] then throw new Error(label)
exitCont = exits[exits.length-1]
compiler.cont(value, compiler.protect(exitCont)))

# continue a block
exports.continue_ = continue_ = special([0,1], 'continue_', (compiler, cont, label='') ->
continues = compiler.continues[label]
if not continues or continues==[] then throw new Error(label)
continueCont = continues[continues.length-1]
il.return(compiler.protect(continueCont).call(null)))

not_ = general.not_

# loop
exports.loop_ = macro(null, 'loop', (label, body...) ->
if not _.isString(label) then (label = ''; body = [label].concat body)
block(label, body.concat([continue_(label)])...))

# while
exports.while_ = macro(null, 'while_', (label, test, body...) ->
if not _.isString(label) then (label = ''; test = label; body = [test].concat body)
block(label, [if_(not_(test), break_(label))].concat(body).concat([continue_(label)])...))

# until
exports.until_ = macro(null, 'until_', (label,body..., test) ->
if not _.isString(label) then (label = ''; test = label; body = [test].concat body)
body = body.concat([if_(not_(test), continue_(label))])
block(label, body...))


# aka. lisp style catch/throw
exports.catch_ = special(-1, 'catch_', (compiler, cont, tag, forms...) ->
v = compiler.vari('v'); v2 = compiler.vari('v')
formsCont = compiler.expsCont(forms, il.clamda(v2
il.popCatch.apply([v]),
il.return(cont.call(v2))))
compiler.cont(tag, il.clamda(v,
il.pushCatch.apply([v, cont]),
formsCont)))

# aka lisp style throw
exports.throw_ = special(2, 'throw_', (compiler, cont, tag, form) ->
v = compiler.vari('v'); v2 = compiler.vari('v')
formCont = il.clamda(v,
compiler.cont(form, il.clamda(v2,
il.return(compiler.protect(il.findCatch.apply([v])).call(v2)))))
compiler.cont(tag, formCont))


# aka. lisp's unwind-protect
exports.protect = special(-1, 'protect', (compiler, cont, form, cleanup...) ->
oldprotect = compiler.protect
v1 = compiler.vari('v'); v2 = compiler.vari('v')
compiler.protect = (cont) -> il.clamda(v1,
compiler.expsCont(cleanup, il.clamda(v2,
il.return(oldprotect(cont).call(v1)))))
result = compiler.cont(form, il.clamda(v1,
compiler.expsCont(cleanup, il.clamda(v2,
il.return(cont.call(v1))))))
compiler.protect = oldprotect
result)

# callcc(someFunction(kont) -> body) <br/>
#current continuation @cont can be captured in someFunction
exports.callcc = special(1, 'callcc', (compiler, cont, fun) ->
if not fun.toCode? then fun = il.fun(fun)
faked = compiler.vari('faked'); result = compiler.vari('result'); v = compiler.vari('v')
cc = il.clamda(v,
il.restore.apply([faked]),
il.assign(result, il.getvalue.apply([il.index.apply([il.run.apply([cont, v]), 1])])),
il.code("solver.finished = false;"),
il.return(result))
il.begin(il.assign(faked, il.fake),
il.return(cont.call(fun.apply([cc])))))

###
# callfc(someFunction(fc) -> body) <br/>
#current compiler.failcont can be captured in someFunction
exports.callfc = special(1, 'callfc', (compiler, cont, fun) -> (v) ->
faked = compiler.fake()
fc = (v) ->
compiler.restore(faked)
result = compiler.run(v, compiler.failcont)
compiler.trail.getvalue(result[1])
cont(fun(fc)))
# 0.1.11 update
# callcs(someFunction(compiler, faked, kont) -> body) <br/>
# the compiler, compiler's current content and current cont can be captured in someFunction
exports.callcs = special(1, 'callcs', (compiler, cont, fun) -> (v) ->
cont(fun(compiler, compiler.fake(), cont)))
# lisp style quasiquote/unquote/unquote-slice "`", "," and ",@"
exports.quasiquote = exports.qq = special(1, 'quasiquote', (compiler, cont, item) ->
compiler.quasiquote?(item, cont))
exports.unquote = exports.uq = special(1, 'unquote', (compiler, cont, item) ->
throw "unquote: too many unquote and unquoteSlice" )
exports.unquoteSlice = exports.uqs = special(1, 'unquoteSlice', (compiler, cont, item) ->
throw "unquoteSlice: too many unquote and unquoteSlice")
###
Loading

0 comments on commit 0365be0

Please sign in to comment.