zygo.slide 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. zygomys: embedded scripting toolkit for Go
  2. 16 March 2016
  3. Jason E. Aten, Ph.D.
  4. Principal Engineer, Betable.com
  5. [email protected]
  6. @jasonaten_
  7. https://github.com/glycerine/zygomys
  8. [[https://github.com/glycerine/zygomys/wiki.]] The wiki has details, examples, and discussion.
  9. * scenario
  10. * Snoopy versus the Red Baron
  11. .image snoopy_ace.png
  12. * What is his cry?
  13. .image curse_you_red_baron.png
  14. - imagine Snoopy comes back with friends...
  15. * data model for a plane formation, Go structs
  16. .code snoopy1
  17. - note slice of interface / embedded elements (we handle these)
  18. * Methods defined on the Snoopy struct
  19. .code snoopy2
  20. - anything that can Fly satisfies the Flyer interface. Weather, informs the Fly event:
  21. .code weather
  22. * Flyer friends, can be listed in the Friends slice in Plane
  23. .code other.planes
  24. * with the data model in mind, lets interact with it using zygo...
  25. * Make it rain
  26. .code make.it.rain
  27. * Bring in some planes, in formation
  28. .code make.planes
  29. - in three lines we've instantiated and configured 3 Go structs in a tree
  30. - call a Go method on a Go struct... Snoopy goes Fly()-ing
  31. .code plane.interact
  32. * we've just been interacting/scripting Go data and methods...
  33. * yeah, reflection is pretty cool
  34. * zygomys - a scripting toolkit for Go
  35. * zygomys -- what's in a name?
  36. - zygo means union (yoke in Greek; the zygote was the first cell that was you).
  37. - mys means mouse
  38. - this is a little mouse of a language
  39. - bonus: a "pocket gopher" known as Zygogeomys trichopus. Our mascot, "Ziggy".
  40. - this is the union of lisp and Go. In a small cute package.
  41. - Let's use the shorter `"zygo"` for the language, when speaking aloud.
  42. The Michoacan pocket gopher is a small animal with short, dense, black, lustrous fur... It is docile when caught, making no attempt to bite as do other pocket gophers.
  43. -- [[https://en.wikipedia.org/wiki/Michoacan_pocket_gopher]]
  44. .image pocket_gopher2.jpeg
  45. * Getting started: How to embed the REPL in your code
  46. See [[https://github.com/glycerine/zygomys/blob/master/cmd/zygo/main.go]]. Just three steps.
  47. .code main.go /START OMIT/,/END OMIT/
  48. * architecture / overview of design
  49. .image pocket_gopher3.jpeg
  50. - a) lexer produces tokens
  51. - b) parser produces lists and arrays of symbols
  52. - c) macros run at definition type
  53. - d) codegen produces s-expression byte-code
  54. - e) (work in progress) builders create and check types at `run` time. (Builders are a hybrid between a function and a macro.)
  55. - f) a simple virtual machine executes s-expression byte-code. User's functions run.
  56. * Let's see some code
  57. - hashmaps can define arbitrary records; with or without attached Go shadow structs
  58. .code sample.run1
  59. we range through the hashmap, `hsh`, like this:
  60. .code sample.run3
  61. * records
  62. - records are hash tables with a name. All hash tables preserve key-order.
  63. .code harry.record
  64. * plain hash maps, without a distinct record TypeName
  65. .code hash.demo
  66. * arrays (slices)
  67. .code arrays.run
  68. * aims
  69. - interactive, but also aim to eventually compile-down to Go
  70. - blending Go and lisp
  71. - I built it for myself
  72. - technically interesting about the zygo implementation:
  73. - using goroutines as coroutines to get pause-able parsing. avoids the O(n^2) trap. Call for more input from many points; inversion of select loop -- exit when you've got another line of input tokens. See repl/parser.go.
  74. - if you haven't discovered how to do conditional sends on a channel yet, examples inside `github.com/glycerine/zygomys/repl/parser.go`.
  75. * hard parts that are already done
  76. - script calls to existing Go functions using existing Go structs. Using reflect is somewhat laborious; but its done
  77. - Go-style for loops, nest-able, with break to label and continue to label.
  78. - eval
  79. - sandbox / restrict filesystem access
  80. - full closures with lexical scope
  81. - adjust lisp syntax to be Go compatible: % for quoting, 'a' for characters.
  82. - higher order functions.
  83. * classic lisp style - list processing
  84. .code hof.foldr
  85. - see the closure tests in [[https://github.com/glycerine/zygomys/blob/master/tests/closure.zy]]
  86. * there is also an infix interface
  87. - anything inside curly braces is infix parsed. Can mix in function calls. Math becomes more readable. Uses a Pratt parser.
  88. .code infix.session
  89. * inspect the transformation
  90. .code infix.txt
  91. * Top-down Operator Precedence (Pratt parsing)
  92. - Like quicksort, Pratt's is a short, sharp algorithm; not particularly easy to understand on the first pass. It builds a parse tree so that precedence is decreasing as you go up to the root. Higher precedence means stronger binding, which means being lower in the parse tree.
  93. - works like magic. Very easy to extend your language with new infix operations, once the core Expression routine is implemented. This is how zygo processes infix syntax.
  94. - links for learning:
  95. [[https://github.com/glycerine/zygomys/blob/master/repl/pratt.go]] Already written into zygo.
  96. [[https://github.com/glycerine/PrattParserInC/blob/master/Vaughan.Pratt.TDOP.pdf]] original
  97. [[http://javascript.crockford.com/tdop/tdop.html]] Douglas Crockford's article, javascript
  98. example in python: [[http://effbot.org/zone/simple-top-down-parsing.htm]]
  99. blog with discussion/Java: [[http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/]]
  100. * parse tree
  101. .image parseTree.jpg
  102. - hill-climbing: the precedence gets smaller as you go up.
  103. - + addition has precedence 50.
  104. - * multiplication has precedence 60, and so binds more tightly.
  105. * zygo use cases
  106. - as a query language
  107. - configuration language that can query itself.
  108. - Eventually... multi-core friendly scripting. (Channels now, but no select yet).
  109. - Eventually... leverage Go's multicore strength for exploratory configuration, data analysis and scripting. (I love R for productivity, Go for production).
  110. * the basic Go API: adding compiled functions to zygo
  111. .code first.go /START OMIT/,/END OMIT/
  112. .code use.first
  113. * tour of the insides: major files of `github.com/glycerine/zygomys/repl/`
  114. - repl.go ..........ReplMain() lives here, toplevel loop
  115. - expression.go ..........the core Sexp s-expression definitions
  116. - environment.go ..........lexical scope, symbol table lookup
  117. - lexer.go ..........hand written lexer
  118. - parser.go ..........recursive parsing of symbols into lists and arrays
  119. - generator.go ..........code-gen: generate Sexp byte code
  120. - vm.go ..........virtual machine that executes the byte code
  121. - builders.go ..........declarations and type checking
  122. - gotypereg.go ..........the type registry for Go/zygo type correspondence
  123. * auxiliary/helper files; also in `github.com/glycerine/zygomys/repl/`
  124. - typeutils.go ..........runtime type inspection from zygo (type? var)
  125. - hashutils.go ..........records (a.k.a hash tables)
  126. - listutils.go ..........linked list (*SexpPair) utilities
  127. - strutils.go ..........string utilities
  128. - scope.go ..........stack of symbol tables
  129. - stack.go ..........used by scopes
  130. - rawutils.go ..........raw []byte handling
  131. - numerictower.go ..........number conversions
  132. - vprint.go ..........debug print stuff for development
  133. * custom types: extension example files
  134. - random.go .......... (wrap math/rand.Float64() call)
  135. - regexp.go .......... (wrap regexp.Regexp)
  136. - time.go .......... (wrap time.Time)
  137. - jsonmsgp.go .......... (conversions to/from json and msgpack)
  138. * the fundamental Sexp types
  139. .code exp.txt
  140. - SexpNull (actually a value; an instance of the SexpSentinel type)
  141. - SexpSymbol (variable and function names; symbol table entries)
  142. - SexpPair (linked lists)
  143. - SexpArray (slices)
  144. - SexpHash (hash table; keys and values are any Sexp, key ordering preserved)
  145. * debug tools, at the zygo repl
  146. - `.dump` .......... shows the data stack
  147. - `.debug` .......... traces the PC (program counter) through the byte code
  148. - `.undebug` .......... turns off traces
  149. - `.gls` .......... global list of all symbols
  150. - `.ls` .......... list of local symbols
  151. - `(macexpand)` .......... show what a macro expands to
  152. - `(infixExpand {})` .......... show the s-expression expansion of an infix expression
  153. - the wiki has a lot of documentation. [[https://github.com/glycerine/zygomys/wiki]]
  154. * json / msgpack support
  155. See the top of `github.com/glycerine/zygomys/repl/jsonmsgp.go` for a guide.
  156. .code msgp.txt
  157. * type system
  158. * type system. work in progress...
  159. - always manifestly typed: a variable points to a value that knows its own type.
  160. - add-on: optional static type system -- enforced at definition time -- is half implemented
  161. - to follow status, `github.com/glycerine/zygomys/tests/decl_fun.zy`
  162. - struct declarations done, function type declarations with (func) not yet done.
  163. - the static typing aims for compatibility with Go types (to enable compile-down)
  164. .code declare.struct
  165. * intro to the mechanism of zygo's static type system: Builders
  166. - A builder is a special kind of function; a hybrid between a function and a macro. I chose the term `builder` to reflect their ability to build structs (i.e. new types), packages, type aliases.
  167. - Like a macro, a builder receives the un-evaluated parse-tree of symbols from its caller. A builder can therefore be used to build new types and declare new functions/methods.
  168. - Like a function, a builder is called at run/evaluation time, not at definition time. (Macros are run at code-gen, which is definition time).
  169. - Since it receives an un-evaluated tree of symbols, a builder must manually eval arguments it wants to find bindings for.
  170. - Used in zygo to define structs. Next planned use: define interfaces, functions, methods, and type aliases. See [[https://github.com/glycerine/zygomys/blob/master/repl/builders.go]] for examples.
  171. * If you want to play with type systems
  172. - try out your parametric-polymorphism idea?
  173. - I don't know if its a good idea but...
  174. - the sigil-system is setup to let you explore this area
  175. - sigil prefixed symbols start with `$`, `#`, or `?`
  176. - makes it easy to define type-variables, for example.
  177. * sigil system
  178. symbols with a special prefix
  179. - `mysym` is a regular symbol
  180. - `$mysym` is a sigil symbol, with sigil '$'. It is distinct from `mysym`.
  181. - `#mysym` is a sigil symbol, with sigil '#'. It is distinct from `$mysym` and `mysym`.
  182. - `?mysym` is a sigil symbol, with sigil '?'. It is distinct from the above.
  183. * sigils part 2
  184. - sigil prefixed-symbols evaluate to themselves by default.
  185. - useful for grammars, symbolic reasoning.
  186. * todo
  187. - dataframe
  188. - matrix / tensor types
  189. - complex number support
  190. * it's the future ... dream big
  191. - model checking syntax and checker (Ordered-Binary-Decision-Diagram based)
  192. - port TLA+ model checker to Go, with zygomys interface
  193. - unification engine for type system experiments
  194. * final thoughts
  195. - interpreters teach the value of a test-driven approach
  196. - tests are simply language fragments
  197. * credits
  198. The ancestor dialect of zygomys, [[https://github.com/zhemao/glisp]] Glisp, was designed and implemented by Howard Mao [[https://zhehaomao.com/]].
  199. Thanks Howard!