Est. 2000 Advanced

TOM

Tom is a pattern matching compiler built at LORIA and Inria in Nancy that grafts term rewriting onto Java and C: %match, algebraic signatures, backquote term construction, rewrite rules and a strategy library, compiled away into ordinary host-language code so that rewriting techniques could be used inside real applications instead of inside a dedicated interpreter

Created by Pierre-Etienne Moreau, who led the work and wrote most of the compiler, at the Protheo and later Pareo research groups of LORIA and Inria Nancy - Grand Est, in France. The project AUTHORS file credits the "initial design of Tom" jointly to Christophe Ringeissen and Marian Vittek, and lists Emilie Balland, Jean-Christophe Bach, Horatiu Cirstea and Antoine Reilles as the other main developers, with Paul Brauner, Julien Guyon (the Eclipse plugin), Radu Kopetz (compiler and anti-patterns), Claudia Tavares (type inference) and Marc Pantel (model transformations and the Ada backend) among the contributors. Mark van den Brand, Jurgen Vinju, Patrick Viry and Eelco Visser are thanked in the same file for discussions - Visser specifically beside the %match construct, Viry beside the backquote notation

Paradigm Rule-based and rewriting-oriented, layered on top of an imperative host. Tom is not a standalone language: it is a set of constructs - %match, rewrite rules, algebraic signatures, backquote term construction and a strategy language - added to Java (and, with less coverage, to C and other backends), which the compiler expands into plain host-language code. Its own documentation describes the pattern matching as "similar to the match primitive found in functional languages", and the Tom compiler itself is written in a functional style as a chain of AST-to-AST transformations
Typing Static, inherited from the host language and extended by Tom's own checks. Algebraic sorts and constructors are declared either in a Gom signature (%gom) or through a mapping (%typeterm, %op) that tells the compiler how an existing Java or C data structure is to be read as a term; the compiler type-checks patterns against those sorts and, from version 2.8, ran a new type-inference engine, with a subtyping-aware type engine becoming the default in 2.10
First Appeared 2000 as the project's own start date - the copyright line in the LICENCE file reads "Copyright (c) 2000-2015, Universite de Lorraine, Inria" - but the earliest dated artefacts are from the following winter. The ChangeLog opens on 25 January 2001 with "Setup of TOM under automake", records the JavaCC parser on 6 February 2001 and a "first bootstrap" on 14 February 2001, and the first publication, "A Pattern Matching Compiler" by Moreau, Ringeissen and Vittek, was presented at the first LDTA workshop in Genova in April 2001. Numbered versions only start in late 2002: 0.6 on 29 October 2002, 0.7 on 19 November 2002, 1.0beta on 21 November 2002
Latest Version Tom 2.10, released 21 March 2013 - the last release the project ever made. Development continued in the repository after it (the master branch to December 2017, the v3 branch to August 2019) under an unreleased version number, build.xml still carrying stable.version = 3.0-dev. In May 2026 Pierre-Etienne Moreau pushed 63 commits over three days to a tom-go branch, a fresh port of the compiler to Go; none of that has been released

Tom is what happens when a group of rewriting researchers stop trying to make people come to their language and go to everybody else’s instead. Built at LORIA in Nancy from around 2000 and developed at Inria for the better part of two decades, Tom takes the machinery of term rewriting — algebraic signatures, pattern matching modulo equational theories, rewrite rules, traversal strategies — and grafts it onto Java. A .t file is a Java file with extra constructs in it; the tom command expands those constructs into ordinary Java and hands the result to javac. Nothing is interpreted and no foreign engine takes over at run time, though generated code does link against Tom’s own runtime library (tom-runtime-full.jar, on the CLASSPATH); and in principle an ordinary Java program is already a valid Tom program, since the compiler expands only the constructs it recognises and passes the rest through untouched.

The name is an acronym, and a slightly apologetic one. The project’s own about page explains it: “In its first version, Tom was just supposed to add pattern matching facilities to a programming language. The considered pattern matching feature was supposed to discriminate over a single subject. This is why Tom is called Tom: To One Matching.”

Dating the language

Language lists give 2000, and the project’s own copyright line supports it: the LICENCE file in the source tree reads “Copyright (c) 2000-2015, Universite de Lorraine, Inria”. But nothing dated 2000 survives in the code. The oldest record in the tree is the ChangeLog, and it opens on 25 January 2001 with a single line — “Setup of TOM under automake” — followed on 6 February by the first JavaCC parser and on 14 February 2001 by an entry that reads, in full, “src/jtom/Tom.java: first bootstrap”. The first publication, “A Pattern Matching Compiler” by Pierre-Étienne Moreau, Christophe Ringeissen and Marian Vittek, was presented at the first LDTA workshop in Genova in April 2001.

