-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
cxm01
committed
Nov 26, 2015
1 parent
86ce7a6
commit 0365be0
Showing
25 changed files
with
9,874 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(')')) | ||
]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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') | ||
) | ||
) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)))) | ||
### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") | ||
### |
Oops, something went wrong.