]> git.lizzy.rs Git - metalua.git/blob - junk/notes.txt
Merge remote branch 'origin/master'
[metalua.git] / junk / notes.txt
1 === Random personal notes ===
2
3 ====================================================================
4 This is my persistent *scratch*. There are random notes, in random
5 languages, unstructured, out of date, generally unexploitable. Don't
6 expect anything here to make sense.
7 ====================================================================
8
9 Readme fraft
10 ============
11 This distribution of metalua tries to favor ease of install over
12 saving a couple of kilobytes; therefore it directly embeds pieces of
13 useful other free software rather than letting users fetch and
14 configure them, and it installs separately from a regular lua install,
15 instead of messing it up.
16
17 Open source code used by metalua
18
19
20 Metalua current sources include (possibly slightly modified versions
21 of) these open source projects:
22
23 - Lua, of course.
24
25 - Yueliang, a Lua compiler in written in Lua: this is
26   the base of metalua's bytecode dumper.
27
28 - Rings, a part of the Kelper project, which lets handle multiple Lua
29   states from within Lua.
30
31 - Editline, an interactive command line editor, very similar to GNU
32   readline but with a more permissive licence.
33
34 - bitlib for bitwise manipulations (especially useful for bytecode
35   dumping)
36
37 The mlc module
38 --------------
39 This module contains all of the compilation stuff. The version
40 available after compilation is heavily based on the pattern matching
41 extension, so it isn't used in the code required for bootstrapping
42 (which has to be in lua inter metalua. That is, then, Lua)
43
44 Libraries
45 ---------
46 The mechanism of metalua libraries is exactly the same as Lua's,
47 except that the environment variable names ahve been changed to allow
48 peaceful cohabitation with Lua.
49
50 Etancheite:
51 ===========
52 - shell interactif:
53   * separer les niveaux
54   * permettre de monter/descendre d'un niveau avec des commandes
55     dediees: "+:" et "-:"
56
57 Il faut faire la part entre la synthese de l'AST et l'evaluation. La
58 synthese de l'AST est faite en amont de mlc.splice(). Apparemment, le
59 lexer est commun a tout le monde... et mlp aussi.
60
61 Hygiene:
62 ========
63 les quotes peuvent etre hygieniques (HQQ) ou pas (QQ). les QQ sont
64 normales, ne font rien; ca permet de capturer des variables entre
65 morceaux. 
66
67 Les HQQ sont attachees a un contexte, dans lequel seront reversees
68 leurs variables libres. +{:hexpr(CTX): foo } va alpha renommer toutes
69 les variables libres de +{foo} et les stocker dans CTX.
70
71 Autre possibilite syntaxique: une +{hexpr: foo } retourne +{foo} et
72 son contexte. Le contexte permet de decider comment fusionner deux
73 AST. Il ne se resume pas a une substitution
74
75 ->Laurie:
76
77 Your approach is to tell the user that an AST has a sense by itself:
78 it's an autonomous piece of data that won't interfere with its
79 environment. Then you re-introduce mechanisms to get some dangling
80 bits back, so that you can wire the various bits (QQ and splices)
81 together as you wish. 
82
83 Now, the point from which I'll draw my PoV: an AST is only hygienic
84 relative to a context. Through gensym() we're able to craft ASTs that
85 are hygienic in all normal contexts, but the notion of contexts
86 continues to exist. In particular, as soon as we want to connect bits
87 of AST in interesting ways, we start to need a finer-grained control
88 of contexts.
89
90 You offer, with $c{ } ${ } and &, ways to poke holes into contexts,
91 but since you try pretend to the user that there's no context, the
92 user is screwed when he does want to mess with it. He has to guess how
93 those hidden contexts work, and find ways to use the tools mentionned
94 above so that they have the intended effect on the stealth context.
95
96 That's a good approach when there's nothing clever to do with
97 contexts, and it falls down when users get out of the main use
98 cases. Depending on how rare it is to need such conttext hacking
99 capabilities, your approach might or might not be practical.
100
101 The metalua-consistent approach is the opposite one: if there's such a
102 thing as contexts, and it sometimes makes sense for (advanced) users
103 to fiddle with them, then there must be first class AST context
104 objects. If it can be optionally hidden in most common cases, great,
105 but users aren't supposed to ignore their existence.
106
107 Therefore, whenever you combine two pieces of AST, you specify how
108 their context must be merged. The 2 most common defaults would be
109 "don't touch anything" (non-hygienic macros) and "make sure there's no
110 interference" (full hygiene, no capture). 
111
112 In the example we just discussed, the problem is that we have 3 AST
113 (around, inside and usercode) and we want to splice them in a fancy
114 way: there's only one capturing variable between around and inside,
115 and it must not capture anything in usercode. You hack your way around
116 to build a protective shell on usercode, then toss it with the other
117 ASTs. I'd rather write that around and inside share the same context,
118 and usercode has its own. Then when combining all those, the
119 hygienizer will know what to do. if I wanted to combine around's and
120 outside's contexts so that they'd only share "q_var", I should be able
121 to express that as well.
122
123 Bottom line is: I'd rather have 1st class context than implicit ones,
124 which will be a hassle to interact with when I have to. KISS
125 engineering at its best :)
126
127
128
129 Restent a faire:
130 ================
131 - reflechir a l'addition automatique des mots-clef par les parsers qui
132   vont bien. Peut-etre qu'ils sont attaches optionnellement a un lexer,
133   et que cet attachement est transmis par defaut qd on insere un
134   parser ds un autre
135 - notation pour la generation auto de sous-tables
136 - verifier le runtime error handling patch d'EVE
137 - anaphoric macros should bind 'it' to a function when it appears directly in
138   it. it would allow anonymous recursive functions. However, anaphoric
139   structures tend to capture each other very fast; maybe Arc has insightful
140   ideas about this? (e.g. different captured names for function and other
141   structs)
142
143
144 Bugs a verifier:
145 ================
146 - reentrance de in_a_quote dans mlp_meta.lua
147 - refuser les flags autres qu'expr dans les splices in_a_quote
148
149 il faudra encore fournir une boucle interactive, celle de lua n'est
150 pas patchable. Idem pour le compilo.
151
152 metalua compiler/interpreter short usage manual
153 ===============================================
154
155 Allows to compile and/or run metalua programs, and to use interactive
156 loop.
157
158 --compile
159 --run
160 --interactive
161 --output
162 --load-library <name>[@metalevel]
163 --print-ast
164
165 By default, parameters are passed to all running chunks. However, if
166 there is are parameters and no running chunk, the first parameter is
167 taken as the running chunk.
168
169 metalua --compile foo.mlua 
170
171 if there is an --output, all run and compiled files will be saved in
172 it.
173
174 - compile all files.
175 - displays ASTs depending on --print-ast
176 - run all files if --run
177 - run loop after compile and run if -i or if no file
178 - if no -a and no -o, -x is implied
179 - if -x and no file, first param is a file
180
181 2nd attempt
182 ===========
183
184 Compile and/or execute metalua programs. Parameters passed to the
185 compiler should be prefixed with an option flag, hinting what must be
186 done with them: take tham as file names to compile, as library names
187 to load, as parameters passed to the running program... When option
188 flags lack, metalua tries to adopt a "Do What I Mean" approach:
189
190 - if no code (no library, no literal expression and no file) is
191   specified, the first flag-less parameter is taken as a file name to
192   load.
193
194 - if no code and no parameter is passed, an interactive loop is
195   started.
196
197 - if a target file is specified with --output, the program is not
198   executed by default, unless a --run flag forces it to. Conversely,
199   if no --output target is specified, the code is run unless ++run
200   forbids it.
201
202 When does it compile, when does it execute?
203 ------------------------------------------- 
204 The result of the compilation is saved if there is a --output
205 specifying a destination file. If not, the result is run. If both
206 --output and --run are specified, the result is both saved and run. If
207 the compilation must be saved, it is mandatory to have at least one
208 file or library. 
209
210 How to load chunks to compile/run
211 ---------------------------------
212 Files can be passed, with their relative paths, with --file. Libraries
213 can be loaded, from standard paths, with --library. Litteral blocks of
214 code can be passed with --literal.
215
216 When does it launch an interactive loop?
217 ----------------------------------------
218 When --interactive is specified, or when no chunk is loaded.
219
220
221
222
223 Macro hygiene
224 =============
225
226 alpha should go at the top of the chunk *where the quote is used*,
227 which is generally not the same as where it's defined. Ideally, it
228 should go where the extension using the quote is called. So what I
229 really need is an improved 'extension' statement, which handles quotes
230 anhoring.
231
232 A serious problem is that most quotes are inside functions and
233 therefore not always evaluated in the extension() call.
234
235 Let's consider two instants:
236 - when the QQ is formally created for compilation (1)
237 - when it's returned by a function, presumably to be spliced (2)
238
239
240  If alpha-conv
241 happens at QQ creation, then I lose the
242
243
244 So, alpha
245 conversion must happen at CT
246
247
248 Extension
249 =========
250 The current extension() function automatically loads a runtime, even
251 when empty. More control should be given. Both RT and CT parts should
252 go in the same directory. Finally, RT should probably handle macro
253 hygiene in a standardized way.
254
255 ==> extension() should be like a require(), except that it:
256 - prepends 'extension.' to the module name
257 - returns nil when require() returns true
258
259 From there, macro alphas could be handled as follows:
260 - create a common alpha at the opening of the extension. As an empty list.
261 - push in in H() so that it'll be shared by all hygienizations
262 - return it if there' no runtime, or return it with a require()
263   statement for the RT lib.
264
265 Shipping 0.4
266 ============
267 - remove autotable: I don't use it and it isn't polished enough to be
268   useful yet.
269
270 - remove machine and fsm_test; or at least, put it in samples
271
272 - remove mandatory platform from makefile call
273
274 - H loads extension/H-runtime.mlua?
275
276
277
278 README.TXT
279 ==========
280 For installation matters, cf. INSTALL.TXT
281
282 Metalua 0.4
283 ===========
284 Metalua is a static metaprogramming system for Lua: a set of tools
285 that let you alter the compilation process in arbitrary, powerful and
286 maintainable ways. For the potential first-time users of such a
287 system, a descripition of these tools, as implemented by metalua,
288 follows.
289
290 Dynamic Parsers
291 ---------------
292 One of these tools is dynamic parser: a source file can change the
293 syntax recognized by the parser while it's being parsed. Taken alone,
294 this feature lets you make superficial syntax tweaks on the
295 language. The parser is based on a parser combinator called 'gg'. You
296 should know the half dozen functions in gg API to do advanced things,
297 but it means you can use and define functions that transform parsers:
298
299 - There are a couple of very simple combinators like gg.list,
300   gg.sequence, qq.multisequence, gg.optkeyword etc. that offer a level
301   of expressiveness comparable to Yacc-like parsers. For instance, if
302   mlp.expr parses Lua expressions, gg.list{ mlp.expr } creates a
303   parser which handles lists of Lua expressions.
304
305 - Since you can create all the combinators you can think of, there
306   also are combinators specialized for typical language tasks. In
307   Yacc-like systems, the language definition quickly becomes
308   unreadable, because all non-native features have to be encoded in
309   clumsy and brittle ways; so if your parser won't natively let you
310   specify infix operator precedence and associativity easily, tough
311   luck for you and your code maintainers. With combinators, this is
312   abstracted away in a regular function, so you just write:
313
314   > mlp.expr.infix:add{ "xor", prec=40, assoc='left', builder=xor_builder }
315
316   Moreover, combinators tend to produce usable error messages when fed
317   with syntactically incorrect inputs. It matters, because clearly
318   explaining why an invalid input is invalid is almost as important as
319   compiling a valid one, for a use=able compiler.
320
321 Yacc-like systems might seem simpler to adopt than combinators, as
322 long as they're used on extremely simple problems. However, if if you
323 either try to write something non trivial, or to write a simple macro
324 in a robust way, you'll need to use lots of messy tricks and hacks,
325 and spend much more time getting them (seemingly) ritght than that 1/2
326 hour required to master most of gg.
327
328
329 Real meta-programming
330 ---------------------
331 If you plan to go beyond trivial keyword-for-keyword syntax tweaks,
332 what will limit you is the ability to manipulate source code
333 conveniently: without the proper tools and abstractions, even the
334 simplest tasks will turn into a dirty hacks fest, then either into a
335 nightmare, or most often into abandonware. Providing an empowering
336 framework is metalua's whole purpose.  The core principle is that
337 programs prefer to manipulate code as trees (whereas most developers
338 prefer ASCII sources). The make-or-break deal is then:
339
340 - To easily let users see sources as trees, as sources, or as
341   combination thereof, and switch representations seamlessly.
342
343 - To offer the proper libraries, that won't force you to reinvent a
344   square wheel, will take care of the most common pitfalls, won't
345   force you to resort to brittle hacks.
346
347 On the former point, Lisps are at a huge advantage, their user syntax
348 already being trees. But languages with casual syntax can also offer
349 interchangeable tree/source views; metalua has some quoting +{ ... }
350 and anti-quoting -{ ... } operators which let you switch between both
351 representations at will: internally it works on trees, but you always
352 have the option to see them as quoted sources. Metalua also supports a
353 slightly improved syntax for syntax trees, to improve their
354 readability.
355
356 Library-wise, metalua offers a set of syntax tree manipulation tools:
357
358 - Structural pattern matching, a feature traditionally found in
359   compiler-writing specialized languages (and which has nothing to do
360   with string regular expressions BTW), which lets you express
361   advanced tree analysis operations in a compact, readable and
362   efficient way.  If you regularly have to work with advanced data
363   structures and you try it, you'll never go back.
364
365 - The walker library allows you to perform transformations on big
366   portions of programs. It lets you easily express things like:
367   "replace all return statements which aren't in a nested function by
368   error statements", "rename all local variables and their instances
369   into unique fresh names", "list the variables which escape this
370   chunk's scope", "insert a type-checking instruction into every
371   assignments to variable X", etc. You can't write many non-trivial
372   macros without needing to do some of those global code
373   transformations.
374
375 - Macro hygiene, although not perfect yet in metalua, is required if
376   you want to make macro writing reasonably usable (and contrary to a
377   popular belief, renaming local variables into fresh names only
378   address the easiest part of the hygiene issue; cf. changelog below
379   for more details).
380
381 - The existing extensions are progressively refactored in more modular
382   ways, so that their features can be effectively reused in other
383   extensions.
384
385
386 Notworthy changes since 0.3
387 ===========================
388
389 - A significantly bigger code base, mostly due to more libraries:
390   about 2.5KLoC for libs, 4KLoC for the compiler. However, this remains
391   tiny in today's desktop computers standards. You don't have to know
392   all of the system to do useful stuff with it, and since compiled
393   files are Lua 5.1 compatible, you can keep the "big" system on a
394   development platform, and keep a lightweight runtime for embedded or
395   otherwise underpowered targets.
396
397
398 - The compiler/interpreter front-end is completely rewritten. The new
399   program, aptly named 'metalua', supports proper passing of arguments
400   to programs, and is generally speaking much more user friendly than
401   the mlc from the previous version.
402
403
404 - Metalua source libraries are looked for in environmemt variable
405   LUA_MPATH, distinct from LUA_PATH. This way, in an application
406   that's part Lua part Metalua, you keep a natural access to the
407   native Lua compiler.
408
409   By convention, metalua source files should have extension .mlua. By
410   default, bytecode and plain lua files are preferred to metalua
411   sources, which lets you easily precompile your libraries.
412
413
414 - Compilation of files are separated in different Lua Rings: this
415   prevents unwanted side-effects when several files are compiled
416   (This can be turned off, but shouldn't be IMO).
417
418
419 - Metalua features are accessible programmatically. Library
420   'metalua.runtime' loads only the libraries necessary to run an
421   already compiled file; 'metalua.compile' loads everything useful at
422   compile-time.
423
424   Transformation functions are available in a library 'mlc' that
425   contains all meaningful transformation functions in the form
426   'mlc.destformat_of_sourceformat()', such as 'mlc.luacfile_of_ast()',
427   'mlc.function_of_luastring()' etc. This library has been
428   significantly completed and rewritten (in metalua) since v0.3.
429
430
431 - Helper libraries have been added. For now they're in the
432   distribution, at some point they should be luarocked in. These
433   include:
434   - Lua Rings and Pluto, duct-taped together into Springs, an improved
435     Rings that lets states exchange arbitrary data instead of just
436     scalars and strings.
437   - Lua bits for bytecode dumping.
438   - As always, very large amounts of code borrowed from Yueliang.
439   - As a commodity, I've also packaged Lua sources in.
440
441
442 - Builds on Linux, OSX, Microsoft Visual Studio. Might build on mingw
443   (not tested recently). It's easily ported to all systems with a full
444   support for lua.
445
446   The MS-windows building is hackish: it's driven by a batch script,
447   and Pluto can't compile as a win32 DLL, so it's linked in the Lua
448   VM. If you want to run your own VM, either link pluto in statically,
449   or disabled separate compilation by setting environment variable
450   LUA_MFAST at true. In the later case, expect puzzling behaviors when
451   you load several sources containing compile-time code (==>
452   precompile everything).
453
454   Notice that bits of the compiler itself are now written in metalua,
455   which means that its building now goes through a bootstrapping
456   stage.
457
458
459 - Structural pattern matching:
460   - now also handles string regular expressions: 'someregexp'/pattern
461     will match if the tested term is a string accepted by the regexp,
462     and on success, the list of captures done by the regexp is matched
463     against pattern.
464   - Matching of multiple values has been optimized
465   - the default behavior when no case match is no to raise an error,
466     it's the most commonly expected case in practice. Trivial to
467     cancel with a final catch-all pattern.
468   - generated calls to type() are now hygienic (it's been the cause of
469     a puzzling bug report; again, hygiene is hard).
470
471
472 - AST grammar overhaul: 
473   The whole point of being alpha is to fix APIs with a more relaxed
474   attitude towards backward compatibility. I think and hope it's the
475   last AST revision, so here is it:
476   - `Let{...} is now called `Set{...} 
477     (Functional programmers would expect 'Let' to introduce an
478     immutable binding, and assignment isn't immutable in Lua)
479   - `Key{ key, value } in table literals is now written `Pair{ key, value }
480     (it contained a key *and* its associated value; besides, 'Pair' is
481     consistent with the name of the for-loop iterator)
482   - `Method{...} is now `Invoke{...}
483     (because it's a method invocation, not a method declaration)
484   - `One{...} is now `Paren{...} and is properly documented
485     (it's the node representing parentheses: it's necessary, since
486     parentheses are sometimes meaningful in Lua)
487   - Operator are simplified: `Op{ 'add', +{2}, +{2} } instead of
488     `Op{ `Add, +{2}, +{2} }. Operator names match the corresponding
489     metatable entries, without the leading double-underscore.
490   - The operators which haven't a metatable counterpart are
491     deprecated: 'ne', 'ge', 'gt'.
492
493  
494 - Overhaul of the code walking library:
495   - the API has been simplified: the fancy predicates proved more
496     cumbersome to use than a bit pattern matching in the visitors
497   - binding identifiers are handled as a distinct AST class
498   - walk.id is scope-aware, handles free and bound variables in a
499     sensible way.
500   - the currified API proved useless and sometimes cumbersome, it's
501     been removed.
502
503
504 - Hygiene: I originally planned to release a full-featured hygienic
505   macro system with v0.4, but what exists remains a work in
506   progress. Lua is a Lisp-1, which means unhygienic macros are very
507   dangerous, and hygiene a la Scheme pretty much limits macro writing
508   to a term rewriting subset of the language, which is crippling to
509   use. 
510
511   Note: inside hygiene, i.e. local variables created by the macro
512   which might capture user's variable instances, is trivial to address
513   by alpha conversion. The trickier part is outside hygiene, when
514   user's binders capture globals required by the macro-generated
515   code. That's the cause of pretty puzzling and hard to find bugs. And
516   the *really* tricky part, which is still unsolved in metalua, is
517   when you have several levels of nesting between user code and macro
518   code. For now this case has to be hygienized by hand.
519
520   Note 2: Converge has a pretty powerful approach of hygienic macros
521   in a Lisp-1 language; for long and boringly technical reasons, I
522   don't think its approch would be the best suited to metalua.
523
524   Note 3: Redittors must have read that Paul Graham has released Arc,
525   which is also a Lisp-1 with Common Lisp style macros; I expect this
526   to create a bit of buzz, out of which might emerge proper solutions
527   the macro hygiene problem.
528
529
530 - No more need to create custom syntax for macros when you don't want
531   to. Extension 'dollar' will let you declare macros in the dollar
532   table, as in +{block: function dollar.MYMACRO(a, b, c) ... end},
533   and use it as $MYMACRO(1, 2, 3) in your code.
534
535   With this extension, you can write macros without knowing anything
536   about the metalua parser. Together with quasi-quotes and automatic
537   hygiene, this will probably be the closest we can go to "macros for
538   dummies" without creating an unmaintainable mess generator.
539
540
541 - Lexers can be switched on the fly. This lets you change the set of
542   keywords temporarily, with the new gg.with_lexer() functor, or
543   handle radically different syntaxes in a single file (think
544   multiple-languages systems such as LuaTeX, or programs+goo as PHP).
545
546
547 - Incorporation of the bugs listed on the mailing list and the blog.
548
549
550 - New samples and extensions, in various states of completion:
551
552   - lists by comprehension, a la python/haskell. It includes lists
553     chunking, e.g. mylist[1 ... 3, 5 ... 7]
554
555   - anaphoric macros for 'if' and 'while' statements: with this
556     extension, the condition of the 'if'/'while' is bound to variable
557     'it' in the body; it lets you write things like:
558     while file:read '*l' do print(it) end.
559     No runtime overhead when 'it' isn't used in the body. An anaphoric
560     variable should also be made accessible for functions, to let
561     easily write anonymous recursive functions.
562
563   - continue statement, logging facility, ternary "?:" choice operator
564
565   - Try ... catch ... finally extension.
566
567   - with ... do extension: it uses try/finally to make sure that
568     resources will be properly closed. The only constraint on
569     resources is that they have to sport a :close() releasing method.
570     For instance, he following code guarantees that file1 and file2
571     will be closed, even if a return or an error occurs in the body.
572
573     with file1, file2 = io.open "f1.txt", io.open "f2.txt" do
574        contents = file1:read'*a' .. file2:read ;*a'
575     end
576
577
578 Credits
579 =======
580 I'd like to thank the people who wrote the open source code which
581 makes metalua run: the Lua team, the authors of Yueliang, Pluto, Lua
582 Rings, Bitlib; the people whose bug reports, patches and insightful
583 discussions dramatically improved the global design, including
584 Laurence Tratt, Viacheslav Egorov, David Manura, John Belmonte, Eric
585 Raible...