• Stars
    star
    176
  • Rank 216,987 (Top 5 %)
  • Language
    Perl
  • License
    MIT License
  • Created about 14 years ago
  • Updated almost 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Javascript-to-Javascript compiler

Caterwaul

Caterwaul is two different things. First, and most importantly, it is a powerful low-level Javascript code manipulation library with a Javascript parser, AST, in-process compiler, and replication. Second, it is a programming language implementation that uses this library to transform your code in various arcane ways that I happen to find useful.

The whole project is MIT-licensed, and in the unlikely event that you want to use it you are free to email me with any questions/issues.

What follows is a ten-minute introduction to caterwaul's core concepts. It covers about 5% of what caterwaul does.

Heads up: before you use this

It has a few defects. One relates to stuff like if (x) switch (y) {} else z();, which gets rewritten to broken code. This is a parse-level problem and I haven't had time to fix it yet.

Second, various ES5/6 features aren't entirely supported; for example functions-in-objects (let x = {f() {}};). There's probably more; the ES5 support was hacked on last-minute.

Third, Caterwaul parses non-JS. let @x = 100 is fine, let x\y\z = @foo[\] works, etc. Not a defect exactly, but something to be aware of.

Caterwaul as a library

Caterwaul is implemented in pure Javascript, so you can use it to live-compile your code in a browser, or you can use the waul precompiler to compile your code up-front. You can see the live compiler in action by going to the caterwaul website. This site embeds a caterwaul compiler configured to use the standard macro library; this causes it to compile what I refer to as the caterwaul programming language. The website documents this language in some detail, as does Caterwaul by Example - though some of the examples will fail since Caterwaul 1.2.3, which introduces a breaking change to the seq library.

If you're interested in using caterwaul as a compiler library, I recommend reading the caterwaul reference manual, which covers its core API in significantly more detail than this readme. You can also read through the caterwaul source code, which contains copious documentation, some of which is up to date.

Parsing things

Caterwaul's Javascript parser takes anything with a valid toString() method as input, including Javascript functions.

var tree = caterwaul.parse('3 + 4');
tree.toString()           // '3 + 4'
tree.data                 // '+'
tree.length               // 2
tree[0].data              // '3'
tree[1].data              // '4'

Detecting patterns

If you're serious about this stuff, I recommend writing this code in the caterwaul programming language. It supports a lot of advanced features that make syntax trees much easier to work with; in particular, preparsed quoted constructs (similar to the ' operator in Lisp). These will give you a significant performance advantage and better notation.

var pattern = caterwaul.parse('_x + _y');
var match   = pattern.match(tree);
match._x.data             // '3'
match._y.data             // '4'
var template = caterwaul.parse('f(_x, _y)');
var new_tree = template.replace(match);
new_tree.toString()       // 'f(3, 4)'

Compiling things

Caterwaul's compiler does a lot, but the basic case works like eval:

var f = function (x, y) {return x * y};
caterwaul.compile(new_tree)       // 12

You can also bind variables from the compiling environment:

var new_f = function (x, y) {return x + y};
caterwaul.compile(new_tree, {f: new_f})   // 7

You can only compile things that return values (technically, things which are expressions; the litmus test is whether you could legally wrap it in parentheses), so stuff like var x = 10 won't work. This is different from Javascript's eval function. If you want to execute imperative code, you should wrap it in a function:

var function_wrapper = caterwaul.parse('(function() {_body})');
var code = caterwaul.parse('if (x) {console.log(x)}');
var new_function = caterwaul.compile(function_wrapper.replace({_body: code}));
new_function();

Caterwaul as a programming language

I wrote a set of macros that use the above API to modify Javascript code; this macro set has been refined over the past year to become a programming language that I find useful. You can learn this language on the caterwaul website, which goes through it by example and provides an interactive shell so you can see what the compilation process looks like.

Using caterwaul this way

There are two ways to use caterwaul as a programming language. You can compile code from inside another Javascript process, which works because all caterwaul code is syntactically valid Javascript code as well (note that the following example will work only if you've loaded caterwaul.std.js from the build/ directory):

var compiler = caterwaul(':all');         // :all means 'every macro you know about'
var compiled = compiler(function () {
  console.log(x) -where [x = 10];
});
compiled();               // logs 10

The other way to use the programming language is by using the waul precompiler. This compiles your code to straight Javascript, eliminating the runtime overhead imposed by caterwaul's parser, macroexpander, and compiler. Waul files typically end in .waul or .waul.sdoc (if you're using SDoc, which waul will transparently parse) and contain code like this:

caterwaul(':all')(function () {
  n[10] *console.log -seq;
  console.log('done #{message}')
    -where [message = 'iterating through numbers'];
})();

You can compile this by running waul file.waul, which will generate file.js. file.js may contain references to the caterwaul global if you use certain macros, but there will be no compilation overhead.

Caterwaul as a self-replicating monstrosity

