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:
parent
8d23e5264e
commit
0cebbe52cb
60
README.txt
60
README.txt
@ -59,11 +59,16 @@ To save an image in memory, open an image file with Ronin, or drag an image file
|
||||
|
||||
Library
|
||||
|
||||
Files
|
||||
|
||||
- (open name ~scale) Imports a graphic file with format.
|
||||
- (import name ~shape) Imports a graphic file with format.
|
||||
- (export ~format ~quality) Exports a graphic file with format.
|
||||
- (files) Returns the list of loaded files.
|
||||
- (print string) Exports string to file.
|
||||
|
||||
Shapes
|
||||
|
||||
- (pos ~x ~y) Returns a position shape.
|
||||
- (line ax ay bx by) Returns a line shape.
|
||||
- (size w h) Returns a size shape.
|
||||
@ -74,6 +79,9 @@ Library
|
||||
- (poly ...pos) Returns a poly shape.
|
||||
- (text x y p t ~a ~f) Returns a text shape.
|
||||
- (svg x y d) Returns a svg shape.
|
||||
|
||||
Canvas operations
|
||||
|
||||
- (color r g b ~a) Returns a color object.
|
||||
- (hsl h s l ~a) returns a HSL color object
|
||||
- (resize ~w) Resizes the canvas to target w and h, returns the rect.
|
||||
@ -92,6 +100,9 @@ Library
|
||||
- (clear ~rect) Clears a rect.
|
||||
- (gradient line ~colors 'black']) Defines a gradient color.
|
||||
- (guide shape color) Draws a shape on the guide layer.
|
||||
|
||||
Pixel operations
|
||||
|
||||
- (pixels fn ~q ~rect)
|
||||
- (saturation pixel q) Change the saturation of pixels.
|
||||
- (contrast pixel q) Change the contrast of pixels.
|
||||
@ -100,8 +111,14 @@ Library
|
||||
- (multiply pixel q) Change the color balance of pixels.
|
||||
- (normalize pixel q) Normalize the color of pixels with another color.
|
||||
- (lum color) Return the luminance of a color.
|
||||
|
||||
Strings
|
||||
|
||||
- (concat ...items) Concat multiple strings.
|
||||
- (split string char) Split string at character.
|
||||
|
||||
Math
|
||||
|
||||
- (add ...args) Adds values.
|
||||
- (sub ...args) Subtracts values.
|
||||
- (mul ...args) Multiplies values.
|
||||
@ -125,38 +142,71 @@ Library
|
||||
- (PI)
|
||||
- (TWO_PI)
|
||||
- (random ...args)
|
||||
|
||||
Logic
|
||||
|
||||
- (gt a b) Returns true if a is greater than b, else false.
|
||||
- (lt a b) Returns true if a is less than b, else false.
|
||||
- (eq a b) Returns true if a is equal to b, else false.
|
||||
- (and ...args) Returns true if all conditions are true.
|
||||
- (or a b ...rest) Returns true if at least one condition is true.
|
||||
- (not a) Negation. Returns true if a is false. Returns false if a is true.
|
||||
- (while fn action) While loop. Execute action for as long as fn is true.
|
||||
|
||||
Language
|
||||
- (let name value)
|
||||
- (def name value)
|
||||
- (defn fname ~(...fnparams) ...instructions)
|
||||
- (λ (...args) ...instructions)
|
||||
- (if (condition) ...instruction-when-true ~...instruction-when-false)
|
||||
|
||||
Lists
|
||||
|
||||
- (each arr fn) Run a function for each element in a list.
|
||||
- (map arr fn) Run a function on each element in a list.
|
||||
- (filter arr fn) Remove from list, when function returns false.
|
||||
- (reduce arr fn acc)
|
||||
- (len item) Returns the length of a list.
|
||||
- (cons arr ...items) Returns a new array with the items appended.
|
||||
- (push arr ...items) Appends the items into the existing list.
|
||||
- (pop arr) Pop the last item from the list and return the item.
|
||||
- (first arr) Returns the first item of a list.
|
||||
- (last arr) Returns the last
|
||||
- (rest [_ ...arr])
|
||||
- (range start end ~step)
|
||||
- (rest [_ ...arr]) Returns all arguments except the first
|
||||
- (range start end ~step) Returns a list of numbers counting from start to end. Step defaults to 1.
|
||||
|
||||
Objects (maps)
|
||||
|
||||
- (get item key) Gets an object's parameter with name.
|
||||
- (set item ...args) Sets an object's parameter with name as value.
|
||||
- (of h ...keys) Gets object parameters with names.
|
||||
- (object ...entries) Creates an object with provided entries.
|
||||
- (keys item) Returns a list of the object's keys
|
||||
- (values item) Returns a list of the object's values
|
||||
- (convolve kernel ~rect)
|
||||
|
||||
Convolution filters
|
||||
|
||||
- (convolve kernel ~rect) Apply convolution filter with given kernel on an area.
|
||||
- (blur) Returns the blur kernel.
|
||||
- (sharpen) Returns the sharpen kernel.
|
||||
- (edge) Returns the edge kernel.
|
||||
|
||||
Points
|
||||
|
||||
- (offset a b) Offsets pos a with pos b, returns a.
|
||||
- (distance a b) Get distance between positions.
|
||||
|
||||
Utilities
|
||||
|
||||
- (echo ...args) Print arguments to interface.
|
||||
- (debug arg) Print arguments to console.
|
||||
- (time ~rate) Returns timestamp in milliseconds.
|
||||
- (js) Javascript interop.
|
||||
- (js) Javascript interop. Returns window object.
|
||||
- (on event f) Triggers on event.
|
||||
- (test name a b)
|
||||
- (test name a b) Unit test. Checks if a is equal to b, logs results to console.
|
||||
- (benchmark fn) Logs time taken to execute a function.
|
||||
- (get-theme) Returns an object with current theme colors.
|
||||
- (get-frame) Returns a shape object describing the current canvas.
|
||||
|
||||
Extras
|
||||
|
||||
|
@ -35,9 +35,9 @@
|
||||
|
||||
;
|
||||
(defn redraw ()
|
||||
(
|
||||
|
||||
(clear)
|
||||
(rec 300)))
|
||||
(rec 300))
|
||||
|
||||
;
|
||||
(on "animate" redraw)
|
@ -3,6 +3,9 @@
|
||||
;
|
||||
(clear)
|
||||
|
||||
(def frame
|
||||
(get-frame))
|
||||
|
||||
;
|
||||
(def gradient-line
|
||||
(line frame:c 0 frame:c frame:h))
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
(clear)
|
||||
|
||||
(def frame
|
||||
(get-frame))
|
||||
|
||||
|
||||
; times
|
||||
|
||||
@ -26,13 +29,13 @@
|
||||
; position on a circle from angle
|
||||
|
||||
(defn circle-pos
|
||||
(cx cy r a) {:x
|
||||
(cx cy r a) (object "x"
|
||||
(add cx
|
||||
(mul r
|
||||
(cos a))) :y
|
||||
(cos a))) "y"
|
||||
(add cy
|
||||
(mul r
|
||||
(sin a)))})
|
||||
(sin a)))))
|
||||
|
||||
|
||||
; draw
|
||||
@ -42,10 +45,10 @@
|
||||
(
|
||||
(stroke
|
||||
(line cx cy
|
||||
(:x
|
||||
(circle-pos cx cy r a))
|
||||
(:y
|
||||
(circle-pos cx cy r a))) "white" 2)))
|
||||
(get
|
||||
(circle-pos cx cy r a) "x")
|
||||
(get
|
||||
(circle-pos cx cy r a) "y")) "white" 2)))
|
||||
|
||||
;
|
||||
(defn draw-star
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
(def theme
|
||||
(get-theme))
|
||||
|
||||
(def frame
|
||||
(get-frame))
|
||||
|
||||
; ex: theme:f_high
|
||||
|
||||
|
@ -1,5 +1,11 @@
|
||||
(clear)
|
||||
|
||||
(def theme
|
||||
(get-theme))
|
||||
|
||||
(def frame
|
||||
(get-frame))
|
||||
|
||||
(defn branch
|
||||
(v)
|
||||
(if
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
(clear)
|
||||
|
||||
(def theme
|
||||
(get-theme))
|
||||
|
||||
(transform:move 150 150)
|
||||
|
||||
(fill
|
||||
|
168
examples/events/webmidi.lisp
Normal file
168
examples/events/webmidi.lisp
Normal file
@ -0,0 +1,168 @@
|
||||
;A simple MIDI visualiser
|
||||
;showing activity per note
|
||||
;and channel.
|
||||
|
||||
(clear)
|
||||
|
||||
(def theme
|
||||
(get-theme))
|
||||
|
||||
(resize 1200 600)
|
||||
|
||||
(def maxcirclesize 50)
|
||||
|
||||
(def mincirclesize 20)
|
||||
|
||||
(def circlexdist 40)
|
||||
|
||||
(def circleydist 30)
|
||||
|
||||
(def notes
|
||||
(object 0 "A" 1 "A#" 2 "B" 3 "C" 4 "C#" 5 "D" 6 "D#" 7 "E" 8 "F" 9 "F#" 10 "G" 11 "G#"))
|
||||
|
||||
(def sharpnotes
|
||||
(object 1 "A#" 4 "C#" 6 "D#" 9 "F#" 11 "G#"))
|
||||
|
||||
(def frame
|
||||
(get-frame))
|
||||
|
||||
(def jswindow
|
||||
(js))
|
||||
|
||||
(defn isblackkey
|
||||
(num)
|
||||
(def distfromA0
|
||||
(sub num 21))
|
||||
(def semitonenum
|
||||
(mod distfromA0 12))
|
||||
(not
|
||||
(eq
|
||||
(get sharpnotes semitonenum) undefined)))
|
||||
|
||||
(defn circlebynotenum
|
||||
(num)
|
||||
(circle
|
||||
(mul
|
||||
(sub num 47) circlexdist)
|
||||
(if
|
||||
(isblackkey num) circleydist
|
||||
(mul 2.5 circleydist)) mincirclesize))
|
||||
|
||||
(def reactivecircles
|
||||
(reduce
|
||||
(range 48 76)
|
||||
(λ
|
||||
(acc num index)
|
||||
(set acc num
|
||||
(circlebynotenum num)))
|
||||
(object)))
|
||||
|
||||
(def channelcircles
|
||||
(map
|
||||
(range 0 15)
|
||||
(λ
|
||||
(num)
|
||||
(circle
|
||||
(add
|
||||
(mul num circlexdist 1.25) circlexdist) 200 mincirclesize))))
|
||||
|
||||
(defn js-exec
|
||||
(obj fname listargs)
|
||||
(def boundfunction
|
||||
(js-bind
|
||||
(get obj fname) obj))
|
||||
(def result
|
||||
(apply boundfunction
|
||||
(if
|
||||
(eq listargs undefined) () listargs))) result)
|
||||
|
||||
(defn midimsghandler
|
||||
(midiMessage)
|
||||
(def eventType
|
||||
(get
|
||||
(:data midiMessage) "0"))
|
||||
;zero based
|
||||
(def channelNum
|
||||
(logand eventType 15))
|
||||
;ignore clock in debug to keep things cleaner
|
||||
(if
|
||||
(not
|
||||
(eq eventType 248))
|
||||
(debug "incoming MIDI:" "CH" channelNum
|
||||
(:data midiMessage)))
|
||||
(def noteNum
|
||||
(get
|
||||
(:data midiMessage) "1"))
|
||||
(def noteVelocity
|
||||
(get
|
||||
(:data midiMessage) "2"))
|
||||
(set
|
||||
(get channelcircles channelNum) "r"
|
||||
(add mincirclesize
|
||||
(mul
|
||||
(sub maxcirclesize mincirclesize)
|
||||
(div noteVelocity 100))))
|
||||
(set
|
||||
(or
|
||||
(get reactivecircles noteNum)()) "r"
|
||||
(add mincirclesize
|
||||
(mul
|
||||
(sub maxcirclesize mincirclesize)
|
||||
(div noteVelocity 100)))))
|
||||
|
||||
(defn midiokhandler
|
||||
(midiAccess)
|
||||
(def midiInputs
|
||||
(js-exec
|
||||
(:inputs midiAccess) "values"))
|
||||
(eachof midiInputs
|
||||
(λ
|
||||
(input id)
|
||||
(debug "Setting listener on"
|
||||
(:name input)
|
||||
(:manufacturer input))
|
||||
(set input "onmidimessage" midimsghandler))))
|
||||
|
||||
(defn midierrhandler
|
||||
(err)
|
||||
(debug "midierrhandler" err))
|
||||
|
||||
(js-exec
|
||||
(js-exec
|
||||
(:navigator jswindow) "requestMIDIAccess") "then"
|
||||
(list midiokhandler midierrhandler))
|
||||
|
||||
(defn drawcircle
|
||||
(arglist)
|
||||
(def notenum
|
||||
(first arglist))
|
||||
(def i
|
||||
(last arglist))
|
||||
(if
|
||||
(gt
|
||||
(:r i) mincirclesize)
|
||||
(set i "r"
|
||||
(sub
|
||||
(:r i) 0.6)))
|
||||
(fill i
|
||||
(if
|
||||
(isblackkey notenum)
|
||||
(theme:f_med)
|
||||
(theme:f_low))))
|
||||
|
||||
(defn redraw ()
|
||||
(clear)
|
||||
(each
|
||||
(entries reactivecircles) drawcircle)
|
||||
(each channelcircles
|
||||
(λ
|
||||
(s i)
|
||||
(fill s theme:b_high)
|
||||
(fill
|
||||
(text
|
||||
(sub s:cx mincirclesize)
|
||||
(add s:cy mincirclesize 18) 18
|
||||
(concat "CH" i)) theme:b_inv 2))))
|
||||
|
||||
;
|
||||
(on "animate" redraw)
|
3
examples/not-implemented-yet/README.md
Normal file
3
examples/not-implemented-yet/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Not implemented (yet)
|
||||
|
||||
This set of examples shows the limitations of Ronin's LISP.
|
44
examples/not-implemented-yet/object-symbols.lisp
Normal file
44
examples/not-implemented-yet/object-symbols.lisp
Normal file
@ -0,0 +1,44 @@
|
||||
;To inspect the results of these tests,
|
||||
;open your browser's debugging tools
|
||||
;
|
||||
(usually F12)
|
||||
and navigate to the
|
||||
;JavaScript console.
|
||||
(clear)
|
||||
|
||||
(def mydog
|
||||
(object "color" "gold" "coat" "long" :speed "quick" :health "good"))
|
||||
|
||||
(debug mydog)
|
||||
|
||||
(test "My dog's color is"
|
||||
(get mydog "color") "gold")
|
||||
|
||||
(test "My dog's coat is"
|
||||
(get mydog "coat") "long")
|
||||
|
||||
(test "My dog's speed is"
|
||||
(get mydog "speed") "quick")
|
||||
|
||||
;the last one passes only because :health
|
||||
;in the set instruction above
|
||||
;resolves to undefined - and
|
||||
;technically you can have one object value
|
||||
;for key=undefined
|
||||
(test "My dog's health is"
|
||||
(get mydog :health) "good")
|
||||
|
||||
;You can, however, use obj:param syntax to
|
||||
;get properties of objects.
|
||||
;A shorthand for
|
||||
(get obj "param")
|
||||
.
|
||||
;
|
||||
(test "Get color" mydog:color "gold")
|
||||
|
||||
;Also,
|
||||
(:coat mydog)
|
||||
|
||||
;is another shorthand.
|
||||
(test "Get coat shorthand function"
|
||||
(:coat mydog) "long")
|
@ -2,17 +2,31 @@
|
||||
|
||||
(clear)
|
||||
|
||||
(defn glitch
|
||||
(rec)
|
||||
(if (gt rec 1)
|
||||
(
|
||||
(translate
|
||||
(rect (random 400) (random 400) (random 10) (random 10))
|
||||
(pos (random 400) (random 400)))
|
||||
(glitch (sub rec 1)))))
|
||||
|
||||
(import
|
||||
"../static/crystal.jpg"
|
||||
(import $path
|
||||
(rect 0 0 400 400))
|
||||
|
||||
(defn translate
|
||||
(source-rect dest-pos)
|
||||
(
|
||||
(paste
|
||||
(copy source-rect)
|
||||
(rect dest-pos:x dest-pos:y source-rect:w source-rect:h))))
|
||||
|
||||
(defn glitch
|
||||
(rec)
|
||||
(if
|
||||
(gt rec 1)
|
||||
(
|
||||
(translate
|
||||
(rect
|
||||
(random 1 400)
|
||||
(random 1 400)
|
||||
(random 1 10)
|
||||
(random 1 10))
|
||||
(pos
|
||||
(random 1 400)
|
||||
(random 1 400)))
|
||||
(glitch
|
||||
(sub rec 1)))))
|
||||
|
||||
(glitch 500)
|
@ -1,6 +1,12 @@
|
||||
; Normalize photo colors
|
||||
|
||||
(open $path 0.5)
|
||||
|
||||
;(pick (rect 0 0 100 100)) will return the average color
|
||||
;of 100x100px rectangle.
|
||||
;without extra arguments,
|
||||
;pick grabs the whole canvas by default,
|
||||
;and calculates the average color.
|
||||
(def average-color
|
||||
(pick))
|
||||
(pixels normalize average-color)
|
@ -1,4 +1,4 @@
|
||||
; saturate image
|
||||
(open "../static/crystal.jpg")
|
||||
(pixels
|
||||
(frame) saturation 12)
|
||||
(open $path)
|
||||
(pixels saturation 12
|
||||
(get-frame))
|
@ -2,7 +2,7 @@
|
||||
; drag an image on the window
|
||||
(open $path)
|
||||
;
|
||||
(pixels
|
||||
(rect 100 100 400 400) saturation 0)
|
||||
(pixels
|
||||
(rect 300 300 400 400) contrast 0.5)
|
||||
(pixels saturation 0
|
||||
(rect 100 100 400 400))
|
||||
(pixels contrast 0.5
|
||||
(rect 300 300 400 400))
|
@ -6,7 +6,7 @@
|
||||
(if
|
||||
(gt rec 0)
|
||||
(
|
||||
(import "../static/crystal.jpg"
|
||||
(import $path
|
||||
(rect
|
||||
(random 200)
|
||||
(random 200)
|
||||
|
@ -18,63 +18,10 @@
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(def color-2
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(def color-3
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(def color-4
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(def color-5
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(def color-6
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(def color-7
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(def color-8
|
||||
(pick
|
||||
(guide
|
||||
(rect $xy unit unit))))
|
||||
(echo color-1)
|
||||
|
||||
; display
|
||||
|
||||
(fill
|
||||
(circle
|
||||
(mul 20 2) pos-row-1 18) color-1)
|
||||
(fill
|
||||
(circle
|
||||
(mul 20 4) pos-row-1 18) color-2)
|
||||
(fill
|
||||
(circle
|
||||
(mul 20 6) pos-row-1 18) color-3)
|
||||
(fill
|
||||
(circle
|
||||
(mul 20 8) pos-row-1 18) color-4)
|
||||
(fill
|
||||
(circle
|
||||
(mul 20 3) pos-row-2 18) color-5)
|
||||
(fill
|
||||
(circle
|
||||
(mul 20 5) pos-row-2 18) color-6)
|
||||
(fill
|
||||
(circle
|
||||
(mul 20 7) pos-row-2 18) color-7)
|
||||
(fill
|
||||
(circle
|
||||
(mul 20 9) pos-row-2 18) color-8)
|
||||
;
|
||||
(def res
|
||||
(add color-1:hex ":" color-2:hex ":" color-3:hex ":" color-4:hex ":" color-5:hex ":" color-6:hex ":" color-7:hex ":" color-8:hex))
|
||||
(echo
|
||||
(add res ":" res))
|
@ -1,4 +1,4 @@
|
||||
(resize 600 200)
|
||||
(resize 600 800)
|
||||
|
||||
(clear)
|
||||
|
||||
@ -14,6 +14,9 @@
|
||||
(guide
|
||||
(line 0 100 600 100)) colors))
|
||||
|
||||
;collect colors to prepared list,
|
||||
;in particular points from the gradient
|
||||
;marked by the guides
|
||||
(each picked-colors
|
||||
(λ
|
||||
(color id)
|
||||
@ -25,5 +28,33 @@
|
||||
(mul id
|
||||
(div 600 9)) 100)))))))
|
||||
|
||||
;show picked colors as swatches
|
||||
(each picked-colors
|
||||
(λ
|
||||
(color id)
|
||||
(
|
||||
;swatch circle
|
||||
(fill
|
||||
(circle
|
||||
20 (add (mul id
|
||||
(div 600 9)) 300) 18) color)
|
||||
"black")))
|
||||
|
||||
;show picked colors as text
|
||||
(each picked-colors
|
||||
(λ
|
||||
(color id)
|
||||
(
|
||||
(fill
|
||||
(text
|
||||
12 (add (mul id
|
||||
(div 600 9)) 300 5) 24
|
||||
(concat id ": "
|
||||
(get
|
||||
(get picked-colors
|
||||
(concat "" id)) "hex"))) "black"))))
|
||||
|
||||
;get the first color in different formats
|
||||
(echo
|
||||
(get picked-colors:1 "hex"))
|
||||
(get picked-colors:0 "hex")
|
||||
(get picked-colors:0 "rgba"))
|
@ -7,5 +7,8 @@
|
||||
(add
|
||||
(mul index 40) 50) 40 name) "red"))
|
||||
|
||||
;this will display the list of loaded files.
|
||||
;drag a few pictures into Ronin, then eval
|
||||
;this script again.
|
||||
(each
|
||||
(files) print-file)
|
@ -3,6 +3,8 @@
|
||||
;
|
||||
(clear)
|
||||
|
||||
(def frame (get-frame))
|
||||
|
||||
;
|
||||
(def gradient-line
|
||||
(line frame:c 0 frame:c frame:h))
|
||||
|
134
examples/tests/lists.lisp
Normal file
134
examples/tests/lists.lisp
Normal file
@ -0,0 +1,134 @@
|
||||
(test "Native last call - list of numbers"
|
||||
(last
|
||||
(1 2 3)) 3)
|
||||
|
||||
(test "Native last call - list of numbers, 1 element"
|
||||
(last
|
||||
(1)) 1)
|
||||
|
||||
(test "Native last call - list of numbers, no elements"
|
||||
(last ()) undefined)
|
||||
|
||||
(test "Native last call - list of strings, 1 element"
|
||||
(last
|
||||
("abc")) "abc")
|
||||
|
||||
(test "Native last call - list of strings, many elements"
|
||||
(last
|
||||
("ala" "bla" "cla")) "cla")
|
||||
|
||||
;functions defined as defn/lambda args bodyinstrs...
|
||||
|
||||
(defn lastfn
|
||||
(listarg) (debug "some other instruction")
|
||||
(last listarg))
|
||||
|
||||
(test "Proxied last call - list of numbers"
|
||||
(lastfn
|
||||
(1 2 3)) 3)
|
||||
|
||||
(test "Proxied last call - list of numbers, 1 element"
|
||||
(lastfn
|
||||
(1)) 1)
|
||||
|
||||
(test "Proxied last call - list of numbers, no elements"
|
||||
(lastfn ()) undefined)
|
||||
|
||||
(test "Proxied last call - list of strings, 1 element"
|
||||
(lastfn
|
||||
("abc")) "abc")
|
||||
|
||||
(test "Proxied last call - list of strings, many elements"
|
||||
(lastfn
|
||||
("ala" "bla" "cla")) "cla")
|
||||
|
||||
|
||||
|
||||
|
||||
(test "Lambda last call - list of numbers"
|
||||
((λ
|
||||
(listarg) (debug "some other instruction")
|
||||
(last listarg))
|
||||
(1 2 3)) 3)
|
||||
|
||||
(test "Lambda last call - list of numbers, 1 element"
|
||||
((λ
|
||||
(listarg) (debug "some other instruction")
|
||||
(last listarg))
|
||||
(1)) 1)
|
||||
|
||||
(test "Lambda last call - list of numbers, no elements"
|
||||
((λ
|
||||
(listarg) (debug "some other instruction")
|
||||
(last listarg)) ()) undefined)
|
||||
|
||||
(test "Lambda last call - list of strings, 1 element"
|
||||
((λ
|
||||
(listarg) (debug "some other instruction")
|
||||
(last listarg))
|
||||
("abc")) "abc")
|
||||
|
||||
(test "Lambda last call - list of strings, many elements"
|
||||
((λ
|
||||
(listarg) (debug "some other instruction")
|
||||
(last listarg))
|
||||
("ala" "bla" "cla")) "cla")
|
||||
|
||||
|
||||
|
||||
;functions defined as defn/lambda args bodyinstr
|
||||
|
||||
(defn lastfn2
|
||||
(listarg)
|
||||
(last listarg))
|
||||
|
||||
(test "Proxied last call - list of numbers"
|
||||
(lastfn2
|
||||
(1 2 3)) 3)
|
||||
|
||||
(test "Proxied last call - list of numbers, 1 element"
|
||||
(lastfn2
|
||||
(1)) 1)
|
||||
|
||||
(test "Proxied last call - list of numbers, no elements"
|
||||
(lastfn2 ()) undefined)
|
||||
|
||||
(test "Proxied last call - list of strings, 1 element"
|
||||
(lastfn2
|
||||
("abc")) "abc")
|
||||
|
||||
(test "Proxied last call - list of strings, many elements"
|
||||
(lastfn2
|
||||
("ala" "bla" "cla")) "cla")
|
||||
|
||||
|
||||
|
||||
|
||||
(test "Lambda last call - list of numbers"
|
||||
((λ
|
||||
(listarg)
|
||||
(last listarg))
|
||||
(1 2 3)) 3)
|
||||
|
||||
(test "Lambda last call - list of numbers, 1 element"
|
||||
((λ
|
||||
(listarg)
|
||||
(last listarg))
|
||||
(1)) 1)
|
||||
|
||||
(test "Lambda last call - list of numbers, no elements"
|
||||
((λ
|
||||
(listarg)
|
||||
(last listarg)) ()) undefined)
|
||||
|
||||
(test "Lambda last call - list of strings, 1 element"
|
||||
((λ
|
||||
(listarg)
|
||||
(last listarg))
|
||||
("abc")) "abc")
|
||||
|
||||
(test "Lambda last call - list of strings, many elements"
|
||||
((λ
|
||||
(listarg)
|
||||
(last listarg))
|
||||
("ala" "bla" "cla")) "cla")
|
70
index.html
70
index.html
@ -148,14 +148,16 @@ function Lain (lib = {}) {
|
||||
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))
|
||||
return getReturnValue(result)
|
||||
}
|
||||
},
|
||||
λ: function (input, context) {
|
||||
@ -165,13 +167,20 @@ 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))
|
||||
return getReturnValue(result)
|
||||
}
|
||||
},
|
||||
if: function (input, context) {
|
||||
return interpret(input[1], context) ? interpret(input[2], context) : input[3] ? interpret(input[3], context) : []
|
||||
}
|
||||
}
|
||||
const getReturnValue = function (interpretResult) {
|
||||
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)
|
||||
@ -1185,6 +1194,21 @@ function Library (client) {
|
||||
}
|
||||
return Math.random()
|
||||
}
|
||||
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
|
||||
}
|
||||
this.gt = (a, b) => { // Returns true if a is greater than b, else false.
|
||||
return a > b
|
||||
}
|
||||
@ -1211,20 +1235,29 @@ 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
|
||||
}
|
||||
this.while = (fn, action) => {
|
||||
this.while = (fn, action) => { //While loop. Execute action for as long as fn is true.
|
||||
while (fn()) {
|
||||
action()
|
||||
}
|
||||
}
|
||||
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]
|
||||
fn(arg, i)
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
@ -1242,7 +1275,10 @@ function Library (client) {
|
||||
this.len = (item) => { // Returns the length of a list.
|
||||
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)
|
||||
}
|
||||
this.push = (arr, ...items) => { // Appends the items into the existing list.
|
||||
@ -1260,10 +1296,10 @@ function Library (client) {
|
||||
this.last = (arr) => { // Returns the last
|
||||
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) {
|
||||
@ -1277,7 +1313,7 @@ function Library (client) {
|
||||
return arr
|
||||
}
|
||||
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.
|
||||
for (let i = 0; i < args.length; i += 2) {
|
||||
@ -1305,6 +1341,9 @@ function Library (client) {
|
||||
this.values = (item) => { // Returns a list of the object's values
|
||||
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);
|
||||
}
|
||||
this.convolve = (kernel, rect = this['get-frame']()) => {
|
||||
const sigma = kernel.flat().reduce((a, x) => (a + x))
|
||||
const kw = kernel[0].length; const kh = kernel.length
|
||||
@ -1357,9 +1396,9 @@ function Library (client) {
|
||||
client.log(args)
|
||||
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.
|
||||
return (Date.now() * rate)
|
||||
@ -1367,10 +1406,13 @@ function Library (client) {
|
||||
this.js = () => { // Javascript interop.
|
||||
return window
|
||||
}
|
||||
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 {
|
||||
@ -1387,7 +1429,7 @@ function Library (client) {
|
||||
this['get-theme'] = () => { // Get theme values.
|
||||
return client.theme.active
|
||||
}
|
||||
this['get-frame'] = () => { // Get theme values.
|
||||
this['get-frame'] = () => { // Get frame shape.
|
||||
return client.surface.getFrame()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user