diff --git a/README.md b/README.md index 1f1aa21..d49c62f 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ npm start - `(import path rect)` Imports a graphic file with format. - `(export path ~format ~quality)` Exports a graphic file with format. +- `(open path)` Imports a graphic file and resizes the frame. - `(pos x y ~t)` Returns a position shape. - `(size w h ~t)` Returns a size shape. - `(rect x y w h ~t)` Returns a rect shape. @@ -37,7 +38,7 @@ npm start - `(stroke ~shape)` Strokes a shape. - `(fill ~rect)` Fills a shape. - `(clear ~rect)` Clears a rect. -- `(concat ...items)` +- `(concat ...items)` Concat multiple strings. - `(add ...args)` Adds values. - `(sub ...args)` Subtracts values. - `(mul ...args)` Multiplies values. @@ -69,32 +70,29 @@ npm start - `(range start end ~step)` - `(get item key)` Gets an object's parameter with name. - `(set item key val)` Sets an object's parameter with name as value. -- `(of h ...keys)` +- `(of h ...keys)` Gets object parameters with names. - `(frame)` Returns a rect of the frame. - `(center)` Returns a position of the center of the frame. -- `(scale rect w h)` - `(resize w h ~fit)` Resizes the canvas to target w and h, returns the rect. - `(rescale w h)` Rescales the canvas to target ratio of w and h, returns the rect. -- `(crop rect)` +- `(crop rect)` Crop canvas to rect. - `(clone a b)` - `(theme variable ~el)` - `(gradient [x1 y1 x2 y2] ~colors 'black'])` - `(pixels rect fn q)` - `(saturation pixel ~q)` - `(contrast pixel ~q)` -- `(echo ...args)` -- `(str ...args)` -- `(open path)` Imports a graphic file and resizes the frame. - `(dir ~path)` Returns the content of a directory. -- `(file ~path)` Returns the content of a file +- `(file ~path)` Returns the content of a file. - `(dirpath ~path)` Returns the path of a directory. -- `(filepath ~path)` Returns the path of a file +- `(filepath ~path)` Returns the path of a file. - `(exit ~force)` Exits Ronin. -- `(time)` Returns timestamp in milliseconds. +- `(echo ...args)` +- `(time ~rate)` Returns timestamp in milliseconds. - `(animate ~play)` Toggles animation. - `(js)` Javascript interop. - `(test name a b)` -- `(benchmark fn)` logs time taken to execute a function +- `(benchmark fn)` logs time taken to execute a function. ## Extras diff --git a/desktop/sources/lisp/prelude.lisp b/desktop/sources/lisp/prelude.lisp new file mode 100644 index 0000000..82c0999 --- /dev/null +++ b/desktop/sources/lisp/prelude.lisp @@ -0,0 +1,11 @@ +(echo "Loading prelude.lisp") + +(defn translate + (r p) + (clone + r + (rect + (of p :x) + (of p :y) + (of r :w) + (of r :h)))) diff --git a/desktop/sources/scripts/commander.js b/desktop/sources/scripts/commander.js index 95892a5..f42d1d1 100644 --- a/desktop/sources/scripts/commander.js +++ b/desktop/sources/scripts/commander.js @@ -35,12 +35,13 @@ function Commander (ronin) { if (txt.indexOf('$') > -1) { ronin.log('Present: $'); return } const inter = new Lisp(txt, ronin.library) inter.toPixels() - ronin.always && requestAnimationFrame(() => this.run(txt)) + ronin.always === true && requestAnimationFrame(() => this.run(txt)) } this.load = function (txt) { + ronin.animate(false) this._input.value = txt - this.run() + this.run(txt) } this.reindent = function () { diff --git a/desktop/sources/scripts/library.js b/desktop/sources/scripts/library.js index 39167f9..c279226 100644 --- a/desktop/sources/scripts/library.js +++ b/desktop/sources/scripts/library.js @@ -13,6 +13,10 @@ function Library (ronin) { return path } + this.open = async (path) => { // Imports a graphic file and resizes the frame. + return ronin.surface.open(path) + } + // Shapes this.pos = (x, y, t = 'pos') => { // Returns a position shape. @@ -62,7 +66,7 @@ function Library (ronin) { // Strings - this.concat = function (...items) { + this.concat = function (...items) { // Concat multiple strings. return items.reduce((acc, item) => { return `${acc}${item}` }, '') } @@ -223,12 +227,20 @@ function Library (ronin) { return item[key] } - this.of = (h, ...keys) => { + this.of = (h, ...keys) => { // Gets object parameters with names. return keys.reduce((acc, key) => { return acc[key] }, h) } + this.keys = (item) => { // Returns a list of the object's keys + return Object.keys(item) + } + + this.values = (item) => { // Returns a list of the object's values + return Object.values(item) + } + // Frame this.frame = () => { // Returns a rect of the frame. @@ -240,10 +252,6 @@ function Library (ronin) { return this.pos(rect.w / 2, rect.h / 2) } - this.scale = (rect, w, h) => { - return { x: rect.x, y: rect.y, w: rect.w * w, h: rect.h * h } - } - this.resize = async (w, h, fit = true) => { // Resizes the canvas to target w and h, returns the rect. const rect = { x: 0, y: 0, w, h } const a = document.createElement('img') @@ -264,7 +272,7 @@ function Library (ronin) { return ronin.surface.draw(b, rect) } - this.crop = async (rect) => { + this.crop = async (rect) => { // Crop canvas to rect. return ronin.surface.crop(rect) } @@ -310,45 +318,35 @@ function Library (ronin) { return [pixel.r * q + intercept, pixel.g * q + intercept, pixel.b * q + intercept, pixel.a] } - // Misc - - this.echo = (...args) => { - ronin.log(args) - return args - } - - this.str = (...args) => { - return args.reduce((acc, val) => { return acc + val }, '') - } - - this.open = async (path) => { // Imports a graphic file and resizes the frame. - return ronin.surface.open(path) - } - // File System - this.dir = (path = ronin.source.path) => { // Returns the content of a directory. + this.dir = (path = this.dirpath()) => { // Returns the content of a directory. return fs.existsSync(path) ? fs.readdirSync(path) : [] } - this.file = (path = ronin.source.path) => { // Returns the content of a file - return fs.existsSync(path) ? fs.readFileSync(p, 'utf8') : '' + this.file = (path = this.filepath()) => { // Returns the content of a file. + return fs.existsSync(path) ? fs.readFileSync(path, 'utf8') : '' } - this.dirpath = (path = ronin.source.path) => { // Returns the path of a directory. + this.dirpath = (path = this.filepath()) => { // Returns the path of a directory. return require('path').dirname(path) } - this.filepath = (path = ronin.source.path) => { // Returns the path of a file - return fs.existsSync(path) ? fs.readdirSync(path) : [] + this.filepath = (path = ronin.source.path) => { // Returns the path of a file. + return path } this.exit = (force = false) => { // Exits Ronin. ronin.source.quit(force) } - this.time = () => { // Returns timestamp in milliseconds. - return Date.now() + this.echo = (...args) => { + ronin.log(args) + return args + } + + this.time = (rate = 1) => { // Returns timestamp in milliseconds. + return (Date.now() * rate) } this.animate = (play = true) => { // Toggles animation. @@ -368,7 +366,7 @@ function Library (ronin) { return a === b } - this.benchmark = async (fn) => { // logs time taken to execute a function + this.benchmark = async (fn) => { // logs time taken to execute a function. const start = Date.now() const result = await fn() console.log(`time taken: ${Date.now() - start}ms`) diff --git a/desktop/sources/scripts/lisp.js b/desktop/sources/scripts/lisp.js index 7459f97..d2a9541 100644 --- a/desktop/sources/scripts/lisp.js +++ b/desktop/sources/scripts/lisp.js @@ -22,7 +22,7 @@ function Lisp (input, lib) { include: (input, context) => { if (!input[1].value || !fs.existsSync(input[1].value)) { console.warn('Source', input[1].value); return [] } const file = fs.readFileSync(input[1].value, { encoding: 'utf-8' }) - return interpret(this.parse(file), context) + return interpret(this.parse(`(${file})`), context) }, let: function (input, context) { const letContext = input[1].reduce(function (acc, x) { @@ -65,6 +65,27 @@ function Lisp (input, lib) { return interpret(input[2], context) } return input[3] ? interpret(input[3], context) : [] + }, + __fn: function (input, context) { + return async function () { + const lambdaArguments = arguments + const keys = [...new Set(input.slice(2).flat(100).filter(i => + i.type === TYPES.identifier && + i.value[0] === '%' + ).map(x => x.value).sort())] + const lambdaScope = keys.reduce(function (acc, x, i) { + acc[x] = lambdaArguments[i] + return acc + }, {}) + return interpret(input.slice(1), new Context(lambdaScope, context)) + } + }, + __obj: async function (input, context) { + const obj = {} + for (let i = 1 ; i