Archived
lastest
This commit is contained in:
1 parent
620fc5bda1
commit
bd3ef9f279
779 files changed
+202868
No files matched your search
+149
@@ -0,0 +1,149 @@
|
||||
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")
|
||||
|
||||
Reference in new issue
Block a user