Fixes in lambda/function definitions (body args). Cleanup of examples and decumentation. Added convenience methods for JS interop, lists and objects.
This commit is contained in:
@@ -40,15 +40,21 @@ function Lain (lib = {}) {
|
||||
defn: function (input, context) {
|
||||
const identifier = input[1].value
|
||||
if (context.scope[identifier]) { console.warn('Lain', `Redefining function: ${identifier}`) }
|
||||
|
||||
const fnParams = input[2].type === TYPES.string && input[3] ? input[3] : input[2]
|
||||
const fnBody = input[2].type === TYPES.string && input[4] ? input[4] : input[3]
|
||||
const fnBodyFirstIndex = input[2].type === TYPES.string && input[4] ? 4 : 3
|
||||
const fnBody = input.slice(fnBodyFirstIndex)
|
||||
|
||||
context.scope[identifier] = function () {
|
||||
const lambdaArguments = arguments
|
||||
const lambdaScope = fnParams.reduce(function (acc, x, i) {
|
||||
acc[x.value] = lambdaArguments[i]
|
||||
return acc
|
||||
}, {})
|
||||
return interpret(fnBody, new Context(lambdaScope, context))
|
||||
|
||||
let result = interpret(fnBody, new Context(lambdaScope, context))
|
||||
//lisp returns the return value of the last executed function, not a list of all results of all functions.
|
||||
return getReturnValue(result)
|
||||
}
|
||||
},
|
||||
λ: function (input, context) {
|
||||
@@ -58,7 +64,10 @@ function Lain (lib = {}) {
|
||||
acc[x.value] = lambdaArguments[i]
|
||||
return acc
|
||||
}, {})
|
||||
return interpret(input[2], new Context(lambdaScope, context))
|
||||
|
||||
let result = interpret(input.slice(2), new Context(lambdaScope, context))
|
||||
//lisp returns the return value of the last executed function, not a list of all results of all functions.
|
||||
return getReturnValue(result)
|
||||
}
|
||||
},
|
||||
if: function (input, context) {
|
||||
@@ -66,6 +75,15 @@ function Lain (lib = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
const getReturnValue = function (interpretResult) {
|
||||
//lisp returns the return value of the last executed function,
|
||||
//not a list of all results of all functions.
|
||||
if(!interpretResult || !(interpretResult instanceof Array) || !interpretResult.length){
|
||||
return interpretResult
|
||||
}
|
||||
return interpretResult[interpretResult.length - 1]
|
||||
}
|
||||
|
||||
const interpretList = function (input, context) {
|
||||
if (input.length > 0 && input[0].value in special) {
|
||||
return special[input[0].value](input, context)
|
||||
|
||||
@@ -382,6 +382,28 @@ function Library (client) {
|
||||
return Math.random()
|
||||
}
|
||||
|
||||
// Binary
|
||||
|
||||
this.logand = (a, b) => {
|
||||
return a & b
|
||||
}
|
||||
|
||||
this.logior = (a, b) => {
|
||||
return a | b
|
||||
}
|
||||
|
||||
this.logxor = (a, b) => {
|
||||
return a ^ b
|
||||
}
|
||||
|
||||
this.lognot = (a) => {
|
||||
return ~ a
|
||||
}
|
||||
|
||||
this.ash = (a, b) => {
|
||||
return a << b
|
||||
}
|
||||
|
||||
// Logic
|
||||
|
||||
this.gt = (a, b) => { // Returns true if a is greater than b, else false.
|
||||
@@ -415,18 +437,22 @@ function Library (client) {
|
||||
return args[args.length - 1]
|
||||
}
|
||||
|
||||
this.not = (a) => {
|
||||
this.not = (a) => { //Negation. Returns true if a is false. Returns false if a is true.
|
||||
return !a
|
||||
}
|
||||
|
||||
// Arrays
|
||||
|
||||
this.while = (fn, action) => {
|
||||
this.while = (fn, action) => { //While loop. Execute action for as long as fn is true.
|
||||
while (fn()) {
|
||||
action()
|
||||
}
|
||||
}
|
||||
|
||||
// Arrays
|
||||
this.apply = (fn, argslist) => {
|
||||
let result = fn(...argslist);
|
||||
return result;
|
||||
}
|
||||
|
||||
this.each = (arr, fn) => { // Run a function for each element in a list.
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const arg = arr[i]
|
||||
@@ -434,6 +460,12 @@ function Library (client) {
|
||||
}
|
||||
}
|
||||
|
||||
this.eachof = (arr, fn) => {
|
||||
for(let elem of arr){
|
||||
fn(elem);
|
||||
}
|
||||
}
|
||||
|
||||
this.map = (arr, fn) => { // Returns a new list with fn applied to each value.
|
||||
return arr.map(fn);
|
||||
}
|
||||
@@ -455,7 +487,11 @@ function Library (client) {
|
||||
return item.length
|
||||
}
|
||||
|
||||
this.cons = (arr, ...items) => { // Retruns a new array with the items appended.
|
||||
this.list = (...items) => { // Returns a new array with the items
|
||||
return items
|
||||
}
|
||||
|
||||
this.cons = (arr, ...items) => { // Returns a new array with the items appended to arr.
|
||||
return arr.concat(items)
|
||||
}
|
||||
|
||||
@@ -478,11 +514,11 @@ function Library (client) {
|
||||
return arr[arr.length - 1]
|
||||
}
|
||||
|
||||
this.rest = ([_, ...arr]) => {
|
||||
this.rest = ([_, ...arr]) => { // Returns all arguments except the first
|
||||
return arr
|
||||
}
|
||||
|
||||
this.range = (start, end, step = 1) => {
|
||||
this.range = (start, end, step = 1) => { //Returns a list of numbers counting from start to end. Step defaults to 1.
|
||||
const arr = []
|
||||
if (step > 0) {
|
||||
for (let i = start; i <= end; i += step) {
|
||||
@@ -499,7 +535,7 @@ function Library (client) {
|
||||
// Objects
|
||||
|
||||
this.get = (item, key) => { // Gets an object's parameter with name.
|
||||
return item && key ? item[key] : null
|
||||
return item && (key !== null && key !== undefined) ? item[key] : null
|
||||
}
|
||||
|
||||
this.set = (item, ...args) => { // Sets an object's parameter with name as value.
|
||||
@@ -533,6 +569,10 @@ function Library (client) {
|
||||
return Object.values(item)
|
||||
}
|
||||
|
||||
this.entries = (item) => { // Returns a list of the object's properties, each in array of [key, value]
|
||||
return Object.entries(item);
|
||||
}
|
||||
|
||||
// Convolve
|
||||
|
||||
this.convolve = (kernel, rect = this['get-frame']()) => {
|
||||
@@ -575,6 +615,8 @@ function Library (client) {
|
||||
[-1, -1, -1]]
|
||||
}
|
||||
|
||||
// Points
|
||||
|
||||
this.offset = (a, b) => { // Offsets pos a with pos b, returns a.
|
||||
a.x += b.x
|
||||
a.y += b.y
|
||||
@@ -585,6 +627,8 @@ function Library (client) {
|
||||
return Math.sqrt(((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y)))
|
||||
}
|
||||
|
||||
// Utilities
|
||||
|
||||
this.print = (value) => {
|
||||
client.source.write('ronin-print', 'txt', value, 'text/plain')
|
||||
return value
|
||||
@@ -595,9 +639,9 @@ function Library (client) {
|
||||
return args
|
||||
}
|
||||
|
||||
this.debug = (arg) => { // Print arguments to console.
|
||||
console.log(arg)
|
||||
return arg
|
||||
this.debug = (...args) => { // Print arguments to console.
|
||||
console.log(...args)
|
||||
return args
|
||||
}
|
||||
|
||||
this.time = (rate = 1) => { // Returns timestamp in milliseconds.
|
||||
@@ -608,11 +652,24 @@ function Library (client) {
|
||||
return window
|
||||
}
|
||||
|
||||
// Returns a new function that
|
||||
// Useful when executing JS functions that need a strict `this` context.
|
||||
//
|
||||
// An example:
|
||||
// `(get (get (js) "navigator") "requestMIDIAccess")` in Ronin
|
||||
// should be equivalent to `window.navigator.requestMIDIAccess` in JS.
|
||||
// Executing such retrieved JS method will crash though - as the method
|
||||
// needs an internal `this` context - in exemplary case, window.navigator.
|
||||
//
|
||||
this['js-bind'] = (fn, thisArg, ...args) => {
|
||||
return fn.bind(thisArg, ...args)
|
||||
}
|
||||
|
||||
this.on = (event, f) => { // Triggers on event.
|
||||
client.bind(event, f)
|
||||
}
|
||||
|
||||
this.test = (name, a, b) => {
|
||||
this.test = (name, a, b) => { //nit test. Checks if a is equal to b, logs results to console.
|
||||
if (`${a}` !== `${b}`) {
|
||||
console.warn('failed ' + name, a, b)
|
||||
} else {
|
||||
@@ -634,7 +691,7 @@ function Library (client) {
|
||||
return client.theme.active
|
||||
}
|
||||
|
||||
this['get-frame'] = () => { // Get theme values.
|
||||
this['get-frame'] = () => { // Get frame shape.
|
||||
return client.surface.getFrame()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user