diff --git a/src/stdlib/ns/fn.es6 b/src/stdlib/ns/fn.es6 new file mode 100644 index 00000000..2e7e6ed9 --- /dev/null +++ b/src/stdlib/ns/fn.es6 @@ -0,0 +1,17 @@ +export default function(cheddar){ + return cheddar.namespace([ + ["hook", cheddar.from(require("./fn/hook"))], + ["fork", cheddar.from(require("./fn/fork"))], + ["reflexive", cheddar.from(require("./fn/reflexive"))], + ["dbl", cheddar.from(require("./fn/dbl"))], + ["pref", cheddar.from(require("./fn/pref"))], + ["insert", cheddar.from(require("./fn/insert"))], + ["prefix", cheddar.from(require("./fn/prefix"))], + ["id", cheddar.from(require("./fn/id"))], + ["curry", cheddar.from(require("./fn/curry"))], + ["bind", cheddar.from(require("./fn/bind"))], + ["rev", cheddar.from(require("./fn/rev"))], + ["repeat", cheddar.from(require("./fn/repeat"))], + ["of", cheddar.from(require("./fn/of"))] + ]); +} diff --git a/src/stdlib/ns/fn/bind.es6 b/src/stdlib/ns/fn/bind.es6 new file mode 100644 index 00000000..aebde74a --- /dev/null +++ b/src/stdlib/ns/fn/bind.es6 @@ -0,0 +1,29 @@ +export default function bind(cheddar) { + return new cheddar.func( + [ + ["args", {Splat: true}] + ], + function(scope, input){ + let args = input("args").value; + if(args[0] instanceof cheddar.func){ + let f = args.shift(); + return new cheddar.func( + [["b", {Splat: true}]], + function(s, k){ + return f.exec(k("b").value.concat(args), null); + } + ); + } else if(args[args.length - 1] instanceof cheddar.func){ + let f = args.pop(); + return new cheddar.func( + [["b", {Splat: true}]], + function(s, k){ + return f.exec(args.concat(k("b").value), null); + } + ); + } else { + return "Expected function as first or last argument."; + } + } + ); +} diff --git a/src/stdlib/ns/fn/curry.es6 b/src/stdlib/ns/fn/curry.es6 new file mode 100644 index 00000000..ce0d9ecf --- /dev/null +++ b/src/stdlib/ns/fn/curry.es6 @@ -0,0 +1,19 @@ +export default function curry(cheddar) { + return new cheddar.func( + [ + ["f", { Type: cheddar.func }], + ["a", {}] + ], + function(scope, input){ + return new cheddar.func( + [["b", {}]], + function(s, k){ + let f = input("f"); + let a = input("a"); + let b = k("b"); + return f.exec([a, b], null); + } + ) + } + ); +} diff --git a/src/stdlib/ns/fn/fork.es6 b/src/stdlib/ns/fn/fork.es6 new file mode 100644 index 00000000..7c618661 --- /dev/null +++ b/src/stdlib/ns/fn/fork.es6 @@ -0,0 +1,26 @@ +export default function fork(cheddar) { + return new cheddar.func( + [ + ["f", { Type: cheddar.func }], + ["g", { Type: cheddar.func }], + ["h", { Type: cheddar.func }] + ], + function(scope, input){ + return new cheddar.func( + [["args", {Splat: true}]], + function(s, k){ + let args = k("args").value; + + let f = input("f"); + let g = input("g"); + let h = input("h"); + + return g.exec([ + f.exec(args, null), + h.exec(args, null) + ], null); + } + ) + } + ); +} diff --git a/src/stdlib/ns/fn/hook.es6 b/src/stdlib/ns/fn/hook.es6 new file mode 100644 index 00000000..dc7990e0 --- /dev/null +++ b/src/stdlib/ns/fn/hook.es6 @@ -0,0 +1,27 @@ +export default function hook(cheddar) { + return new cheddar.func( + [ + ["f", { Type: cheddar.func }], + ["g", { Type: cheddar.func }] + ], + function(scope, input, args){ + if(args.length !== 2) + return `Expected 2 arguments, received ${args.length}.`; + + return new cheddar.func( + [["args", {Splat: true}]], + function(s, k){ + let args = k("args").value; + + if(args.length > 2 || !args.length) + return `Expected 1 or 2 args, received ${args.length || "none"}`; + + let f = input("f"); + let g = input("g"); + + return f.exec([args[0], g.exec([args.length === 1 ? args[0] : args[1]], null)], null); + } + ) + } + ); +} diff --git a/src/stdlib/ns/fn/id.es6 b/src/stdlib/ns/fn/id.es6 new file mode 100644 index 00000000..e77d8120 --- /dev/null +++ b/src/stdlib/ns/fn/id.es6 @@ -0,0 +1,8 @@ +export default function id(cheddar) { + return new cheddar.func( + [["a", { Type: cheddar.func }]], + function(scope, input){ + return input("a"); + } + ) +} diff --git a/src/stdlib/ns/fn/insert.es6 b/src/stdlib/ns/fn/insert.es6 new file mode 100644 index 00000000..2450dd74 --- /dev/null +++ b/src/stdlib/ns/fn/insert.es6 @@ -0,0 +1,25 @@ +export default function insert(cheddar) { + return new cheddar.func( + [ + ["f", { Type: cheddar.func }], + ], + function(scope, input){ + return new cheddar.func( + [["array", { + Type: cheddar.array + }]], + function(s, k){ + let arr = k("array"); + let f = input("f"); + + if(arr.length === 1) + return arr; + + // console.log("DEBUG:",arr); + + return arr.value.reduce((prev, cur) => f.exec([prev, cur], null)); + } + ) + } + ); +} diff --git a/src/stdlib/ns/fn/of.es6 b/src/stdlib/ns/fn/of.es6 new file mode 100644 index 00000000..30179a7f --- /dev/null +++ b/src/stdlib/ns/fn/of.es6 @@ -0,0 +1,51 @@ +import { UOP, OP } from "../../../tokenizer/consts/ops"; +import fork from "./fork"; + +const ops = [ + "+", "*", "**", "-", "^", + "&", "|", "/", "%", "@\"" +]; // TODO: make dynamic + +const parse = (str) => { + let tokens = []; + for(let i = 0; i < str.length; i++){ + if(!ops.some(x => x[0] === str[i])) continue; + + let build = ""; + while(ops.some(x => x.indexOf(build + str[i]) >= 0)){ + build += str[i++]; + } + i--; + tokens.push(build); + } + return tokens; +} + +export default function insert(cheddar) { + return new cheddar.func( + [ + ["str", { + Type: cheddar.string + }], + ], + function(scope, input){ + let str = input("str"); + let toks = parse(str.value); + if(toks.length !== 3){ + return "I haven't implemented this yet."; + } + return fork.exec(...toks.map(e => + new cheddar.func( + ["LHS", { }], + ["RHS", { Optional: true }], + function(_scope, _input){ + let LHS = input("LHS"); + let RHS = input("RHS"); + + return LHS.Operator.get(e)(RHS ? LHS : null, RHS || LHS); + } + ) + ), null); + } + ); +} diff --git a/src/stdlib/ns/fn/pref.es6 b/src/stdlib/ns/fn/pref.es6 new file mode 100644 index 00000000..a71de9f2 --- /dev/null +++ b/src/stdlib/ns/fn/pref.es6 @@ -0,0 +1,12 @@ +export default function pref(cheddar) { + return new cheddar.func( + [ + ["array", {}], + ], + function(scope, input){ + return cheddar.init(cheddar.array, ...input("array").value.map( + (e, i, a) => cheddar.init(cheddar.array, ...a.slice(0, i + 1)) + )); + } + ); +} diff --git a/src/stdlib/ns/fn/prefix.es6 b/src/stdlib/ns/fn/prefix.es6 new file mode 100644 index 00000000..e7620fb4 --- /dev/null +++ b/src/stdlib/ns/fn/prefix.es6 @@ -0,0 +1,18 @@ +export default function prefix(cheddar) { + return new cheddar.func( + [["f", { Type: cheddar.func }]], + function(scope, k){ + return new cheddar.func( + [["array", {}]], + function(s, input){ + let f = k("f"); + return cheddar.init(cheddar.array, ...input("array").value.map( + (e, i, a) => f.exec([ + cheddar.init(cheddar.array, ...a.slice(0, i + 1)) + ], null) + )); + } + ); + } + ) +} diff --git a/src/stdlib/ns/fn/reflexive.es6 b/src/stdlib/ns/fn/reflexive.es6 new file mode 100644 index 00000000..a22fefb3 --- /dev/null +++ b/src/stdlib/ns/fn/reflexive.es6 @@ -0,0 +1,17 @@ +export default function reflexive(cheddar) { + return new cheddar.func( + [ + ["f", { Type: cheddar.func }], + ], + function(scope, input){ + return new cheddar.func( + [["a", {}]], + function(s, k){ + let f = input("f"); + + return f.exec(Array(f.args.length).fill(k("a")), null); + } + ) + } + ); +} diff --git a/src/stdlib/ns/fn/repeat.es6 b/src/stdlib/ns/fn/repeat.es6 new file mode 100644 index 00000000..1141e651 --- /dev/null +++ b/src/stdlib/ns/fn/repeat.es6 @@ -0,0 +1,27 @@ +export default function repeat(cheddar) { + return new cheddar.func( + [ + ["f", { Type: cheddar.func }], + ["n", {}] + ], + function(scope, input){ + return new cheddar.func( + [["args", { Splat: true }]], + function(s, k){ + let f = input("f"); + let n = input("n").value; + let args = k("args"); + if(n === 0) + return args; + + args = args.value; + let res = f.exec(args, null); + while(--n > 0){ + res = f.exec([res], null); + } + return res; + } + ) + } + ); +} diff --git a/src/stdlib/ns/fn/rev.es6 b/src/stdlib/ns/fn/rev.es6 new file mode 100644 index 00000000..6c549769 --- /dev/null +++ b/src/stdlib/ns/fn/rev.es6 @@ -0,0 +1,16 @@ +export default function rev(cheddar) { + return new cheddar.func( + [ + ["f", { Type: cheddar.func }] + ], + function(scope, input){ + return new cheddar.func( + [["a", { Splat: true }]], + function(s, k){ + let a = k("a"); + return input("f").exec(a.value.reverse(), null); + } + ) + } + ); +} diff --git a/src/stdlib/stdlib.es6 b/src/stdlib/stdlib.es6 index ababd50e..a5d90e19 100644 --- a/src/stdlib/stdlib.es6 +++ b/src/stdlib/stdlib.es6 @@ -20,9 +20,11 @@ STDLIB.Item("Math"); STDLIB.Item("Rational"); // Interface Libraries -STDLIB.Item("Encoding"); -STDLIB.Item("Buffer"); -STDLIB.Item("IO", true); +STDLIB.Item("Encoding", require('./ns/Encoding')); +STDLIB.Item("Buffer", require('./ns/Buffer')); +STDLIB.Item("IO", require('./ns/IO')); +STDLIB.Item("fn", require("./ns/fn")); +//STDLIB.Item("HTTP", require('./ns/HTTP')); /** Primitives **/ STDLIB.p("String", API.string); diff --git a/test.cdr b/test.cdr new file mode 100644 index 00000000..368e3bfc --- /dev/null +++ b/test.cdr @@ -0,0 +1,3 @@ +var fib = (n) -> { + print n +} diff --git a/test/tests/stdlib/fn.js b/test/tests/stdlib/fn.js new file mode 100644 index 00000000..fc8e7916 --- /dev/null +++ b/test/tests/stdlib/fn.js @@ -0,0 +1,22 @@ +var TestCheddarFrom = require('../globals').TestCheddarFrom; +var chai = require('chai'); + +describe("fn", function(){ + describe("reflexive", function(){ + it("should work", TestCheddarFrom.Code( + "fn.reflexive((+))(3)", + "6" + )); + it("should work", TestCheddarFrom.Code( + "fn.reflexive((*))(3)", + "9" + )); + }); + + describe("hook", function(){ + it("should work", TestCheddarFrom.Code( + "fn.hook((+),(sqrt),(-))(4)", + "6" + )); + }); +});