Merge pull request #4 from hundredrabbits/master

sync
This commit is contained in:
Nikolaus Gradwohl 2019-07-20 21:50:23 +02:00 committed by GitHub
commit d6399f2740
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 402 additions and 349 deletions

View File

@ -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

View File

@ -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))))

View File

@ -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 () {

View File

@ -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`)

View File

@ -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<input.length ; i+=2) {
obj[await interpret(input[i] ,context)] = await interpret(input[i+1], context)
}
return obj
}
}
@ -98,6 +119,8 @@ function Lisp (input, lib) {
return { type: TYPES.number, value: parseFloat(input) }
} else if (input[0] === '"' && input.slice(-1) === '"') {
return { type: TYPES.string, value: input.slice(1, -1) }
} else if (input[0] === ':') {
return { type: TYPES.string, value: input.slice(1) }
} else if (input === 'true' || input === 'false') {
return { type: TYPES.bool, value: input === 'true' }
} else {
@ -110,10 +133,18 @@ function Lisp (input, lib) {
const token = input.shift()
if (token === undefined) {
return list.pop()
} else if (token === '\'(') {
input.unshift('__fn')
list.push(parenthesize(input, []))
return parenthesize(input, list)
} else if (token === '{') {
input.unshift('__obj')
list.push(parenthesize(input, []))
return parenthesize(input, list)
} else if (token === '(') {
list.push(parenthesize(input, []))
return parenthesize(input, list)
} else if (token === ')') {
} else if (token === ')' || token === '}') {
return list
} else {
return parenthesize(input, list.concat(categorize(token)))
@ -121,7 +152,18 @@ function Lisp (input, lib) {
}
const tokenize = function (input) {
return input.replace(/^\;.*\n?/gm, '').split('"').map(function (x, i) { return i % 2 === 0 ? x.replace(/\(/g, ' ( ').replace(/\)/g, ' ) ') : x.replace(/ /g, '!whitespace!') }).join('"').trim().split(/\s+/).map(function (x) { return x.replace(/!whitespace!/g, ' ') })
const i = input.replace(/^\;.*\n?/gm, '').split('"')
return i.map(function (x, i) {
return i % 2 === 0 ?
x.replace(/\(/g, ' ( ')
.replace(/\)/g, ' ) ')
.replace(/' \( /g, ' \'( ') // '()
.replace(/\{/g, ' { ') // {}
.replace(/\}/g, ' } ') // {}
: x.replace(/ /g, '!whitespace!')
})
.join('"').trim().split(/\s+/)
.map(function (x) { return x.replace(/!whitespace!/g, ' ') })
}
this.parse = function (input) {
@ -129,6 +171,8 @@ function Lisp (input, lib) {
}
this.toPixels = async function () {
return interpret(this.parse(input))
return interpret(this.parse(`(
(include "./sources/lisp/prelude.lisp")
${input})`))
}
}

View File

@ -66,7 +66,7 @@ function Source (ronin) {
if (!fs.existsSync(loc)) { console.warn('Source', 'File does not exist: ' + loc); return }
console.log('Source', 'Reading ' + loc)
this.path = loc
this.load(fs.readFileSync(this.path, 'utf8'))
ronin.commander.load(fs.readFileSync(this.path, 'utf8'))
ronin.log(`Reading file.`)
}
@ -74,10 +74,6 @@ function Source (ronin) {
ronin.commander.run()
}
this.load = function (data) {
ronin.commander._input.value = data
}
this.quit = function (force = false) {
if (this.hasChanges() === true && force === false) {
this.verify()

View File

@ -1,5 +1,5 @@
; animate
(
(clear)
(def t
(sin
@ -14,4 +14,4 @@
(stroke
(square pos) 1 "red")
; set false to stop
(animate true))
(animate true)

View File

@ -1,31 +1,26 @@
(echo (map (lambda (a) (add a 1)) (1 2 3)))
(echo (map '(add %1 1) (1 2 3)))
(
(echo (first (1 2 3)))
(echo (rest (1 2 3)))
)
(echo
(filter
(lambda (a) (eq 0 (mod a 2)))
'(eq 0 (mod %1 2))
(1 2 3 4 5))
)
(
(clear)
(map (lambda (a)
(stroke (rect (mul a 30) 20 50 50)
1 "red"))
(map
'(stroke (rect (mul a 30) 20 50 50)
1 "red")
(range 0 20 5))
)
(
(clear)
(map (lambda (a)
(stroke
(map
'(stroke
(rect
(mul a 10)
(add 50 (mul (sin a) 40))
a
(add 20 (mul (cos a) 50))) 1 "red"))
(range 0 200 5)))
(mul %1 10)
(add 250 (mul (sin %1) 250))
(mul 4 %1)
(add 20 (mul (cos %1) 50))) 1 "red")
(range 0 200 5))

View File

@ -1,9 +1,9 @@
; basics
(
; define a variable
(def a 25)
(echo a)
; define a function
(defn add-two (a) (add 2 a))
(echo (add-two 4)))
(echo (add-two 4))

View File

@ -0,0 +1,14 @@
; filesystem
; print path
(echo
(filepath))
; print folder path
(echo
(dirpath))
; print file content
(echo
(file))
; print folder content
(echo
(dir))

View File

@ -1,6 +1,5 @@
; benchmark
(
; Basics
(test "add" (add 8 4 2) 14)
@ -53,9 +52,8 @@
; Generics
(test "str" (str 1 4 "-" (add 3 4) ".jpg") "14-7.jpg")
(test "concat" (concat 1 4 "-" (add 3 4) ".jpg") "14-7.jpg")
; Interop
(test "interop" ((of (of js "Math") "max") 2 4) 4)
(test "recursive key selector" ((of js "Math" "max") 2 4) 4)
)
(test "interop" ((of (of (js) "Math") "max") 2 4) 4)
(test "recursive key selector" ((of (js) "Math" "max") 2 4) 4)

View File

@ -1,7 +1,5 @@
; crop
(
(clear)
(open "../static/crystal.jpg")
(crop (rect 100 100 400 400))
)

View File

@ -1,6 +1,5 @@
; dejong attractor
(
(clear)
(defn point (x y color)
(fill (rect x y 1 1) color))
@ -25,11 +24,10 @@
(2 1)
)
)
(benchmark (lambda ()
(dejong 12800
(benchmark
'(dejong 12800
(random -2 2)
(random -2 2)
(random -2 2)
(random -2 2)
)))
)
))

View File

@ -1,14 +0,0 @@
; filesystem
(
; get files
(def files
(dir
(dirpath)))
; pick a random file
(def random-index
(floor
(random
(len files))))
; print random file name
(echo
(get files random-index)))

View File

@ -1,25 +1,18 @@
; pixels
(
(clear)
; Glitch
(clear)
(defn glitch
(rec)
(if (gt rec 1)
((clone
(rect (random 400) (random 400) 2 2)
(rect (random 400) (random 400)
(random 10) (random 30)))
(glitch (sub rec 1))))
)
; Draw photo
(
(translate
(rect (random 400) (random 400) (random 10) (random 10))
(pos (random 400) (random 400)))
(glitch (sub rec 1)))))
(import
"../static/crystal.jpg"
(rect 0 0 400 400))
(glitch 500)
)

View File

@ -1,4 +1,3 @@
(
; gradients
(clear)
@ -13,4 +12,3 @@
(gradient
(50 0 180 0)
("black" "white" "blue" "green")))
)

View File

@ -1,5 +1,4 @@
; guides
(
(clear)
(stroke
(frame) 1 "red")
@ -54,4 +53,4 @@
(frame) "w")
(div
(of
(frame) "h") 2))) 1 "#72dec2"))
(frame) "h") 2))) 1 "#72dec2")

View File

@ -1,5 +1,5 @@
(
(clear)
(def a (import
"../static/crystal.jpg"
(rect 0 0 400 400)))
(echo a))
(echo a)

View File

@ -1,4 +1,3 @@
; include
(
(include "../examples/recursive.lisp")
(echo line-color))
(echo line-color)

1
examples/lambda.lisp Normal file
View File

@ -0,0 +1 @@
(echo (map '(add %1 2) (4 5 6))

15
examples/objects.lisp Normal file
View File

@ -0,0 +1,15 @@
; objects
(test "symbols" :a "a")
(def ob {:a "fantastic" :b 2})
((of (js) :console :log) ob)
(echo (of ob :a))
(echo (keys ob))
(echo (values ob))
(set ob :a 4)
(echo (of ob :a))

View File

@ -1,9 +1,7 @@
; scale file
(
; saturate image
(open "../static/crystal.jpg")
(pixels
(frame)
saturation
12)
)

View File

@ -1,7 +1,7 @@
; pixels
(
(clear)
(import "../../PREVIEW.jpg"
(frame))
(pixels
(rect 0 0 500 500) saturation 0.5))
(rect 0 0 500 500) saturation 0.5)

14
examples/random.file.lisp Normal file
View File

@ -0,0 +1,14 @@
; filesystem
; get files
(def files
(dir
(dirpath)))
; pick a random file
(def random-index
(floor
(random
(len files))))
; print random file name
(echo
(get files random-index))

View File

@ -1,5 +1,5 @@
; random
(
(clear)
(defn place
(rec)
@ -14,4 +14,4 @@
(random 200)))
(place
(sub rec 1)))))
(place 30))
(place 30)

View File

@ -1,5 +1,5 @@
; recursive
(
(clear)
(defn rec
(v)
@ -13,4 +13,4 @@
(mul 5 v)) 1 "red")
(rec
(sub v 5)))))
(rec 100))
(rec 100)

View File

@ -1,5 +1,5 @@
; resize
(
(clear)
(open "../../PREVIEW.jpg")
(resize 0.5 0.5))
(resize 0.5 0.5)

View File

@ -1,6 +1,6 @@
; Shapes
((clear)
(clear)
; variables
(def center-w (div (of (frame) "w") 2))
@ -22,4 +22,3 @@
(pos (sub center-w rad) center-h)
(pos (add center-w rad) center-h)))
(stroke (text 10 170 200 "HELL") 2 "pink")
)

View File

@ -1,6 +1,6 @@
; animated recusive spiral
; by @local_guru
(
(clear)
(defn rec
(v)
@ -27,4 +27,4 @@
(sub v 0.3)))))
; set false to stop
(animate true)
(rec 300))
(rec 300)

View File

@ -1,8 +1,8 @@
(
(clear)
; ronin path
(stroke
(svg "M60,60 L195,60 A45,45 0 0,1 240,105 A45,45 0 0,1 195,150 L60,150 M195,150 A45,45 0 0,1 240,195 L240,240 ") 2 "white")
; outline
(stroke
(svg "M15,15 L15,15 L285,15 L285,285 L15,285 Z") 1 "#555"))
(svg "M15,15 L15,15 L285,15 L285,285 L15,285 Z") 1 "#555")

View File

@ -1,5 +1,5 @@
; theme
(
(clear)
(def col
(lambda
@ -35,4 +35,4 @@
(rec
(sub v 3)
(add i 1))))))
(rec 40 0))
(rec 40 0)