Version numbers arrive late and start low. The ChangeLog dates version 0.6 to 29 October 2002 (it introduces the backquote notation), version 0.7 to 19 November 2002 (“bootstrap with ApiGen”), and 1.0beta to 21 November 2002. The safest reading is that 2000 is when the design work began, 2001 when there was a working compiler, and 2002 when it started being versioned for other people.

Where it came from: the ELAN lesson

Tom’s ancestry is explicit. The Protheo group at LORIA had spent the 1990s building ELAN, a rewriting language with non-deterministic strategies and a compiler for associative-commutative rewriting that was, along with Maude, among the most serious implementations of its kind. The Tom about page states the lineage directly: Tom’s “design follows our research on rule based languages, and our experiences on the efficient compilation of ELAN”.

What the group took from ELAN was less a technique than a disappointment. The RTA 2007 system description sets it out plainly: implementing a good term data structure is hard, marshalling data in and out of a rewriting engine is often the bottleneck, built-in integers and doubles are awkward, mutable structures like arrays are essential and missing — “but one of the most important things we learned is that even if efficiency is important to make our technology credible, integration capabilities are even more important to make our research widely used both in academic and industrial projects.”

The alternative to piling libraries, threads, GUIs and native interfaces onto a research language was to stop competing with Java. The group called the resulting idea a formal island: a fragment of formally-defined, rule-based code embedded in an ordinary program, connected to the surrounding data by a formal anchor — a mapping that explains how an existing concrete data structure is to be read as an algebraic term. The idea is related to Wadler’s views, and its practical effect is that Tom can rewrite data structures it did not create, without converting them first.

What the language adds

The whole language is a handful of constructs. The canonical example from the project’s guided tour defines a signature and matches on it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import matching.logic.types.*;

public class Matching {

  %gom {                                // algebraic signature
    module Logic
      imports int String
      abstract syntax

      Proposition = P(t:Term)
                  | Q(t:Term)
                  | implies(p1:Proposition, p2:Proposition)

      Term = nat(i:int)
           | var(name:String)
           | plus(t1:Term, t2:Term)
  }

  public static String prettyProposition(Proposition p) {
    %match(p) {                          // pattern matching over terms
      P(t)           -> { return "P(" + prettyTerm(`t) + ")"; }
      Q(t)           -> { return "Q(" + prettyTerm(`t) + ")"; }
      implies(p1,p2) -> { return "(" + prettyProposition(`p1)
                                 + " => " + prettyProposition(`p2) + ")"; }
    }
    return "";                           // javac does not know this is unreachable
  }