This is the coolest part of caterwaul in my opinion. Both caterwaul as a Javascript object and waul can give you string expressions that reproduce them. This is very useful for library bundling; for example:

var r = caterwaul.replicator();
var code = r.toString();

If you do this, someone else can eval 'code' and they will end up with a global called caterwaul that is configured exactly as your caterwaul is configured. The only requirement is that configurations be declared as modules, which is done like this:

// caterwaul.module(name, [compiler_configuration], function)
caterwaul.module('my-configuration', ':all', function ($) {
  // $ is the global caterwaul object
  $.foo = 'bar';
});

The output of replicator is a function that recreates all modules by re-running their initializers. Note that replicator rewrites the module functions into their post-compilation equivalents; in other words, the body of each function has already been compiled into normal Javascript. This reduces total compilation overhead.

Waul replication

Suppose you write a custom caterwaul module and want a new version of waul that contains it. You can ask waul to replicate itself with an extension like this:

$ ./waul -r -e extension.waul > new-waul
$ chmod u+x new-waul
$ ./new-waul my-file.waul

This is especially useful for setting up shebang lines for scripts that require custom waul extensions:

#!./new-waul
caterwaul(':all')(function () {
  // custom code
})();

The waul in caterwaul's root directory is preloaded with build/caterwaul.std.js and build/caterwaul.ui.js. As you might guess, waul wasn't written specially to contain these; rather, it was generated by waul-core (which doesn't have any libraries built-in) by this process:

$ ./waul-core --replicate -e build/caterwaul.std.min.js -e build/caterwaul.ui.min.js > waul
$ chmod 0700 waul

More Repositories

1

jit-tutorial

How to write a very simple JIT compiler
C
1,733
star
2

shell-tutorial

How to write a UNIX shell, with a lot of background
C
326
star
3

js-in-ten-minutes

JavaScript in Ten (arbitrarily long) Minutes
Perl
268
star
4

bash-lambda

Anonymous functions and FP stuff for bash
Shell
190
star
5

nfu

Numeric Fu for the command line
Perl
110
star
6

cd

A better "cd" for bash
Shell
96
star
7

ni

Say "ni" to data of any size
Perl
82
star
8

bashrc-tmux

Smart auto-tmuxing for SSH logins
Shell
58
star
9

jquery.fix.clone

A compilation of fixes for the clone() method in jQuery.
JavaScript
48
star
10

flotsam

Fast floating-point array serialization for Java and JS
JavaScript
35
star
11

canard

A functional concatenative language implemented in Linux/AMD64 machine code and self-modifying perl
Perl
18
star
12

tinyelf

A way to produce really small x86-64 Linux ELF files
Perl
16
star
13

interviewing-in-ten-minutes

A guide to surviving the technical interviewing process
Perl
15
star
14

zerovpn

Automatic OpenVPN using SSH
Shell
14
star
15

js-typeclasses

A typeclass implementation for JavaScript
JavaScript
13
star
16

cheloniidae

Extreme Java Turtle Graphics
Java
13
star
17

delimited-continuations-in-scheme

A simple implementation of shift/reset using call/cc
Scheme
11
star
18

divergence

A functional JavaScript library
JavaScript
11
star
19

cpp-template-lisp

An attempt to write a Lisp in C++ templates
C++
11
star
20

manhattan-model

A 3D model of Manhattan, built from youtube videos
11
star
21

divergence.rebase

Operator overloading and syntactic macros for JavaScript
JavaScript
11
star
22

jquery.gaussian

Gaussian blur plugin for jQuery
JavaScript
10
star
23

jquery.fix.textarea-clone

A fix for blank <textarea> elements after calling clone()
JavaScript
10
star
24

bash-prompt

A bash prompt with custom indicators
Shell
9
star
25

cheloniidae-live

A port of Cheloniidae to JavaScript/Canvas using the Divergence function library
Perl
9
star
26

www

HTML
8
star
27

conky-compiler

Absolute element positioning for conkyrc
Perl
8
star
28

infuse-js

The best Javascript library that could ever possibly exist, ever
JavaScript
8
star
29

fsh

Functional shell scripts
Shell
6
star
30

js-vim-highlighter

A better JavaScript VIM highlighter
Vim Script
6
star
31

bake

Make in bash
Shell
6
star
32

xv

Process-level virtualization for Linux/x86-64
C
6
star
33

perl-objects

Self-modifying Perl objects
Perl
5
star
34

perlquery

A jQuery-like interface to the filesystem
Perl
5
star
35

writing-self-modifying-perl

A step-by-step introduction to self-modifying Perl files
Perl
5
star
36

git-in-ten-minutes

A quick guide to the more confusing parts of Git
Perl
5
star
37

phi

A JIT-compiled functional language in the making
Perl
5
star
38

wumber

CAD for Haskell
Haskell
4
star
39

information-theory-in-ten-minutes

TeX
4
star
40

figment

A programming language with no defined semantics
Perl
4
star
41

plain-blog

A static blog without any Javascript
Perl
4
star
42

divergence.debug

Expression-level debugging for JavaScript
JavaScript
3
star
43

atom-node

An ATOM->JSON converter for node.js
JavaScript
3
star
44

webcrash

My presentations for the Web 3.0 Crash Course
JavaScript
3
star
45

montenegro

A lightweight web framework for node.js and Caterwaul
JavaScript
3
star
46

lock

A mutex for shell commands
Shell
3
star
47

bipolar

Perl
3
star
48

browserpower

A map/reduce server that uses browsers as computing nodes
JavaScript
3
star
49

yagfs

Yet another Git/FUSE filesystem
Ruby
2
star
50

resume

TeX
2
star
51

dotfiles

Emacs Lisp
2
star
52

modus

A UI library for Caterwaul and Montenegro
JavaScript
2
star
53

instaserver

A quick directory server in node
JavaScript
2
star
54

motley

Administration for a motley crew of questionable machines
Shell
2
star
55

data-science-in-ten-minutes

Data science in substantially more than ten minutes
TeX
2
star
56

divergence-guide

Divergence user's guide
JavaScript
2
star
57

caterwaul-terminal

ANSI terminal wrapper for Caterwaul (like ncurses)
JavaScript
2
star
58

docker

A docker SSH/xpra server with stuff I find useful
Dockerfile
2
star
59

futon

Design notes for a futon made from 2x6 spruce
Perl
2
star
60

mulholland

A totally awesome term-rewriting language
Perl
2
star
61

diskbench

A small set of shell scripts to benchmark various disk access patterns
Shell
2
star
62

scala-ctags

A CTags langdef for Scala
2
star
63

metaoptimize-challenge

My solutions to the challenge problem posted at http://metaoptimize.com/blog/2010/11/05/nlp-challenge-find-semantically-related-terms-over-a-large-vocabulary-1m
2
star
64

thermal

A dependency-tracking project management application
JavaScript
2
star
65

jquery.fix.select-clone

A clone() patch to preserve <select> selected values
JavaScript
2
star
66

ocd-scripts

Shell scripts for people with OCD tendencies
Shell
2
star
67

markdown-unlit

Literate compiler for Markdown
Perl
2
star
68

caterwaul-serialization

A serialization library that supports abstract values
JavaScript
2
star
69

note-paper

Graph paper with embedded data markings
PostScript
2
star
70

call-cc-in-ten-minutes

A quick guide to continuations from a Javascript perspective
Perl
2
star
71

mapomatic

Instant Leaflet.js maps
Perl
2
star
72

quickdupe

Fast duplicate-file detector
Perl
2
star
73

node-runabuf

A native extension to execute a node.js Buffer object as machine code
Assembly
2
star
74

rather-insane-serialization

A fairly complete serialization system in Javascript
Perl
2
star
75

perl-in-ten-minutes

A guide to the world's finest programming language
TeX
2
star
76

rho

A Ruby/C/Forth-inspired language
Vim Script
2
star
77

sdoc

Simple documentation for lightweight development
JavaScript
2
star
78

caterwaul-invariant

A library to maintain invariants across state transitions
JavaScript
2
star
79

lazytest

Tests for lazy developers (not that I know of any)
Perl
2
star
80

mathbio2008

A math/biology research project from summer 2008
TeX
1
star
81

mulholland-asm

An x86-64 assembler written in mulholland
JavaScript
1
star
82

caterwaul-reflection

Lexical closure inspection and first-class scope chains for Javascript
Perl
1
star
83

node-talk

A trivial command-line chat client and server
Perl
1
star
84

jquery.instavalidate

A lightweight, general-purpose text field validator for jQuery
JavaScript
1
star
85

bash-hats

Replayable command history
Shell
1
star
86

caterwaul.llasm

A low-level assembler/ELF generator for Caterwaul
JavaScript
1
star
87

peril

The successor of ni
Perl
1
star
88

uml-machine

A self-modifying Perl script to install and manage user-mode linux instances
1
star
89

divergence.vector

Vector geometry Divergence module
JavaScript
1
star
90

caterwaul-futures

A simple but expressive future library for Caterwaul
Perl
1
star
91

caterwaul-c

A really awful C parser/serializer for Caterwaul
Shell
1
star
92

ssh-baby-monitors

So the NSA can't hear stuff your baby says
1
star
93

webshell

A collection of instant-feedback web tools
1
star
94

caterwaul.analysis

Code analysis for Javascript
JavaScript
1
star
95

on

A simple way to run something on another machine
1
star
96

caterwaul.queue.blocking

An asynchronous blocking queue (should work on both client and server)
JavaScript
1
star
97

caterwaul-factory

A Caterwaul library for generating test data
JavaScript
1
star
98

node-router

A simple multiprotocol request router for node.js
JavaScript
1
star
99

bash-variable

Self-modifying files for storing values in bash
Perl
1
star
100

caterwaul-splunge

Realtime graphing for Caterwaul
Perl
1
star