Update web version, add a sharable try.html

This commit is contained in:
Nathan Braswell
2020-09-13 19:03:44 -04:00
parent aa75269608
commit 23910ba51e
3 changed files with 222 additions and 47 deletions

View File

@@ -51,7 +51,7 @@
<a name="concept"/>
<h3>Concept:</h3>
<ul>
<li> Minimal, close to the metal Kernel/Scheme (operate on words, bytes, vectors) as AST / core language, with Kernel/Vau calculus inspiration oblivating the need for non-reader macros (<a title="Kernel/Vau calculus thesis" href="https://web.wpi.edu/Pubs/ETD/Available/etd-090110-124904/unrestricted/jshutt.pdf">Kernel/Vau calculus thesis</a>)
<li> Minimal, close to the metal Kernel/Scheme (operate on words, bytes, arrays) as AST / core language, with Kernel/Vau calculus inspiration oblivating the need for non-reader macros (<a title="Kernel/Vau calculus thesis" href="https://web.wpi.edu/Pubs/ETD/Available/etd-090110-124904/unrestricted/jshutt.pdf">Kernel/Vau calculus thesis</a>)
<li> Full Context-free (and eventually, context sensitive) reader macros using FUN-GLL (<a title="fun-gll paper" href="https://www.sciencedirect.com/science/article/pii/S2590118420300058">FUN-GLL paper</a>) to extend language's syntax dynamically
<li> Implement Type Systems as Macros (but using Vaus instead of macros) (<a title="type systems as macros paper 1" href="http://www.ccs.neu.edu/home/stchang/pubs/ckg-popl2017.pdf">paper, up to System Fω</a>) (<a title="type systems as macros paper 2" href="https://www.ccs.neu.edu/home/stchang/pubs/cbtb-popl2020.pdf">second paper, up to dependent types</a>)
<li> Use above "type systems as vaus" to create richer language and embed entire other programming languages (syntax, semantics, and type system) for flawless interop/FFI (C, Go, Lua, JS, etc)
@@ -79,33 +79,66 @@ Note that the current implementation is inefficient, and sometimes has problems
<h4>Vau/Kernel as simple core:</h4>
By constructing our core language on a very simple Vau/Kernel base, we can keep the base truely tiny, and build up normal Lisp functions and programming language features in the language itself. This should help implement other programming languages concisely, and will hopefully make optimization easier and more broadly applicable.
<br>
Below is the current prelude that adds quoting, quasiquoting, syntax for vectors and quoting/quasiquoting, do, if, let, and even lambda itself!
Below is the current prelude that adds quoting, quasiquoting, syntax for arrays and quoting/quasiquoting, do, if, let, and even lambda itself!
<br>
<button onclick="executeKraken(prelude_editor.getValue(), 'prelude_output')"><b>Run</b></button> <br>
<div id="prelude_editor">
(set! current-env (vau de () de))
(set! quote (vau _ (x) x))
(set! lambda (vau se (p b) (wrap (eval (array vau (quote _) p b) se))))
(set! current-env (vau de () de))
(set! fun (vau se (n p b) (eval (array set! n (array lambda p b)) se)))
(add_grammar_rule (quote form) (quote ( "'" optional_WS form )) (vau de (_ _ f) (vector quote (eval f de))))
(add_grammar_rule 'form '( "\\[" optional_WS space_forms optional_WS "\\]" ) (vau de (_ _ fs _ _) (concat (vector vector) (eval fs de))))
; do_helper is basically mapping eval over statements, but the last one is in TCO position
; a bit of a hack, using cond to sequence (note the repitition of the eval in TCO position if it's last,
; otherwise the same eval in cond position, and wheather or not it returns a truthy value, it recurses in TCO position)
(fun do_helper (s i se) (cond (= i (len s)) nil
(= i (- (len s) 1)) (eval (idx s i) se)
(eval (idx s i) se) (do_helper s (+ i 1) se)
true (do_helper s (+ i 1) se)))
(set! do (vau se (& s) (do_helper s 0 se)))
(fun concat_helper (a1 a2 a3 i) (cond (< i (len a1)) (do (set-idx! a3 i (idx a1 i)) (concat_helper a1 a2 a3 (+ i 1)))
(< i (+ (len a1) (len a2))) (do (set-idx! a3 i (idx a2 (- i (len a1)))) (concat_helper a1 a2 a3 (+ i 1)))
true a3))
(fun concat (a1 a2) (concat_helper a1 a2 (array-with-len (+ (len a1) (len a2))) 0))
(add_grammar_rule (quote form) (quote ( "'" optional_WS form )) (vau de (_ _ f) (array quote (eval f de))))
(add_grammar_rule 'form '( "\\[" optional_WS space_forms optional_WS "\\]" ) (vau de (_ _ fs _ _) (concat (array array) (eval fs de))))
(fun vapply (f p ede) (eval (concat [f] p) ede))
(fun lapply (f p) (eval (concat [(unwrap f)] p) (current-env)))
(set! vapply (vau de (f p ede) (eval (concat [(eval f de)] (eval p de)) (eval ede de))))
(set! let1 (vau de (s v b) (eval [[vau '_ [s] b] (eval v de)] de)))
(set! let (vau de (vs b) (cond (= (len vs) 0) (eval b de) true (vapply let1 [(idx vs 0) (idx vs 1) [let (slice vs 2 -1) b]] de))))
;(set! lambda (vau se (p b) (let1 f (eval [vau '_ p b] se) (vau de (& op) (vapply f (map (vau dde (ip) (eval (eval ip dde) de)) op) se)))))
(set! lambda (vau se (p b) (wrap (eval [vau '_ p b] se))))
(set! fun (vau se (n p b) (eval [set! n [lambda p b]] se)))
(fun lapply (f p) (eval (concat [(unwrap f)] p) (current-env)))
(fun do (& params) (cond
(= 0 (len params)) nil
true (idx params (- (len params) 1))))
(set! if (vau de (con than & else) (cond
(eval con de) (eval than de)
(> (len else) 0) (eval (idx else 0) de)
true nil)))
(fun map (f l)
(let (helper (lambda (f l n i recurse)
(if (= i (len l))
n
(do (set-idx! n i (f (idx l i)))
(recurse f l n (+ i 1) recurse)))))
(helper f l (array-with-len (len l)) 0 helper)))
(fun flat_map (f l)
(let (helper (lambda (f l n i recurse)
(if (= i (len l))
n
(recurse f l (concat n (f (idx l i))) (+ i 1) recurse))))
(helper f l (array) 0 helper)))
(fun map_with_idx (f l)
(let (helper (lambda (f l n i recurse)
(if (= i (len l))
n
(do (set-idx! n i (f i (idx l i)))
(recurse f l n (+ i 1) recurse)))))
(helper f l (array-with-len (len l)) 0 helper)))
(fun print_through (x) (let (_ (println x)) x))
(fun is_pair? (x) (and (vector? x) (> (len x) 0)))
(fun print_through (x) (do (println x) x))
(fun is_pair? (x) (and (array? x) (> (len x) 0)))
(set! quasiquote (vau de (x)
(cond (is_pair? x)
@@ -122,14 +155,16 @@ Note that the current implementation is inefficient, and sometimes has problems
(add_grammar_rule 'form '("~" optional_WS form) (lambda (_ _ f) ['unquote f]))
(add_grammar_rule 'form '("," optional_WS form) (lambda (_ _ f) ['splice-unquote f]))
(println "now with both vector and quasiquote syntax, check out " `(1 2 3 ~(+ 7 8) ,[ 5 6 7]))
(println "now with both array and quasiquote syntax, check out " `(1 2 3 ~(+ 7 8) ,[ 5 6 7]))
</div>
<h4>Output:</h4>
<textarea id="prelude_output">Output will appear here</textarea>
<a name="method_example"/>
<h4>Method Example:</h4>
Let's use our meta system (attaching objects to other objects) to implement basic objects/methods.
We will attach a vector of alternating symbols / functions (to make this example simple, since maps aren't built in) to our data as the meta, then look up methods on it when we perform a call. The add_grammar_rule function modifies the grammar/parser currently being used to parse the file and operates as a super-powerful reader macro. We use it in this code to add a rule that transforms <pre><code>a.b(c, d)</code></pre> into <pre><code>(method-call a 'b c d)</code></pre> where method-call is the function that looks up the symbol 'b on the meta object attached to a and calls it with the rest of the parameters.
Let's use our meta system (attaching objects to other objects) to implement basic objects/methods, a new lambda syntax, a new block syntax, and string interpolation!
We will attach a array of alternating symbols / functions (to make this example simple, since maps aren't built in) to our data as the meta, then look up methods on it when we perform a call. The add_grammar_rule function modifies the grammar/parser currently being used to parse the file and operates as a super-powerful reader macro. We use it in this code to add a rule that transforms <pre><code>a.b(c, d)</code></pre> into <pre><code>(method-call a 'b c d)</code></pre> where method-call is the function that looks up the symbol 'b on the meta object attached to a and calls it with the rest of the parameters.
Note also the block ({}) syntax that translates to nested do/let expressions, the nicer lambda syntax, and the string interpolation (that even works nested!).
<br>
<button onclick="executeKraken(method_editor.getValue(), 'method_output')"><b>Run</b></button>
<br>
@@ -139,9 +174,9 @@ Note that the current implementation is inefficient, and sometimes has problems
; First quick lookup function, since maps are not built in
(fun get-value-helper (dict key i) (if (>= i (len dict))
nil
(if (= key (idx dict i))
(idx dict (+ i 1))
(get-value-helper dict key (+ i 2)))))
(if (= key (idx (idx dict i) 0))
(idx (idx dict i) 1)
(get-value-helper dict key (+ i 1)))))
(fun get-value (dict key) (get-value-helper dict key 0))
; Our actual method call function
@@ -150,33 +185,92 @@ Note that the current implementation is inefficient, and sometimes has problems
(println "no method " method)
(lapply method_fn (concat [object] arguments)))))
; Some nice syntactic sugar for method calls
; No params
(add_grammar_rule 'form ['form "\\." 'atom]
(lambda (o _ m) `(method-call ~o '~m)))
; params
(add_grammar_rule 'form ['form "\\." 'atom 'optional_WS "\\(" 'optional_WS 'space_forms 'optional_WS "\\)"]
(lambda (o _ m _ _ _ p _ _) `(method-call ~o '~m ,p)))
; Ok, let's create our object by hand for this example
(set! actual_obj (with-meta [0] [
'inc (lambda (o) (set-idx! o 0 (+ (idx o 0) 1)))
'dec (lambda (o) (set-idx! o 0 (- (idx o 0) 1)))
'set (lambda (o n) (set-idx! o 0 n))
'get (lambda (o) (idx o 0))
]))
(do
; Use our new sugar
actual_obj.set(1337)
actual_obj.inc()
(println "get: " actual_obj.get())
actual_obj.dec()
(println "get: " actual_obj.get())
; object creation
(fun make_constructor (members methods)
(eval `(lambda ~members
(with-meta [,members]
[,(map_with_idx (lambda (i x) [array `'~x (lambda (o) (idx o i))]) members)
,(map (lambda (x) [array `'~(idx x 0) (idx x 1)]) methods)]))))
; Use methods directly
(method-call actual_obj 'set 654)
(method-call actual_obj 'inc)
(println "get: " (method-call actual_obj 'get))
(method-call actual_obj 'dec)
(method-call actual_obj 'dec)
(println "get: " (method-call actual_obj 'get))
; object syntax
(add_grammar_rule 'form ["obj" 'WS 'atom "\\(" ['optional_WS 'atom] * 'optional_WS "\\)" 'optional_WS "{" 'optional_WS ['atom 'optional_WS 'form 'optional_WS] * "}"] (lambda (_ _ name _ members _ _ _ _ _ methods _)
`(set! ~name (make_constructor [,(map (lambda (x) `'~(idx x 1)) members)]
[,(map (lambda (x) `['~(idx x 0) ~(idx x 2)]) methods)]))))
nil)
; Lambda syntax
(add_grammar_rule 'form ["\\|" 'optional_WS [ 'atom 'optional_WS ] * "\\|" 'optional_WS 'form ]
(lambda (_ _ params _ _ body) `(lambda (,(map (lambda (x) (idx x 0)) params)) ~body)))
; {} body translated to do and let
(add_grammar_rule 'block_member [ 'form ] |x| [x])
(add_grammar_rule 'block_member [ "let" 'optional_WS 'atom 'optional_WS "=" 'optional_WS 'form ]
|_ _ name _ _ _ rhs| `(~name ~rhs))
(fun construct_body (is_do current to_add i)
(if (> (len to_add) i)
(cond (and is_do (= (len (idx to_add i)) 1)) (construct_body true (concat current [(idx (idx to_add i) 0)]) to_add (+ i 1))
(= (len (idx to_add i)) 1) (concat current [(construct_body true [do (idx (idx to_add i) 0)] to_add (+ i 1))])
true (concat current [(construct_body false [let [(idx (idx to_add i) 0) (idx (idx to_add i) 1)] ] to_add (+ i 1))]))
current))
(add_grammar_rule 'form ["{" 'optional_WS [ 'block_member 'optional_WS ] * "}"]
|_ _ inner _| (construct_body true [do] (map |x| (idx x 0) inner) 0))
; Call functions with function first, c style (notice no whitespace)
(add_grammar_rule 'form [ 'form 'call_form ] |f ps| (concat [f] ps))
; fun syntax
(add_grammar_rule 'form [ "fun" 'WS 'atom 'optional_WS "\\(" 'optional_WS [ 'atom 'optional_WS ] * "\\)" 'optional_WS 'form ]
|_ _ name _ _ _ params _ _ body| `(fun ~name (,(map |x| (idx x 0) params)) ~body))
; string interpolation
fun remove_dollar(done to_do i j) (cond (>= j (- (len to_do) 2)) (str done (slice to_do i -1))
(= "\\$" (slice to_do j (+ j 2))) (remove_dollar (str done (slice to_do i j) "$") to_do (+ j 2) (+ j 2))
true (remove_dollar done to_do i (+ j 1)))
fun fixup_str_parts(s) (remove_dollar "" (slice s 0 -2) 0 0)
(add_grammar_rule 'form [ "$\"" [ "(#|[%-[]| |[]-~]|(\\\\)|(\\n)|(\\t)|(\\*)|(\\\\$)|
|[ -!]|(\\\\\"))*$" 'form ] * "(#|[%-[]| |[]-~]|(\\\\)|(\\n)|(\\t)|(\\*)|(\\\\$)|
|[ -!]|(\\\\\"))*\"" ]
|_ string_form_pairs end| `(str ,( flat_map |x| [ (fixup_str_parts (idx x 0)) (idx x 1) ] string_form_pairs) ~(fixup_str_parts end)))
(println $"unu |\$| $$"inner $(+ 1 2) post-inner" sual")
obj Point( x y ) {
add |self other| { Point((+ self.x other.x) (+ self.y other.y)) }
sub |self other| { Point((- self.x other.x) (- self.y other.y)) }
to_str |self| { str("x: " self.x ", y: " self.y) }
}
fun say_hi(name) {
println("hayo" name)
}
fun test() {
let plus_1 = |x| (+ x 1)
let a = 1
let b = plus_1(a)
println("some" b)
say_hi("Marcus")
let p1 = Point(1 2)
let p2 = Point(3 4)
let p3 = p1.add(p2)
let p4 = p1.sub(p2)
println("p1:" p1.to_str)
println("p2:" p2.to_str)
println("p3:" p3.to_str)
println("p4:" p4.to_str)
(+ a b)
}
println("Test result is" test())
</div>
<h4>Output: </h4>
<textarea id="method_output">Output will appear here</textarea>
@@ -184,12 +278,13 @@ Note that the current implementation is inefficient, and sometimes has problems
<h4>More Complicated Example: BF as an embedded language</h4>
<button onclick="executeKraken(bf_editor.getValue(), 'bf_output')"><b>Run</b></button> <br>
<div id="bf_editor">
(load-file "./k_prime_stdlib/prelude.kp")
; We don't have atoms built in, mutable vectors
; We don't have atoms built in, mutable arrays
; are our base building block. In order to make the
; following BF implementation nice, let's add atoms!
; They will be implmented as length 1 vectors with nice syntax for deref
; They will be implmented as length 1 arrays with nice syntax for deref
(fun make-atom (x) [x])
(fun set-atom! (x y) (set-idx! x 0 y))
(fun get-atom (x) (idx x 0))
@@ -224,10 +319,10 @@ Note that the current implementation is inefficient, and sometimes has problems
(lambda (_ _ _ _ x _ _)
`(lambda (input)
(let (
tape (vector 0 0 0 0 0)
tape (array 0 0 0 0 0)
cursor (make-atom 0)
inptr (make-atom 0)
output (make-atom (vector))
output (make-atom (array))
)
(do (println "beginning bfs") ,x (idx output 0))))))