123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- OMeta/JS is a new version of OMeta, a language for pattern-directed metaprogramming first described in
- Alessandro Warth and Ian Piumarta, "OMeta: An Object-Oriented Language for Pattern-Matching," in Proceedings of the Dynamic
- Languages Symposium, 2007. (Available at http://www.cs.ucla.edu/~awarth/papers/dls07.pdf)
- This page contains the information necessary for someone who has read the OMeta paper to be able to use OMeta/JS.
- Pattern Syntax
- --------------
- +------------------------------------------------------------------------+
- | "kind of thing" OMeta OMeta/JS |
- +------------------------------------------------------------------------+
- | boolean true true |
- | number 123 123 |
- | character 'x' 'x' | (see note #1)
- | string "foo" 'foo' |
- | `foo |
- | #foo |
- | atom foo N/A |
- | rule application <expr> expr |
- | <r x y> r(x, y) | (see note #3)
- | <super stmt> ^stmt | (see note #4)
- | list ("hello" 42 answer ()) ['hello' 42 `answer []] |
- | negation ~'x' ~'x' |
- | look-ahead ~~'x' ~~'x' |
- | &'x' |
- | semantic predicate ?(> x y) ?(x > y) | (see note #2)
- | semantic action => (+ x y) -> (x + y) |
- | !(+ x y) !(x + y) |
- | binding <expr>:x expr:x | (in OMeta/JS, spaces are not allowed before the colon)
- | :x | (this is shorthand for "anything:x")
- +------------------------------------------------------------------------+
- Note #1: There is no such thing as a character in JavaScript. Even though the language lets you access each "character" of a string via indexing, e.g, "foo"[0], the answer is not a character, but rather a string of length 1.
- Note #2: In the version of OMeta described in the paper, semantic actions and predicates were written in COLA (kind of a mix between Scheme and Smalltalk). In OMeta/JS, they are written in JavaScript. More specifically, they are either primary expressions, e.g.,
- 123
- x
- foo.bar()
- new Person()
- (x + y) // note that you need parentheses around "x + y" in order to make it into a primary expression
- or something I made up called "statement expressions", which have the form
- "{" <statement>* <expr> "}"
- For example,
- { x += 2; y = "foo"; f(x) }
- The value of a statement expression is equal to that of its last expression.
- Note #3: The arguments you pass to a rule don't have to be statement expressions - they can be any JavaScript expression.
- Note #4: In OMeta/JS, "super" is just like any other rule (not a special form), so you have to quote the rule name that you pass in as an argument, e.g., both ^r(1, 2) and super("r", 1, 2) are valid super-sends.
- A "Handy" New Shorthand
- -----------------------
- In OMeta/JS, the pattern
- "foo"
- does not match the string 'foo'; it is instead shorthand for
- token('foo')
- The Parser grammar provides a definition for token that skips any number of spaces, then tries to match the sequence of characters that was passed to it as an argument. I have used this in many of the example projects, and have found it to be very useful.
- Still, there are times when this is not what you want. But that's not a problem, because you can define it to do whatever you want (see the JavaScript Compiler project for an example).
- Rules
- -----
- Here is a parameterized rule taken from the paper, in the original OMeta syntax:
- cRange x y ::= <char>:c ?(>= c x)
- ?(<= c y) => c;
- And here is the same rule rule, in the new OMeta/JS syntax:
- cRange :x :y = char:c ?(c >= x)
- ?(c <= y) -> c
- A couple of (purely syntactic) differences:
- (1) rule declarations now use "=" instead of "::=", and
- (2) they are no longer terminated with a ";"
- A more significant difference has to do with the rule's arguments; note that in the OMeta/JS version, they are preceded by a ':'. This is actually shorthand for
- cRange anything:x anything:y = ...
- This change has to do with an improvement in the parameter-passing mechanism, which now allows a rule's parameters to be pattern-matched against. (See the paper's "Future Work" section for more details.)
- The "=" is actually optional in rule declarations... this, combined with some new syntax that allows a rule to have multiple definitions that are tried in lexicographic order, allows programmers to write rules that have an "ML flavor":
- ometa M {
- fact 0 -> 1,
- fact :n ?(n > 0) fact(n - 1):m -> (n * m)
- }
- M.match(5, "fact")
- Grammar Syntax
- --------------
- The only change here has to do with rule declarations, which now must be separated by commas:
- ometa M {
- x = y z,
- y = "foo" "bar",
- z = "baz"
- }
- Using Grammars "from the outside"
- ----------------------------------
- The public interface provided by an OMeta/JS grammar object to the rest of the world consists of two methods:
- match(object, ruleName)
- and
- matchAll(arrayOrStringObject, ruleName)
- Here's an example that hopefully explains the difference between the two. The key to understanding it is that a string is just a list of characters.
- ometa M <: Parser {
- theCharacters = "the" "cat" "sat" "on" "the" "mat",
- theWholeString = [theCharacters]
- }
- input = "the cat sat on the mat"
- M.matchAll(input, "theCharacters")
- M.match(input, "theWholeString")
|