  public static String prettyTerm(Term t) {
    %match(t) {
      nat(i)      -> { return Integer.toString(`i); }
      var(x)      -> { return `x; }
      plus(t1,t2) -> { return prettyTerm(`t1) + " + " + prettyTerm(`t2); }
    }
    return "";
  }

  public static void main(String[] args) {
    // backquote builds terms; maximal sharing makes equality a pointer test
    Proposition p = `implies(P(plus(nat(1),nat(2))), Q(var("x")));
    System.out.println(prettyProposition(p));
  }
}

The moving parts:

ConstructWhat it does
%matchThe core. Like ML’s match, but discriminating over algebraic terms rather than atomic values, and falling through to the next pattern if the action does not break the control flow
` (backquote)Builds terms, and reads the variables bound by a pattern back into host-language expressions
%gom / GomDeclares an algebraic signature and generates the Java classes implementing it, with maximal sharing
%typeterm, %opThe mapping, or formal anchor: how to see a data structure you already have as a term you can match on
%strategy, the sl libraryTraversal and control: TopDown, BottomUp, Repeat, Choice, All, and user-defined combinators, applied to terms as first-class strategy objects
!Anti-patterns — matching terms that do not have a given shape, added in version 2.4
%transformation, %resolve, %tracelinkModel-to-model transformation with traceability, added in the final release

Two properties follow from Gom’s term representation, inherited from CWI’s ATerm and ApiGen work: terms are maximally shared — the property inherited from CWI’s ATerm library, under which no two structurally equal subterms are ever separately allocated, so that testing structural equality is a pointer comparison rather than a traversal — and lists can be normalised with respect to equational axioms — associativity, associativity with neutral element, and (from 2.8) associativity-commutativity — so that matching happens modulo those theories rather than syntactically.

Evolution

ReleaseDateWhat it brought
0.6 / 0.7 / 1.0betaOct–Nov 2002Backquote notation; bootstrap on ApiGen; first stable numbering
1.510 Dec 2003New checker, XML syntax for patterns, Eclipse plugin days later
2.09 Jun 2004Caml support, optimizer, built-in char and string, redesigned kernel compiler
2.120 Dec 2004ANTLR parser, plugin architecture, first traversal strategy library
2.229 Jul 2005%typeterm unification, second optimization level
2.328 Apr 2006Gom, %strategy, %[...]% backend-writing construct
2.44 Oct 2006Anti-patterns, sort inference for subjects, bytecode support, Eclipse plugin revived
2.59 Jul 2007Constraint-based compiler, associative matching with neutral element, sl library
2.611 Apr 2008Matching constraints p << t with && / ||, mapping inlining, ANTLR adapter
2.725 May 2009Fresh names and binders in Gom, generics in strategies, parallel compilation
2.814 Feb 2011AC matching, new type inference, Tom–EMF bridge
2.914 Oct 2011Non-linear AC patterns, default values in %op, alpha ANTLR v3 parser
2.1021 Mar 2013Subtyping type engine by default, Ada backend, %transformation / %resolve / %tracelink

The backend story is messier than the release notes suggest. Java was always the supported target; the source tree also carries generators for C, C#, Caml, Python and - from the final release of 2013, according to NEWS - Ada, of varying completeness, and the manual is candid that the model-transformation constructs of the last release work “only [for] Java and EMF”. The installation guide in doc/ gives the requirement as a development kit “version 1.5 or newer”, and reports that Tom “has been used successfully on many platforms, including GNU/Linux distributions (Debian, Gentoo, Mandrake, Ubuntu), MacOS X, FreeBSD, NetBSD, Windows XP, Windows Vista and Windows 7” — a list of platforms the project says it was used on rather than a supported-platform matrix.

The decline

Tom did not fail; it stopped. Version 2.10 shipped on 21 March 2013 and no release followed. The ChangeLog runs on to August 2013, the master branch to December 2017, a v3 branch to August 2019, and build.xml still names an unreleased 3.0-dev. Then the infrastructure went: Inria took gforge.inria.fr off-line at the end of 2020, and with it every download link, the Windows installer, the bug tracker and the git URLs printed all over the project’s pages. The site at tom.loria.fr is still served, but what is served is a static HTTrack copy of it made on 1 March 2023, complete with dead links to the forge. Tom does not appear ever to have been published to Maven Central — nothing is served under the obvious group IDs — so there is no package-manager fallback either.

What survives is the source. A mirror of the repository was created on GitHub in February 2016 and is complete back to the CVS-to-Subversion import of 8 January 2003, with the pre-2003 history preserved in the ChangeLog. And in May 2026, over three days, Pierre-Étienne Moreau pushed 63 commits to a branch called tom-go: the ATerm library, the parser, the Gom backend and the compiler phases ported to Go, with the commit messages tracking parity against the Java implementation test by test. It is branch work, unreleased and unannounced, and it would be wrong to call it a revival — but it is the only movement in the project since 2019, and it is by the person who started it.

Why it matters

Tom is the most fully worked-out answer to a question the programming-language research community keeps running into: what do you do when your ideas are good and nobody will switch languages to get them? The formal-island approach — put the formal fragment inside the industrial language, connect it to existing data through a mapping rather than a conversion, compile it away to nothing — let a rewriting group ship pattern matching, equational matching, rewrite rules and strategy combinators into Java projects the best part of two decades before Java itself got pattern matching, and let those projects keep their own data structures while doing it.

It is also a good specimen of how such a project actually ends. There was no fork, no schism, no successor language: there was a research group whose people finished their theses and moved on, a series of releases that got steadily better and steadily more specialised, one clearly documented industrial engagement, and finally a hosting service being decommissioned. The compiler is four fifths written in itself, which is the sincerest thing a language designer can say about a design; the tarballs it was distributed in are gone; and the whole of it now fits in a git clone.

Running Tom today

There is no Docker image and no official download. What is available:

  • The source. git clone https://github.com/rewriting/tom.git gives the full history, the Ant build (./build.sh), the manual under doc/, and the examples and regression tests. Building it requires a JDK and bootstrapping through the checked-in stable compiler; the tree was last built against Java 8 and would need care on a modern JDK.
  • The documentation. The reference manual, guided tour and FAQ are in the repository as Markdown under doc/, and the 2.7-era manual PDF is deposited in Inria’s HAL archive.
  • The web site, tom.loria.fr, as a frozen 2023 mirror: news log, applications, licensing, and the Emacs, Vim and Notepad++ syntax files, which are among the few links on it that still resolve.

The licence remains the one the project settled on in 2005: GPL v2 for the compiler, BSD for the runtime library and the predefined mappings, precisely so that anything Tom generates can be redistributed under whatever licence its author prefers.

Timeline

2000
The year Tom's own copyright line starts from: "Copyright (c) 2000-2015, Universite de Lorraine, Inria". The context is the Protheo group at LORIA in Nancy, which had spent the 1990s building ELAN, a rewriting-based language with its own compiler and its own runtime. The lesson the group drew from ELAN, as the 2007 RTA paper puts it, was that efficiency mattered less than integration: a rewriting engine nobody could plug into an existing application would not be used. Tom is the answer to that - put the rewriting on top of a language people already use
2001
The first surviving development records. The ChangeLog opens on 25 January with "Setup of TOM under automake"; a JavaCC-based parser is integrated on 6 February; on 14 February Pierre-Etienne Moreau records a "first bootstrap" - the compiler compiling itself. The declaration syntax is committed on 2 March - %typeterm, %typelist, %typearray, %op, %oplist and %oparray - of which %typeterm, %op, %oplist and %oparray were still there in the last release, while %typelist and %typearray were dropped again in 2.2; list patterns follow later that month. In April, Moreau, Christophe Ringeissen and Marian Vittek present "A Pattern Matching Compiler" at the first Workshop on Language Descriptions, Tools and Applications in Genova, published in volume 44 of ENTCS
2002
The first numbered versions appear in the ChangeLog: 0.6 on 29 October, which introduces the backquote mechanism for building terms; 0.7 on 19 November, recorded as "bootstrap with ApiGen" - the term data structure now comes from CWI's ApiGen and ATerm technology, with maximal sharing; and 1.0beta two days later on 21 November, described in NEWS as the "new stable version based on ApiGen"
2003
The project becomes public-facing. Moreau, Ringeissen and Vittek publish "A Pattern Matching Compiler for Multiple Target Languages" at the 12th Conference on Compiler Construction in Warsaw (LNCS 2622, pages 61-76); the HAL record gives the year but not the month. Versions 1.3 (22 August) and 1.4 (23 September) are released; XML pattern matching is integrated on 20 October; the tom-users mailing list is created on 24 November; version 1.5 is released on 10 December and tagged the next day, and an Eclipse plugin ships for Eclipse 2.1.x and 3.0M6 on 12 December
2004
Tom 2.0 on 9 June adds a Caml backend, predefined mappings, an optimizer that inlines generated code, and built-in char and string support; its kernel compiler and list-matching are redesigned. Tom 2.1 on 20 December brings the pieces that shape the rest of the project: a parser based on ANTLR, an internal architecture built out of plugins, and the first library for defining traversal strategies
2005
Tom 2.2 is released on 29 July, removing %typelist and %typearray in favour of a single %typeterm and adding a second optimization level. The same year the software is given the Inter Deposit Digital Number IDDN.FR.001.130053.000.S.P.2005.000.10400 - the about page quotes the number, and its 2005 field is what dates the deposit, and the licensing is settled in the form it kept: the compiler under GPL v2, the runtime library and predefined mappings under a BSD licence so that generated code carries no obligations
2006
Two releases that define what Tom finally looked like. Version 2.3 on 28 April introduces Gom, a generator of algebraic data types with hooks, and the %strategy construct that removes the need to hand-write inner classes. Version 2.4 on 4 October adds anti-patterns - the ! operator, for matching what a term is not - makes the sort of a %match subject optional by inferring it, allows strategies themselves to be matched as terms, and adds support for Java bytecode analysis
2007
Tom 2.5 arrives on 9 July with a compiler rebuilt on constraint solving, associative matching with neutral element for list operators, and the sl strategy library. The same year gives the project its most cited paper, "Tom: Piggybacking rewriting on Java", presented at RTA in Paris in June by Emilie Balland, Paul Brauner, Radu Kopetz, Pierre-Etienne Moreau and Antoine Reilles, alongside workshop papers on bytecode rewriting, term-graph rewriting and anti-pattern matching
2009
Tom 2.7 is released on 25 May, following 2.6 of 11 April 2008. It adds a --fresh option to Gom for signatures involving alpha-convertible names and binding, an option to generate data structures without maximal sharing, Java generics in the strategy library's visit methods, and a thread-safe compiler able to compile files in parallel
2011
Tom 2.8 on 14 February integrates associative-commutative matching, a new type-inference engine and a tool connecting Tom to the Eclipse Modeling Framework; the project describes it as an "administrative release". Tom 2.9 follows on 14 October with non-linear AC patterns, a bracket notation for backquote terms, default values in %op declarations and an alpha ANTLR v3 parser
2013
21 March: Tom 2.10, the last release. It makes the subtyping type engine the default, adds an Ada backend, and adds the high-level model-transformation constructs %transformation, %resolve and %tracelink that came out of the avionics work with Airbus and Ellidiss. The ChangeLog carries on to 9 August 2013, and a source-line count taken on 6 March 2014 shows the compiler sources at 59,361 lines, of which 46,996 - just under four fifths - are written in Tom itself
2020
Inria takes gforge.inria.fr off-line at the end of the year, in favour of its GitLab. Every download link, the bug tracker and the git URLs on tom.loria.fr point there, so the official distribution channel simply stops existing. The web site survives, but as a static HTTrack copy made on 1 March 2023; the code survives on GitHub, where a mirror of the repository was created in February 2016
2026
19-21 May: after nearly seven quiet years, Pierre-Etienne Moreau pushes 63 commits to a tom-go branch of the GitHub repository - a port of the aterm library, the parser, the Gom backend and the compiler pipeline to Go, working towards parity with the Java reference implementation. It is unreleased and unannounced work on a branch, not a revival of the project, but it is the only Tom development activity in the record since 2019

Notable Uses & Legacy

The Tom compiler itself

Tom bootstrapped on 14 February 2001 and stayed bootstrapped: the compiler is a chain of transformations over its own abstract syntax tree, written in Tom, compiled by the previous Tom. The project's own SLOCCount run of 6 March 2014 puts src/tom at 59,361 lines - 46,996 of Tom, 7,573 of Java, plus the Ada and Python runtime pieces - which makes the compiler the largest and best-documented Tom program in existence, and the reason the project's applications page calls it "the most famous application" of Tom

Airbus and Ellidiss - model transformation for avionics

The clearest industrial trace. "Tom-based tools to transform EMF models in avionics context", by Jean-Christophe Bach, Pierre-Etienne Moreau and Marc Pantel, presented at the industrial track of Software Language Engineering on 25 September 2012, describes using Tom's rule-based approach to implement and trace the transformations that take a system model written in an engineering language into the formal languages a model checker can verify - work done "in a research project involving industrial partners: Airbus and Ellidiss", where the transformation step itself has to be qualifiable for certification. The %transformation, %resolve and %tracelink constructs released in Tom 2.10 came out of this line of work

Java bytecode analysis and rewriting

From version 2.4 Tom shipped support for treating compiled Java bytecode as terms, with the mapping layer standing in for a parser. Emilie Balland, Pierre-Etienne Moreau and Antoine Reilles described the approach in "Bytecode Rewriting in Tom" at the Bytecode workshop in Braga in 2007: patterns are written over instruction sequences and strategies drive the traversal, so that analyses and instrumentation can be expressed as rewrite rules rather than as visitor code

Rule-based protocol verification

Horatiu Cirstea, Pierre-Etienne Moreau and Antoine Reilles used Tom to encode and re-verify the Needham-Schroeder public-key protocol, presented as "Rule based programming in Java for protocol verification" at the 5th International Workshop on Rewriting Logic and its Applications in Barcelona in 2004. The point of the exercise was the division of labour Tom was built for: rewrite rules describe the transitions of the system, while the search strategies over them - depth-first, breadth-first, parallel - are written and executed separately

Embedding Tom in other host languages - the GLL experiment

"Island Grammar-based Parsing using GLL and Tom" (SLE 2012), by Ali Afroozeh, Mark van den Brand and Maarten Manders at TU Eindhoven, Adrian Johnstone and Elizabeth Scott at Royal Holloway, and Bach and Moreau at Inria, used Tom as the case study for a hard parsing problem: embedding one language inside another recursively produces a nondeterministic composite grammar, exactly the situation Tom's own parser faces when Tom constructs are scattered through Java or C source. The paper is a good measure of how much of Tom's difficulty was in the host-language embedding rather than in the matching

Rewriting research: deep inference, anti-patterns, the rho-calculus

Tom's main constituency was the rewriting community that built it. "Implementing Deep Inference in Tom" (Ozan Kahramanogullari, Moreau and Reilles, ICALP Structures and Deduction workshop, 2005) used it for proof-theoretic search; "Anti-Pattern Matching" (Claude Kirchner, Radu Kopetz and Moreau, ESOP 2007) introduced into Tom the negative patterns that few other languages have; and the project's own applications page records a first implementation of the rho-calculus, propositional provers, and encodings of L-systems and of the BoulderDash gravity rule written in Tom

Language Influence

Influenced By

ELAN ASF+SDF Stratego ML Java C

Running Today

Run examples using the official Docker image:

docker pull
Last updated: