This commit is contained in:
Danni committed 2026-09-20 13:07:50 +07:00
1 parent 620fc5bda1
commit bd3ef9f279
779 files changed
+202868

No files matched your search

+1
View File
@@ -0,0 +1 @@
*.swp
+48
View File
@@ -0,0 +1,48 @@
The language supported in this workspace is not quite JavaScript; it is rather a (large) subset of JavaScript, extended with some
new syntax.
One such extension allows string literals to be written as
'`' <identifier> or '#' <identifier>
For example, instead of writing
"foo"
you can write
`foo
And of course,
"foo" == `foo && `foo == #foo
I did this because I think parse trees, like
["plus", ["lit", 2], ["lit", 5]]
look better when you write them like this
[`plus, [`lit, 2], [`lit, 5]]
Another extension is that string literals, as in Smalltalk, can span multiple lines, e.g.,
" this whole thing
is a string
yay!
"
This is useful because it lets you put an entire program into a string (I do this in the Prolog, Logo, and MetaToo projects). Keep in mind that, as in Python, you can put escape sequences inside multi-line strings. So if you want a '\' character inside one of these guys, you need to type '\\'.
And because it's usually annoying to have to escape double quotes inside these big strings, you can also write multi-line string literals in Python-like syntax, e.g.,
"""
1+2
alert("hello world")
"""
-Alex
------------------------------------------------------------------------------------------------------------------------------------
Hey, Alex -- How about using a symbol that is less in one's face than "#"? What about tilde ~ or ` or underline, etc.? -- Alan
Hi Alan - this is funny, because the # was inspired by ST-80, heh heh... anyway, I like the idea of using ` instead. Try it now, it works. --- Alex
Hi Alex -- I have always hated that convention in ST-80 (I was not around to protest when that went in). ST-80 had the interesting problem of moving from an environment at PARC in which any glyphs desired could be authored, displayed and printed, to the "outside world" in the early 80s in which none of those things could be done. So they had to go back to ASCII conventions and this was painful. Thanks for the change. --- Alan
+150
View File
@@ -0,0 +1,150 @@
// a simple recognizer, produces no useful value
ometa L {
number = digit+,
addExpr = addExpr '+' mulExpr
| addExpr '-' mulExpr
| mulExpr,
mulExpr = mulExpr '*' primExpr
| mulExpr '/' primExpr
| primExpr,
primExpr = '(' expr ')'
| number,
expr = addExpr
}
L.matchAll('6*(4+3)', 'expr')
// a recognizer that also interprets
ometa Calc {
digit = ^digit:d -> d.digitValue(),
number = number:n digit:d -> (n * 10 + d)
| digit,
addExpr = addExpr:x '+' mulExpr:y -> (x + y)
| addExpr:x '-' mulExpr:y -> (x - y)
| mulExpr,
mulExpr = mulExpr:x '*' primExpr:y -> (x * y)
| mulExpr:x '/' primExpr:y -> (x / y)
| primExpr,
primExpr = '(' expr:x ')' -> x
| number,
expr = addExpr
}
Calc.matchAll('6**(4+3)', 'expr')
// parser and simple interpreter combo
ometa CalcParser {
digit = ^digit:d -> d.digitValue(),
number = number:n digit:d -> (n * 10 + d)
| digit,
addExpr = addExpr:x '+' mulExpr:y -> ['add', x, y]
| addExpr:x '-' mulExpr:y -> ['sub', x, y]
| mulExpr,
mulExpr = mulExpr:x '*' primExpr:y -> ['mul', x, y]
| mulExpr:x '/' primExpr:y -> ['div', x, y]
| primExpr,
primExpr = '(' expr:x ')' -> x
| number:n -> ['num', n],
expr = addExpr
}
tree = CalcParser.matchAll('6*(4+3)', 'expr')
ometa CalcInterpreter {
interp = ['num' anything:x] -> x
| ['add' interp:x interp:y] -> (x + y)
| ['sub' interp:x interp:y] -> (x - y)
| ['mul' interp:x interp:y] -> (x * y)
| ['div' interp:x interp:y] -> (x / y)
}
CalcInterpreter.match(tree, 'interp')
// we can write a "compiler" instead
ometa CalcCompiler {
comp = ['num' anything:x] -> x.toString()
| ['add' comp:x comp:y] -> ('(' + x + '+' + y + ')')
| ['sub' comp:x comp:y] -> ('(' + x + '-' + y + ')')
| ['mul' comp:x comp:y] -> ('(' + x + '*' + y + ')')
| ['div' comp:x comp:y] -> ('(' + x + '/' + y + ')')
}
code = CalcCompiler.match(tree, 'comp')
eval(code)
// spice things up with ML-like syntax
ometa CalcCompiler {
comp ['num' anything:x] -> x.toString(),
comp ['add' comp:x comp:y] -> ('(' + x + '+' + y + ')'),
comp ['sub' comp:x comp:y] -> ('(' + x + '-' + y + ')'),
comp ['mul' comp:x comp:y] -> ('(' + x + '*' + y + ')'),
comp ['div' comp:x comp:y] -> ('(' + x + '/' + y + ')')
}
code = CalcCompiler.match(tree, 'comp')
eval(code)
// a neat trick: dispatch on node tags using higher-order rule "apply"
ometa CalcCompiler {
comp [anything:t apply(t):ans] -> ans,
num anything:x -> x.toString(),
add comp:x comp:y -> ('(' + x + '+' + y + ')'),
sub comp:x comp:y -> ('(' + x + '-' + y + ')'),
mul comp:x comp:y -> ('(' + x + '*' + y + ')'),
div comp:x comp:y -> ('(' + x + '/' + y + ')')
}
code = CalcCompiler.match(tree, 'comp')
eval(code)
+624
View File
@@ -0,0 +1,624 @@
// TODO: rewrite _apply to use worlds
//////// lib.js
/*
Copyright (c) 2007, 2008 Alessandro Warth <[email protected]>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
// try to use StringBuffer instead of string concatenation to improve performance
function StringBuffer() {
this.strings = []
for (var idx = 0; idx < arguments.length; idx++)
this.nextPutAll(arguments[idx])
}
StringBuffer.prototype.nextPutAll = function(s) { this.strings.push(s) }
StringBuffer.prototype.contents = function() { return this.strings.join("") }
String.prototype.writeStream = function() { return new StringBuffer(this) }
// make Arrays print themselves sensibly
Object.prototype.printOn = function(ws) { ws.nextPutAll(this.toString()) }
Array.prototype.toString = function() { var ws = "".writeStream(); this.printOn(ws); return ws.contents() }
Array.prototype.printOn = function(ws) {
ws.nextPutAll("[")
for (var idx = 0; idx < this.length; idx++) {
if (idx > 0)
ws.nextPutAll(", ")
this[idx].printOn(ws)
}
ws.nextPutAll("]")
}
// delegation
Object.prototype.delegated = function(props) {
var f = function() { }
f.prototype = this
var r = new f()
for (var p in props)
if (props.hasOwn(p))
r[p] = props[p]
return r
}
// some reflective stuff
Object.prototype.ownPropertyNames = function() {
var r = []
for (name in this)
if (this.hasOwn(name))
r.push(name)
return r
}
Object.prototype.hasProperty = function(p) { return this[p] != undefined }
Object.prototype.isNumber = function() { return false }
Number.prototype.isNumber = function() { return true }
Object.prototype.isString = function() { return false }
String.prototype.isString = function() { return true }
Object.prototype.isCharacter = function() { return false }
String.prototype.isCharacter = function() { return this.length == 1 }
String.prototype.isSpace = function() { return this.isCharacter() && this.charCodeAt(0) <= 32 }
String.prototype.isDigit = function() { return this.isCharacter() && this >= "0" && this <= "9" }
String.prototype.isLower = function() { return this.isCharacter() && this >= "a" && this <= "z" }
String.prototype.isUpper = function() { return this.isCharacter() && this >= "A" && this <= "Z" }
String.prototype.digitValue = function() { return this.charCodeAt(0) - "0".charCodeAt(0) }
Object.prototype.isSequenceable = false
Array.prototype.isSequenceable = true
String.prototype.isSequenceable = true
// some functional programming stuff
Array.prototype.map = function(f) {
var r = []
for (var idx = 0; idx < this.length; idx++)
r[idx] = f(this[idx])
return r
}
Array.prototype.reduce = function(f, z) {
var r = z
for (var idx = 0; idx < this.length; idx++)
r = f(r, this[idx])
return r
}
Array.prototype.delimWith = function(d) {
return this.reduce(
function(xs, x) {
if (xs.length > 0)
xs.push(d)
xs.push(x)
return xs
},
[])
}
// Squeak's ReadStream, kind of
function ReadStream(anArrayOrString) {
this.src = anArrayOrString
this.pos = 0
}
ReadStream.prototype.atEnd = function() { return this.pos >= this.src.length }
ReadStream.prototype.next = function() { return this.src[this.pos++] }
// escape characters
escapeStringFor = new Object()
for (var c = 0; c < 256; c++)
escapeStringFor[c] = String.fromCharCode(c)
escapeStringFor["\\".charCodeAt(0)] = "\\\\"
escapeStringFor['"'.charCodeAt(0)] = '\\"'
escapeStringFor["'".charCodeAt(0)] = "\\'"
escapeStringFor["\r".charCodeAt(0)] = "\\r"
escapeStringFor["\n".charCodeAt(0)] = "\\n"
escapeStringFor["\t".charCodeAt(0)] = "\\t"
escapeChar = function(c) {
var charCode = c.charCodeAt(0)
return charCode > 255 ? String.fromCharCode(charCode) : escapeStringFor[charCode]
}
function unescape(s) {
if (s[0] == '\\')
switch (s[1]) {
case '\\': return '\\'
case 'r': return '\r'
case 'n': return '\n'
case 't': return '\t'
default: return s[1]
}
else
return s
}
String.prototype.toProgramString = function() {
var ws = "\"".writeStream()
for (var idx = 0; idx < this.length; idx++)
ws.nextPutAll(escapeChar(this[idx]))
ws.nextPutAll("\"")
return ws.contents()
}
// C-style tempnam function
function tempnam(s) { return (s ? s : "_tmpnam_") + tempnam.n++ }
tempnam.n = 0
//////// ometa-base.js
/*
Copyright (c) 2007, 2008 Alessandro Warth <[email protected]>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
/*
new syntax:
#foo match the string object 'foo' (should also be accepted in JS)
'abc' match the string object 'abc'
'c' match the string object 'c'
``abc'' match the sequence of string objects 'a', 'b', 'c'
"abc" token('abc')
[1 2 3] match the array object [1, 2, 3]
foo(bar) apply rule foo with argument bar
-> ... do semantic actions in JS (no more ST). allow multiple statements, but no declarations
probably don't even need {}s, because newlines can terminate it!
*/
/*
// ometa M {
// number = number:n digit:d -> { n * 10 + d.digitValue() }
// | digit:d -> { d.digitValue() }.
// }
try {
M = OMeta.delegated({
number: function() {
var $elf = this
return $elf._or(
function() {
var n, d
n = $elf._apply("number")
d = $elf._apply("digit")
return n * 10 + d.digitValue()
},
function() {
var d
d = $elf._apply("digit")
return d.digitValue()
}
)
}
})
M.matchAll("123456789", "number")
} catch (f) { alert(f) }
*/
// the failure exception
fail = { toString: function() { return "match failed" } }
// streams and memoization
function OMInputStream(hd, tl) {
this.memo = { }
this.hd = hd
this.tl = tl
}
OMInputStream.prototype.head = function() { return this.hd }
OMInputStream.prototype.tail = function() { return this.tl }
function OMInputStreamEnd() { this.memo = { } }
OMInputStreamEnd.prototype.head = function() { throw fail }
OMInputStreamEnd.prototype.tail = function() { throw fail }
Array.prototype.toOMInputStream = function() { return makeArrayOMInputStream(this, 0) }
String.prototype.toOMInputStream = Array.prototype.toOMInputStream
function makeArrayOMInputStream(arr, idx) { return idx < arr.length ? new ArrayOMInputStream(arr, idx) : new OMInputStreamEnd() }
function ArrayOMInputStream(arr, idx) {
this.memo = { }
this.arr = arr
this.idx = idx
this.hd = arr[idx]
}
ArrayOMInputStream.prototype.head = function() { return this.hd }
ArrayOMInputStream.prototype.tail = function() {
if (this.tl == undefined)
this.tl = makeArrayOMInputStream(this.arr, this.idx + 1)
return this.tl
}
function makeOMInputStreamProxy(target) {
return target.delegated({
memo: { },
target: target,
tail: function() { return makeOMInputStreamProxy(target.tail()) }
})
}
// Failer (i.e., that which makes things fail) is used to detect (direct) left recursion and memoize failures
function Failer() { }
Failer.prototype.used = false
// the OMeta "class" and basic functionality
OMeta = {
_apply: function(rule) {
var memoRec = this.input.memo[rule]
if (memoRec == undefined) {
var origInput = this.input,
failer = new Failer()
this.input.memo[rule] = failer
this.input.memo[rule] = memoRec = {ans: this[rule].apply(this), nextInput: this.input}
if (failer.used) {
var sentinel = this.input
while (true) {
try {
this.input = origInput
var ans = this[rule].apply(this)
if (this.input == sentinel)
throw fail
memoRec.ans = ans
memoRec.nextInput = this.input
}
catch (f) {
if (f != fail)
throw f
break
}
}
}
}
else if (memoRec instanceof Failer) {
memoRec.used = true
throw fail
}
this.input = memoRec.nextInput
return memoRec.ans
},
// note: _applyWithArgs and _superApplyWithArgs are not memoized, so they can't be left-recursive
_applyWithArgs: function(rule) {
for (var idx = arguments.length - 1; idx > 0; idx--)
this.input = new OMInputStream(arguments[idx], this.input)
return this[rule].apply(this)
},
_superApplyWithArgs: function($elf, rule) {
for (var idx = arguments.length - 1; idx > 1; idx--)
$elf.input = new OMInputStream(arguments[idx], $elf.input)
return this[rule].apply($elf)
},
_pred: function(b) {
if (b)
return true
throw fail
},
_not: function(x) {
var origInput = this.input
try { x() }
catch (f) {
if (f != fail)
throw f
this.input = origInput
return true
}
throw fail
},
_lookahead: function(x) {
var origInput = this.input,
r = x()
this.input = origInput
return r
},
_or: function() {
var origInput = this.input
for (var idx = 0; idx < arguments.length; idx++)
try { this.input = origInput; return arguments[idx]() }
catch (f) {
if (f != fail)
throw f
}
throw fail
},
_many: function(x) {
var ans = arguments[1] != undefined ? [arguments[1]] : []
while (true) {
var origInput = this.input
try { ans.push(x()) }
catch (f) {
if (f != fail)
throw f
this.input = origInput
break
}
}
return ans
},
_many1: function(x) { return this._many(x, x()) },
_form: function(x) {
var v = this._apply("anything")
if (!v.isSequenceable)
throw fail
var origInput = this.input
this.input = makeArrayOMInputStream(v, 0)
var r = x()
this._apply("end")
this.input = origInput
return v
},
// some basic rules
anything: function() {
var r = this.input.head()
this.input = this.input.tail()
return r
},
end: function() {
var $elf = this
return this._not(function() { return $elf._apply("anything") })
},
pos: function() {
return this.input.idx
},
empty: function() { return true },
apply: function() {
var r = this._apply("anything")
return this._apply(r)
},
foreign: function() {
var g = this._apply("anything"),
r = this._apply("anything"),
gi = g.delegated({input: makeOMInputStreamProxy(this.input)})
var ans = gi._apply(r)
this.input = gi.input.target
return ans
},
// some useful "derived" rules
exactly: function() {
var wanted = this._apply("anything")
if (wanted === this._apply("anything"))
return wanted
throw fail
},
"true": function() {
var r = this._apply("anything")
this._pred(r == true)
return r
},
"false": function() {
var r = this._apply("anything")
this._pred(r == false)
return r
},
"undefined": function() {
var r = this._apply("anything")
this._pred(r == undefined)
return r
},
number: function() {
var r = this._apply("anything")
this._pred(r.isNumber())
return r
},
string: function() {
var r = this._apply("anything")
this._pred(r.isString())
return r
},
"char": function() {
var r = this._apply("anything")
this._pred(r.isCharacter())
return r
},
space: function() {
var r = this._apply("char")
this._pred(r.charCodeAt(0) <= 32)
return r
},
spaces: function() {
var $elf = this
return this._many(function() { return $elf._apply("space") })
},
digit: function() {
var r = this._apply("char")
this._pred(r.isDigit())
return r
},
lower: function() {
var r = this._apply("char")
this._pred(r.isLower())
return r
},
upper: function() {
var r = this._apply("char")
this._pred(r.isUpper())
return r
},
letter: function() {
var $elf = this
return this._or(function() { return $elf._apply("lower") },
function() { return $elf._apply("upper") })
},
letterOrDigit: function() {
var $elf = this
return this._or(function() { return $elf._apply("letter") },
function() { return $elf._apply("digit") })
},
firstAndRest: function() {
var $elf = this,
first = this._apply("anything"),
rest = this._apply("anything")
return this._many(function() { return $elf._apply(rest) }, this._apply(first))
},
seq: function() {
var xs = this._apply("anything")
for (var idx = 0; idx < xs.length; idx++)
this._applyWithArgs("exactly", xs[idx])
return xs
},
notLast: function() {
var $elf = this,
rule = this._apply("anything"),
r = this._apply(rule)
this._lookahead(function() { return $elf._apply(rule) })
return r
},
initialize: function() { },
// match and matchAll are a grammar's "public interface"
_genericMatch: function(input, rule, args, matchFailed) {
if (args == undefined)
args = []
var realArgs = [rule]
for (var idx = 0; idx < args.length; idx++)
realArgs.push(args[idx])
var m = this.delegated({input: input})
m.initialize()
try { return realArgs.length == 1 ? m._apply.call(m, realArgs[0]) : m._applyWithArgs.apply(m, realArgs) }
catch (f) {
if (f == fail && matchFailed != undefined) {
var input = m.input
if (input.idx != undefined) {
while (input.tl != undefined && input.tl.idx != undefined)
input = input.tl
input.idx--
}
return matchFailed(m, input.idx)
}
throw f
}
},
match: function(obj, rule, args, matchFailed) {
return this._genericMatch([obj].toOMInputStream(), rule, args, matchFailed)
},
matchAll: function(listyObj, rule, args, matchFailed) {
return this._genericMatch(listyObj.toOMInputStream(), rule, args, matchFailed)
}
}
//////// parser.js
/*
Copyright (c) 2007, 2008 Alessandro Warth <[email protected]>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
Parser = OMeta.delegated({
listOf: function() {
var $elf = this,
rule = this._apply("anything"),
delim = this._apply("anything")
return this._or(function() {
var r = $elf._apply(rule)
return $elf._many(function() {
$elf._applyWithArgs("token", delim)
return $elf._apply(rule)
},
r)
},
function() { return [] })
},
token: function() {
var cs = this._apply("anything")
this._apply("spaces")
return this._applyWithArgs("seq", cs)
}
})
//////// bs-js-compiler.js
{BSJSParser=Parser.delegated({"fromTo":function(){var $elf=this,x,y;return (function(){x=$elf._apply("anything");y=$elf._apply("anything");$elf._applyWithArgs("seq",x);$elf._many(function(){return (function(){$elf._not(function(){return $elf._applyWithArgs("seq",y)});return $elf._apply("char")})()});return $elf._applyWithArgs("seq",y)})()},"space":function(){var $elf=this;return $elf._or((function(){return Parser._superApplyWithArgs($elf,"space")}),(function(){return $elf._applyWithArgs("fromTo","//","\n")}),(function(){return $elf._applyWithArgs("fromTo","/*","*/")}))},"nameFirst":function(){var $elf=this;return $elf._or((function(){return $elf._apply("letter")}),(function(){return $elf._applyWithArgs("exactly","$")}),(function(){return $elf._applyWithArgs("exactly","_")}))},"nameRest":function(){var $elf=this;return $elf._or((function(){return $elf._apply("nameFirst")}),(function(){return $elf._apply("digit")}))},"iName":function(){var $elf=this,r;return (function(){r=$elf._applyWithArgs("firstAndRest","nameFirst","nameRest");return r.join("")})()},"isKeyword":function(){var $elf=this,x;return (function(){x=$elf._apply("anything");return $elf._pred(BSJSParser._isKeyword(x))})()},"name":function(){var $elf=this,n;return (function(){n=$elf._apply("iName");$elf._not(function(){return $elf._applyWithArgs("isKeyword",n)});return ["name",(n == "self")?"$elf":n]})()},"keyword":function(){var $elf=this,k;return (function(){k=$elf._apply("iName");$elf._applyWithArgs("isKeyword",k);return [k,k]})()},"number":function(){var $elf=this,ws,fs;return (function(){ws=$elf._many1(function(){return $elf._apply("digit")});fs=$elf._or((function(){return (function(){$elf._applyWithArgs("exactly",".");return $elf._many1(function(){return $elf._apply("digit")})})()}),(function(){return (function(){$elf._apply("empty");return []})()}));return ["number",parseFloat(((ws.join("") + ".") + fs.join("")))]})()},"escapeChar":function(){var $elf=this,c;return (function(){$elf._applyWithArgs("exactly","\\");c=$elf._apply("char");return unescape(("\\" + c))})()},"str":function(){var $elf=this,cs,cs,cs,n;return $elf._or((function(){return (function(){$elf._applyWithArgs("seq","\"\"\"");cs=$elf._many(function(){return $elf._or((function(){return $elf._apply("escapeChar")}),(function(){return (function(){$elf._not(function(){return $elf._applyWithArgs("seq","\"\"\"")});return $elf._apply("char")})()}))});$elf._applyWithArgs("seq","\"\"\"");return ["string",cs.join("")]})()}),(function(){return (function(){$elf._applyWithArgs("exactly","\'");cs=$elf._many(function(){return $elf._or((function(){return $elf._apply("escapeChar")}),(function(){return (function(){$elf._not(function(){return $elf._applyWithArgs("exactly","\'")});return $elf._apply("char")})()}))});$elf._applyWithArgs("exactly","\'");return ["string",cs.join("")]})()}),(function(){return (function(){$elf._applyWithArgs("exactly","\"");cs=$elf._many(function(){return $elf._or((function(){return $elf._apply("escapeChar")}),(function(){return (function(){$elf._not(function(){return $elf._applyWithArgs("exactly","\"")});return $elf._apply("char")})()}))});$elf._applyWithArgs("exactly","\"");return ["string",cs.join("")]})()}),(function(){return (function(){$elf._or((function(){return $elf._applyWithArgs("exactly","#")}),(function(){return $elf._applyWithArgs("exactly","`")}));n=$elf._apply("iName");return ["string",n]})()}))},"special":function(){var $elf=this,s;return (function(){s=$elf._or((function(){return $elf._applyWithArgs("exactly","(")}),(function(){return $elf._applyWithArgs("exactly",")")}),(function(){return $elf._applyWithArgs("exactly","{")}),(function(){return $elf._applyWithArgs("exactly","}")}),(function(){return $elf._applyWithArgs("exactly","[")}),(function(){return $elf._applyWithArgs("exactly","]")}),(function(){return $elf._applyWithArgs("exactly",",")}),(function(){return $elf._applyWithArgs("exactly",";")}),(function(){return $elf._applyWithArgs("exactly","?")}),(function(){return $elf._applyWithArgs("exactly",":")}),(function(){return $elf._applyWithArgs("seq","!==")}),(function(){return $elf._applyWithArgs("seq","!=")}),(function(){return $elf._applyWithArgs("seq","===")}),(function(){return $elf._applyWithArgs("seq","==")}),(function(){return $elf._applyWithArgs("seq","=")}),(function(){return $elf._applyWithArgs("seq",">=")}),(function(){return $elf._applyWithArgs("exactly",">")}),(function(){return $elf._applyWithArgs("seq","<=")}),(function(){return $elf._applyWithArgs("exactly","<")}),(function(){return $elf._applyWithArgs("seq","++")}),(function(){return $elf._applyWithArgs("seq","+=")}),(function(){return $elf._applyWithArgs("exactly","+")}),(function(){return $elf._applyWithArgs("seq","--")}),(function(){return $elf._applyWithArgs("seq","-=")}),(function(){return $elf._applyWithArgs("exactly","-")}),(function(){return $elf._applyWithArgs("seq","*=")}),(function(){return $elf._applyWithArgs("exactly","*")}),(function(){return $elf._applyWithArgs("seq","/Line truncated
//////// bs-ometa-compiler.js
{BSOMetaParser=Parser.delegated({"fromTo":function(){var $elf=this,x,y;return (function(){x=$elf._apply("anything");y=$elf._apply("anything");$elf._applyWithArgs("seq",x);$elf._many(function(){return (function(){$elf._not(function(){return $elf._applyWithArgs("seq",y)});return $elf._apply("char")})()});return $elf._applyWithArgs("seq",y)})()},"space":function(){var $elf=this;return $elf._or((function(){return Parser._superApplyWithArgs($elf,"space")}),(function(){return $elf._applyWithArgs("fromTo","//","\n")}),(function(){return $elf._applyWithArgs("fromTo","/*","*/")}))},"nameFirst":function(){var $elf=this;return $elf._or((function(){return $elf._applyWithArgs("exactly","_")}),(function(){return $elf._applyWithArgs("exactly","$")}),(function(){return $elf._apply("letter")}))},"nameRest":function(){var $elf=this;return $elf._or((function(){return $elf._apply("nameFirst")}),(function(){return $elf._apply("digit")}))},"tsName":function(){var $elf=this,xs;return (function(){xs=$elf._applyWithArgs("firstAndRest","nameFirst","nameRest");return xs.join("")})()},"name":function(){var $elf=this;return (function(){$elf._apply("spaces");return $elf._apply("tsName")})()},"eChar":function(){var $elf=this,c;return $elf._or((function(){return (function(){$elf._applyWithArgs("exactly","\\");c=$elf._apply("char");return unescape(("\\" + c))})()}),(function(){return $elf._apply("char")}))},"tsString":function(){var $elf=this,xs;return (function(){$elf._applyWithArgs("exactly","\'");xs=$elf._many(function(){return (function(){$elf._not(function(){return $elf._applyWithArgs("exactly","\'")});return $elf._apply("eChar")})()});$elf._applyWithArgs("exactly","\'");return xs.join("")})()},"characters":function(){var $elf=this,xs;return (function(){$elf._applyWithArgs("exactly","`");$elf._applyWithArgs("exactly","`");xs=$elf._many(function(){return (function(){$elf._not(function(){return (function(){$elf._applyWithArgs("exactly","\'");return $elf._applyWithArgs("exactly","\'")})()});return $elf._apply("eChar")})()});$elf._applyWithArgs("exactly","\'");$elf._applyWithArgs("exactly","\'");return ["App","seq",xs.join("").toProgramString()]})()},"sCharacters":function(){var $elf=this,xs;return (function(){$elf._applyWithArgs("exactly","\"");xs=$elf._many(function(){return (function(){$elf._not(function(){return $elf._applyWithArgs("exactly","\"")});return $elf._apply("eChar")})()});$elf._applyWithArgs("exactly","\"");return ["App","token",xs.join("").toProgramString()]})()},"string":function(){var $elf=this,xs;return (function(){xs=$elf._or((function(){return (function(){$elf._or((function(){return $elf._applyWithArgs("exactly","#")}),(function(){return $elf._applyWithArgs("exactly","`")}));return $elf._apply("tsName")})()}),(function(){return $elf._apply("tsString")}));return ["App","exactly",xs.toProgramString()]})()},"number":function(){var $elf=this,sign,ds;return (function(){sign=$elf._or((function(){return $elf._applyWithArgs("exactly","-")}),(function(){return (function(){$elf._apply("empty");return ""})()}));ds=$elf._many1(function(){return $elf._apply("digit")});return ["App","exactly",(sign + ds.join(""))]})()},"keyword":function(){var $elf=this,xs;return (function(){xs=$elf._apply("anything");$elf._applyWithArgs("token",xs);$elf._not(function(){return $elf._apply("letterOrDigit")});return xs})()},"args":function(){var $elf=this,xs;return $elf._or((function(){return (function(){$elf._applyWithArgs("exactly","(");xs=$elf._applyWithArgs("listOf","hostExpr",",");$elf._applyWithArgs("token",")");return xs})()}),(function(){return (function(){$elf._apply("empty");return []})()}))},"application":function(){var $elf=this,rule,as;return (function(){rule=$elf._apply("name");as=$elf._apply("args");return ["App",rule].concat(as)})()},"hostExpr":function(){var $elf=this,r;return (function(){r=$elf._applyWithArgs("foreign",BSJSParser,"expr");return $elf._applyWithArgs("foreign",BSJSTranslator,"trans",r)})()},"atomicHostExpr":function(){var $elf=this,r;return (function(){r=$elf._applyWithArgs("foreign",BSJSParser,"semAction");return $elf._applyWithArgs("foreign",BSJSTranslator,"trans",r)})()},"curlyHostExpr":function(){var $elf=this,r;return (function(){r=$elf._applyWithArgs("foreign",BSJSParser,"curlySemAction");return $elf._applyWithArgs("foreign",BSJSTranslator,"trans",r)})()},"semAction":function(){var $elf=this,x,x;return $elf._or((function(){return (function(){$elf._or((function(){return $elf._applyWithArgs("token","!")}),(function(){return $elf._applyWithArgs("token","->")}));x=$elf._apply("atomicHostExpr");return ["Act",x]})()}),(function(){return (function(){x=$elf._apply("curlyHostExpr");return ["Act",x]})()}))},"semPred":function(){var $elf=this,x;return (function(){$elf._applyWithArgs("token","?");x=$elf._apply("atomicHostExpr");return ["Pred",x]})()},"expr":function(){var $elf=this,xs;return (function(){xs=$elf._applyWithArgs("listOf","expr4","|");return ["Or"].concat(xs)})()},"expr4":function(){var $elf=this,xs;return (funLine truncated
//////// bs-ometa-optimizer.js
{BSNullOptimization=OMeta.delegated();BSNullOptimization['setHelped']=function() {var $elf=this;return $elf["_didSomething"]=true};BSNullOptimization['helped']=function() {var $elf=this;return $elf._pred($elf["_didSomething"])};BSNullOptimization['trans']=function() {var $elf=this,t,ans;return $elf._or((function(){return (function(){$elf._form(function(){return (function(){t=$elf._apply("anything");$elf._pred($elf.hasProperty(t));return ans=$elf._applyWithArgs("apply", t)})()});return ans})()}),(function(){return $elf._apply("anything")}))};BSNullOptimization['optimize']=function() {var $elf=this,x;return (function(){x=$elf._apply("trans");$elf._apply("helped");return x})()};BSNullOptimization['Or']=function() {var $elf=this,xs;return (function(){xs=$elf._many(function(){return $elf._apply("trans")});return ["Or"].concat(xs)})()};BSNullOptimization['And']=function() {var $elf=this,xs;return (function(){xs=$elf._many(function(){return $elf._apply("trans")});return ["And"].concat(xs)})()};BSNullOptimization['Many']=function() {var $elf=this,x;return (function(){x=$elf._apply("trans");return ["Many",x]})()};BSNullOptimization['Many1']=function() {var $elf=this,x;return (function(){x=$elf._apply("trans");return ["Many1",x]})()};BSNullOptimization['Set']=function() {var $elf=this,n,v;return (function(){n=$elf._apply("anything");v=$elf._apply("trans");return ["Set",n,v]})()};BSNullOptimization['Not']=function() {var $elf=this,x;return (function(){x=$elf._apply("trans");return ["Not",x]})()};BSNullOptimization['Lookahead']=function() {var $elf=this,x;return (function(){x=$elf._apply("trans");return ["Lookahead",x]})()};BSNullOptimization['Form']=function() {var $elf=this,x;return (function(){x=$elf._apply("trans");return ["Form",x]})()};BSNullOptimization['Rule']=function() {var $elf=this,name,ls,body;return (function(){name=$elf._apply("anything");ls=$elf._apply("anything");body=$elf._apply("trans");return ["Rule",name,ls,body]})()};BSNullOptimization.prototype=BSNullOptimization;;BSNullOptimization["initialize"]=(function () {this["_didSomething"]=false});BSAndOrOptimization=BSNullOptimization.delegated();BSAndOrOptimization['And']=function() {var $elf=this,x,xs;return $elf._or((function(){return (function(){x=$elf._apply("trans");$elf._apply("end");$elf._apply("setHelped");return x})()}),(function(){return (function(){xs=$elf._applyWithArgs("transInside", "And");return ["And"].concat(xs)})()}))};BSAndOrOptimization['Or']=function() {var $elf=this,x,xs;return $elf._or((function(){return (function(){x=$elf._apply("trans");$elf._apply("end");$elf._apply("setHelped");return x})()}),(function(){return (function(){xs=$elf._applyWithArgs("transInside", "Or");return ["Or"].concat(xs)})()}))};BSAndOrOptimization['transInside']=function() {var $elf=this,t,xs,ys,x,xs;return (function(){t=$elf._apply("anything");return $elf._or((function(){return (function(){$elf._form(function(){return (function(){$elf._applyWithArgs("exactly", t);return xs=$elf._applyWithArgs("transInside", t)})()});ys=$elf._applyWithArgs("transInside", t);$elf._apply("setHelped");return xs.concat(ys)})()}),(function(){return (function(){x=$elf._apply("trans");xs=$elf._applyWithArgs("transInside", t);return [x].concat(xs)})()}),(function(){return []}))})()};BSAndOrOptimization.prototype=BSAndOrOptimization;;BSOMetaOptimizer=OMeta.delegated();BSOMetaOptimizer['optimizeGrammar']=function() {var $elf=this,n,sn,rs;return (function(){$elf._form(function(){return (function(){$elf._applyWithArgs("exactly", "Grammar");n=$elf._apply("anything");sn=$elf._apply("anything");return rs=$elf._many(function(){return $elf._apply("optimizeRule")})})()});return ["Grammar",n,sn].concat(rs)})()};BSOMetaOptimizer['optimizeRule']=function() {var $elf=this,r,r;return (function(){r=$elf._apply("anything");$elf._many(function(){return r=$elf._applyWithArgs("foreign", BSAndOrOptimization, "optimize", r)});return r})()};BSOMetaOptimizer.prototype=BSOMetaOptimizer;}
//////// bs-ometa-js-compiler.js
{BSOMetaJSParser=BSJSParser.delegated();BSOMetaJSParser['srcElem']=function() {var $elf=this,r;return $elf._or((function(){return (function(){$elf._apply("spaces");r=$elf._applyWithArgs("foreign", BSOMetaParser, "grammar");$elf._apply("sc");return r})()}),(function(){return BSJSParser._superApplyWithArgs($elf,"srcElem")}))};BSOMetaJSParser.prototype=BSOMetaJSParser;;BSOMetaJSTranslator=BSJSTranslator.delegated();BSOMetaJSTranslator['Grammar']=function() {var $elf=this;return $elf._applyWithArgs("foreign", BSOMetaTranslator, "Grammar")};BSOMetaJSTranslator.prototype=BSOMetaJSTranslator;}
+110
View File
@@ -0,0 +1,110 @@
OMeta._or = function() {
for (var idx = 0; idx < arguments.length; idx++) {
var ok = true
in thisWorld.sprout() {
try { return arguments[idx]() }
catch (f) {
ok = false
if (f != fail)
throw f
}
finally { if (ok) thisWorld.commit() }
}
}
throw fail
}
OMeta._many = function(x) {
var ans = arguments[1] != undefined ? [arguments[1]] : []
while (true) {
in thisWorld.sprout() {
try {
ans.push(x())
//print("committing " + ans.toString())
thisWorld.commit()
}
catch (f) {
if (f != fail)
throw f
break
}
}
}
return ans
}
OMeta._not = function(x) {
in thisWorld.sprout() {
try { x() }
catch (f) {
if (f != fail)
throw f
return true
}
}
throw fail
}
/*
OMeta._lookahead = function(x) {
in thisWorld.sprout() {
var r = x()
//print("la = " + r.toString())
return x
}
}
*/
/*
OMeta._apply = function(rule) {
var memoRec = this.input.memo[rule]
if (memoRec == undefined) {
var origInput = this.input,
failer = new Failer()
this.input.memo[rule] = failer
this.input.memo[rule] = memoRec = {ans: this[rule].apply(this), nextInput: this.input}
if (failer.used) {
var sentinel = this.input
while (true) {
try {
this.input = origInput
var ans = this[rule].apply(this)
if (this.input == sentinel)
throw fail
memoRec.ans = ans
memoRec.nextInput = this.input
}
catch (f) {
if (f != fail)
throw f
break
}
}
}
}
else if (memoRec instanceof Failer) {
memoRec.used = true
throw fail
}
this.input = memoRec.nextInput
return memoRec.ans
}
*/
print("defining example 1")
eval(BSOMetaJSTranslator.match(BSOMetaJSParser.matchAll("ometa M { ones = (1 -> 2)* }", "srcElem"), "trans"))
print("running example 1")
print(M.matchAll([1, 1, 1, 1], "ones"))
print("defining example 2")
eval(BSOMetaJSTranslator.match(BSOMetaJSParser.matchAll("ometa M { foo = &(:x) anything*:ys -> [x, ys] }", "srcElem"), "trans"))
print("running example 2")
print(M.matchAll([1, 2, 3, 4], "foo"))
print("defining example 3")
eval(BSOMetaJSTranslator.match(BSOMetaJSParser.matchAll("ometa M { ones = {count=0} ({count++} 1 -> 2)* }", "srcElem"), "trans"))
print("running example 3")
print(M.matchAll([1, 1, 1, 1], "ones"))
print("count = " + count)
+84
View File
@@ -0,0 +1,84 @@
# OMeta/JS
OMeta/JS is a JavaScript implementation of OMeta
## Main Repository
This repository is a forked version of the original intended to
provide an api to node.js and also a package for npm. Questions
about the core should be directed to the original author, Alessandro
Warth.
## Original README
The following files contain some important info:
* Not_Quite_JS.txt explains the difference between "real" JavaScript and
the JavaScript that can be used in the OMeta/JS Workspace.
* Things_You_Should_Know.txt explains the differences between the original
OMeta syntax (as it appeared in the DLS'07 paper) and the newer OMeta/js
syntax.
* OMeta_Tutorial.txt contains a bunch of examples that show how OMeta
can be used for pattern matching, parsing, etc.
Another good resource for OMeta programmers is the OMeta mailing list. To
subscribe, please visit:
http://vpri.org/mailman/listinfo/ometa
And you can also browse the archives of the mailing list at:
http://vpri.org/pipermail/ometa/
Cheers,
Alex
## MIT and Modified MIT License
Copyright (c) 2010 Brian Mavity
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Except as contained in this notice, the name(s) of the above copyright
holders shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written authorization.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2007-2010 Alessandro Warth
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+149
View File
@@ -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")
+112
View File
@@ -0,0 +1,112 @@
/*
Copyright (c) 2008, 2010 Alessandro Warth <[email protected]>
Limitations:
* assignments into the properties of "arguments" (e.g., arguments[5] = 1234) don't modify their respective variables
* for-in doesn't work when the loop variable is a property access (e.g., for (x.y in ys) ...)
*/
Array.prototype.each = function(f) {
for (var idx = 0; idx < this.length; idx++)
f(this[idx], idx)
}
ometa WJSParser <: BSJSParser {
isKeyword :x = ?(x == 'thisWorld')
| super('isKeyword', x),
primExprHd = "thisWorld" -> ['thisWorld']
| super('primExprHd'),
stmt = "in" expr:w block:b -> ['in', w, b]
| super('stmt')
}
makeFunction = function(fs, body) {
return '(function() { var staticScope = thisScope;' +
' var r = function() {' +
' var oldScope = thisScope;' +
' thisScope = staticScope.makeChild();' +
' thisScope.set("arguments", arguments);' +
' thisWorld.set(arguments, "length", arguments.length);' +
' for (var i = 0; i < arguments.length; i++) thisWorld.set(arguments, i, arguments[i]);' +
' try { ' + fs + body + '}' +
' finally { thisScope = oldScope }};' +
' baseWorld.set(r, "prototype", {parent: Object.prototype});' +
' return r })()' }
makeIn = function(w, body) {
return '{ try { worldStack.push(thisWorld); thisWorld = ' + w + '; ' + body + '} ' +
'finally { thisWorld = worldStack.pop() }' +
'undefined }'
}
makeForIn = function(v, e, s, decl) {
var p = tempnam(), ps = tempnam()
var r = 'for (var ' + p + ' in ' + ps + ' = thisWorld.props(' + e + ', {})) {' +
'if (!' + ps + '.hasOwnProperty(' + p + ')) continue; ' +
'thisScope.set("' + v + '", ' + p + '); ' + s +
'}'
if (decl)
r = 'thisScope.decl("' + v + '", undefined); ' + r
r = '{ var ' + ps + ' = undefined; ' + r + '}'
return r
}
ometa WJSTranslator <: BSJSTranslator {
initialize = { self.level = 0 },
fargs = [anything*:fs] -> { var ss = []
fs.each(function(v, i) { ss.push('thisScope.decl("' + v +
'", arguments[' + i + ']);') })
ss.join('') },
thisWorld -> 'thisWorld',
var :n trans:v -> ('thisScope.decl("' + n + '", ' + v + ')'),
get :n -> ('thisScope.get("' + n + '")'),
getp trans:p ['get' 'arguments'] -> ('arguments[' + p + ']'),
getp trans:p trans:x -> ('thisWorld.get(' + x + ', ' + p + ')'),
set ['get' :n] trans:v -> ('thisScope.set("' + n + '", ' + v + ')'),
set ['getp' trans:p ['get' 'arguments']] trans:v -> 'UNSUPPORTED OPERATION',
set ['getp' trans:p trans:x] trans:v -> ('thisWorld.set(' + x + ', ' + p + ', ' + v + ')'),
mset ['get' :n] :op trans:rhs -> ('thisScope.set("' + n + '", thisScope.get("' + n + '")' + op + rhs + ')'),
mset ['getp' trans:p trans:x] :op trans:rhs -> ('(function(r, p) { return thisWorld.set(r, p, thisWorld.get(r, p) ' +
op + ' ' + rhs + ') })(' + x + ', ' + p + ')'),
preop :op ['get' :n] -> ('thisScope.set("' + n + '", thisScope.get("' + n + '")' + op[0] + '1)'),
preop :op ['getp' trans:p trans:x] -> ('(function(r, p) { return thisWorld.set(r, p, thisWorld.get(r, p) ' +
op[0] + ' 1) })(' + x + ', ' + p + ')'),
postop :op ['get' :n] -> ('(function(n) { var ans = thisScope.get(n); ' +
'thisScope.set(n, ans ' + op[0] + ' 1); ' +
'return ans })("' + n + '")'),
postop :op ['getp' trans:p trans:x] -> ('(function(r, p) { var ans = thisWorld.get(r, p); ' +
'thisWorld.set(r, p, ans ' + op[0] + ' 1); ' +
'return ans })(' + x + ', ' + p + ')'),
binop 'instanceof' trans:x trans:y -> ('instanceOf(' + x + ', ' + y + ')'),
binop :op trans:x trans:y -> ('(' + x + ' ' + op + ' ' + y + ')'),
call trans:f trans*:as -> ('(' + f + ')(' + as.join(',') + ')'),
send :m trans:r trans*:as -> ('send("' + m + '", ' + r + ', [' + as.join(',') + '])'),
new :x trans*:as -> ('thisScope.get("' + x + '").worldsNew(' + as.join(',') + ')'),
func fargs:fs {self.level++} trans:body
{self.level--} -> makeFunction(fs, body),
in trans:w trans:b -> makeIn(w, b),
arr trans*:xs -> ('[' + xs.join(',') + '].toWJSArray()'),
json trans*:xs -> ('({' + xs.join(',') + '}).toWJSObject()'),
try curlyTrans:x :name curlyTrans:c curlyTrans:f -> { var e = tempnam()
'try ' + x +
'catch(' + e + ') {thisScope.decl("' + name + '", ' + e + '); ' + c + '}' +
'finally' + f },
forIn ['get' :v ] trans:e trans:s -> makeForIn(v, e, s, false),
forIn ['var' :v :init] trans:e trans:s -> makeForIn(v, e, s, true)
}
compileWJS = function(code) {
var tree = WJSParser.matchAll(code, "topLevel", undefined, function(m, i) { throw fail.delegated({errorPos: i}) })
//print("parsed: " + tree)
var code = WJSTranslator.match(tree, 'trans')
//print("compiled: " + code)
return code
}
thisScope.decl("eval", function(s) { return eval(compileWJS(s)) })
oldPrint = print
print = function(x) { oldPrint(x == undefined || x == null ? x : send("toString", x)) }
translateCode = compileWJS
+311
View File
@@ -0,0 +1,311 @@
// Copyright (c) 2008, 2010 Alessandro Warth <[email protected]>
DEBUG = false;
// getTag: object -> unique id
// tagToRef: unique id -> object
// Note: this hashing scheme causes a huge memory leak (all b/c JS doesn't support weak references)
(function() {
var numIdx = 0, tagToRef = {}
var _getTag = function(r) {
if (r === null || r === undefined)
return r
switch (typeof r) {
case "boolean": return r == true ? "Btrue" : "Bfalse"
case "string": return "S" + r
case "number": return "N" + r
default: return r.hasOwnProperty("_id_") ? r._id_ : r._id_ = "R" + numIdx++
}
}
getTag = function(r) {
var tag = _getTag(r)
tagToRef[tag] = r
return tag
}
getRef = function(t) {
return tagToRef[t]
}
})()
// implementation of possible worlds
worldProto = {}
baseWorld = thisWorld = (function() {
var writes = {}
return {
parent: worldProto,
writes: writes,
hasOwn: function(r, p) {
var id = getTag(r)
return writes.hasOwnProperty(id) && writes[id].hasOwnProperty(p)
},
has: function(r, p) {
return this.hasOwn(r, p) ||
r !== Object.prototype && this.has(r === null || r === undefined ? Object.prototype : r.parent, p)
},
props: function(r, ps) {
var id = getTag(r)
if (writes.hasOwnProperty(id))
for (var p in writes[id])
if (writes[id].hasOwnProperty(p))
ps[p] = true
if (r !== Object.prototype)
this.props(r === null || r === undefined ? Object.prototype : r.parent, ps)
return ps
},
_get: function(r, p) {
var id = getTag(r)
if (DEBUG) console.log("? top-level world looking up " + id + "." + p)
if (writes.hasOwnProperty(id) && writes[id].hasOwnProperty(p))
return writes[id][p]
else if (r !== Object.prototype)
return thisWorld._get(r === null || r === undefined ? Object.prototype : r.parent, p)
else
return undefined
},
get: function(r, p) {
// the top-level world's commit operation is a no-op, so reads don't have to be recorded
if (typeof r === "string" && (typeof p === "number" || p === "length"))
return r[p]
else
return this._get(r, p)
},
set: function(r, p, v) {
if (typeof r === "string" && (typeof p === "number" || p === "length"))
throw "the indices and length of a string are immutable, and you tried to change them!"
var id = getTag(r)
if (DEBUG) console.log("! top-level world assigning to " + id + "." + p)
if (!writes.hasOwnProperty(id))
writes[id] = {}
writes[id][p] = v
return v
},
commit: function() { },
sprout: function() {
var parentWorld = this, writes = {}, reads = {}
return {
parent: worldProto,
writes: writes,
reads: reads,
hasOwn: function(r, p) {
var id = getTag(r)
return writes.hasOwnProperty(id) && writes[id].hasOwnProperty(p) ||
reads.hasOwnProperty(id) && reads[id].hasOwnProperty(p) ||
parentWorld.hasOwn(r, p)
},
has: function(r, p) {
return this.hasOwn(r, p) ||
r !== Object.prototype && this.has(r === null || r === undefined ? Object.prototype : r.parent, p)
},
props: function(r, ps) {
var id = getTag(r)
if (writes.hasOwnProperty(id))
for (var p in writes[id])
if (writes[id].hasOwnProperty(p))
ps[p] = true
if (reads.hasOwnProperty(id))
for (var p in reads[id])
if (reads[id].hasOwnProperty(p))
ps[p] = true
if (r !== Object.prototype)
this.props(r === null || r === undefined ? Object.prototype : r.parent, ps)
parentWorld.props(r, ps)
return ps
},
_get: function(r, p) {
var id = getTag(r)
if (DEBUG) console.log("? child world looking up " + id + "." + p)
if (writes.hasOwnProperty(id) && writes[id].hasOwnProperty(p))
return writes[id][p]
else if (reads.hasOwnProperty(id) && reads[id].hasOwnProperty(p))
return reads[id][p]
else
return parentWorld._get(r, p)
},
get: function(r, p) {
if (typeof r === "string" && (typeof p === "number" || p === "length"))
return r[p]
var id = getTag(r), ans = this._get(r, p)
if (!reads.hasOwnProperty(id)) {
reads[id] = {}
if (!reads[id].hasOwnProperty(p))
reads[id][p] = ans
}
return ans
},
set: function(r, p, v) {
if (typeof r === "string" && (typeof p === "number" || p === "length"))
throw "the indices and length of a string are immutable, and you tried to change them!"
var id = getTag(r)
if (DEBUG) console.log("! child world assigning to " + id + "." + p)
if (!writes.hasOwnProperty(id))
writes[id] = {}
writes[id][p] = v
return v
},
commit: function() {
// serializability check
for (var id in reads) {
if (!reads.hasOwnProperty(id))
continue
for (var p in reads[id]) {
if (!reads[id].hasOwnProperty(p))
continue
else if (reads[id][p] !== parentWorld._get(getRef(id), p))
throw "commit failed"
}
}
// propagation of side effects
for (var id in writes) {
if (!writes.hasOwnProperty(id))
continue
for (var p in writes[id]) {
if (!writes[id].hasOwnProperty(p))
continue
if (!parentWorld.writes.hasOwnProperty(id))
parentWorld.writes[id] = {}
if (DEBUG) console.log("committing " + id + "." + p)
parentWorld.writes[id][p] = writes[id][p]
}
}
writes = {}
reads = {}
},
sprout: parentWorld.sprout
}
}
}
})()
worldStack = [thisWorld]
// Lexical scopes
GlobalScope = function() { }
GlobalScope.prototype = {
parent: Object.prototype,
hasOwn: function(n) { return thisWorld.hasOwn(this, n) },
has: function(n) { return thisWorld.has(this, n) },
get: function(n) { return thisWorld.get(this, n) },
set: function(n, v) { return thisWorld.set(this, n, v) },
decl: function(n, v) { return baseWorld.set(this, n, v) },
makeChild: function() { return new ActivationRecord(this) }
}
ActivationRecord = function(parent) { this.parent = parent }
ActivationRecord.prototype = new GlobalScope()
ActivationRecord.prototype.get = function(n) { return thisWorld.has(this, n) ?
thisWorld.get(this, n) :
this.parent.get(n) }
ActivationRecord.prototype.set = function(n, v) { return thisWorld.has(this, n) ?
thisWorld.set(this, n, v) :
this.parent.set(n, v) }
thisScope = new GlobalScope()
// Sends
send = function(sel, recv, args) {
//alert("doing a send, sel=" + sel + ", recv=" + recv + ", args=" + args)
return thisWorld.get(recv, sel).apply(recv, args)
}
// New
Function.prototype.worldsNew = function() {
var r = {parent: thisWorld.get(this, "prototype")}
this.apply(r, arguments)
return r
}
// instanceof
instanceOf = function(x, C) {
var p = x.parent, Cp = thisWorld.get(C, "prototype")
while (p != undefined) {
if (p == Cp)
return true
p = p.parent
}
return false
}
// Some globals, etc.
wObject = function() { }
thisScope.decl("Object", wObject)
thisWorld.set(wObject, "prototype", Object.prototype)
thisWorld.set(Object.prototype, "hasOwn", function(p) { return thisWorld.has(this, p) })
thisWorld.set(Object.prototype, "toString", function() { return "" + this })
thisWorld.set(worldProto, "sprout", function() { return this.sprout() })
thisWorld.set(worldProto, "commit", function() { return this.commit() })
thisWorld.set(worldProto, "toString", function() { return "[World " + this.getTag() + "]" })
wWorld = function() { }; thisScope.decl("World", wWorld); thisWorld.set(wWorld, "prototype", worldProto)
wBoolean = function() { }; thisScope.decl("Boolean", wBoolean); thisWorld.set(wBoolean, "prototype", {parent: Object.prototype})
wNumber = function() { }; thisScope.decl("Number", wNumber); thisWorld.set(wNumber, "prototype", {parent: Object.prototype})
wString = function() { }; thisScope.decl("String", wString); thisWorld.set(wString, "prototype", {parent: Object.prototype})
wArray = function() { }; thisScope.decl("Array", wArray); thisWorld.set(wArray, "prototype", {parent: Object.prototype})
wFunction = function() { }; thisScope.decl("Function", wFunction); thisWorld.set(wFunction, "prototype", {parent: Object.prototype})
Boolean.prototype.parent = thisWorld.get(wBoolean, "prototype")
Number.prototype.parent = thisWorld.get(wNumber, "prototype")
String.prototype.parent = thisWorld.get(wString, "prototype")
Function.prototype.parent = thisWorld.get(wFunction, "prototype")
// Don't need to do this for Array because Worlds/JS arrays are not JS arrays
thisWorld.set(wString, "fromCharCode", function(x) { return String.fromCharCode(x) })
thisWorld.set(String.prototype.parent, "charCodeAt", function(x) { return this.charCodeAt(x) })
thisWorld.set(Function.prototype.parent, "apply", function(recv, args) {
var jsArgs
if (args && thisWorld.get(args, "length") > 0) {
jsArgs = []
for (var idx = 0; idx < thisWorld.get(args, "length"); idx++)
jsArgs.push(thisWorld.get(args, idx))
}
return this.apply(recv, jsArgs)
})
thisWorld.set(Function.prototype.parent, "call", function(recv) {
var jsArgs = []
for (var idx = 1; idx < arguments.length; idx++)
jsArgs.push(arguments[idx])
return this.apply(recv, jsArgs)
})
thisScope.decl("null", null)
thisScope.decl("undefined", undefined)
thisScope.decl("true", true)
thisScope.decl("false", false)
thisScope.decl("jsEval", function(s) { return eval(thisWorld.get(s, "toString").call(s)) })
thisScope.decl("print", function(s) { print(thisWorld.get(s, "toString").call(s)) })
thisScope.decl("alert", function(s) { alert(thisWorld.get(s, "toString").call(s)) })
thisScope.decl("prompt", function(s) { return prompt(thisWorld.get(s, "toString").call(s)) })
thisScope.decl("confirm", function(s) { return confirm(thisWorld.get(s, "toString").call(s)) })
thisScope.decl("parseInt", function(s) { return parseInt(s) })
thisScope.decl("parseFloat", function(s) { return parseFloat(s) })
WorldsConsole = {}
thisScope.decl("console", WorldsConsole)
thisWorld.set(WorldsConsole, "log", function(s) { Transcript.show(thisWorld.get(s, "toString").apply(s)) })
Array.prototype.toWJSArray = function() {
var r = wArray.worldsNew()
for (var idx = 0; idx < this.length; idx++)
thisWorld.set(r, idx, this[idx])
thisWorld.set(r, "length", this.length)
return r
}
Object.prototype.toWJSObject = function() {
var r = wObject.worldsNew()
for (var p in this)
if (this.hasOwnProperty(p))
thisWorld.set(r, p, this[p])
return r
}
+35
View File
@@ -0,0 +1,35 @@
Array.prototype.toString = function() {
var r = "["
for (var idx = 0; idx < this.length; idx = idx + 1) {
if (idx > 0)
r = r + ", "
r = r + this[idx].toString()
}
return r + "]"
}
Array.prototype.push = function(x) {
this[this.length] = x
this.length = this.length + 1
return x
}
Array.prototype.pop = function() {
var r = this[this.length - 1]
this[this.length - 1] = undefined
this.length = this.length - 1
return r
}
Array.prototype.join = function(delim) {
var r = ""
for (var idx = 0; idx < this.length; idx++) {
if (idx > 0)
r += delim
r += this[idx]
}
return r
}
Array.prototype.concat = function(xs) {
for (var idx = 0; idx < xs.length; idx++)
this.push(xs[idx])
return this
}
+81
View File
@@ -0,0 +1,81 @@
{BSJSParser=objectThatDelegatesTo(Parser,{
"fromTo":function(){var $elf=this,_fromIdx=this.input.idx,x,y;return (function(){x=this._apply("anything");y=this._apply("anything");this._applyWithArgs("seq",x);this._many((function(){return (function(){this._not((function(){return this._applyWithArgs("seq",y)}));return this._apply("char")}).call(this)}));return this._applyWithArgs("seq",y)}).call(this)},
"space":function(){var $elf=this,_fromIdx=this.input.idx;return this._or((function(){return Parser._superApplyWithArgs(this,'space')}),(function(){return this._applyWithArgs("fromTo","//","\n")}),(function(){return this._applyWithArgs("fromTo","/*","*/")}))},
"nameFirst":function(){var $elf=this,_fromIdx=this.input.idx;return this._or((function(){return this._apply("letter")}),(function(){return (function(){switch(this._apply('anything')){case "$":return "$";case "_":return "_";default: throw fail}}).call(this)}))},
"nameRest":function(){var $elf=this,_fromIdx=this.input.idx;return this._or((function(){return this._apply("nameFirst")}),(function(){return this._apply("digit")}))},
"iName":function(){var $elf=this,_fromIdx=this.input.idx,r;return (function(){r=this._applyWithArgs("firstAndRest","nameFirst","nameRest");return r.join("")}).call(this)},
"isKeyword":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("anything");return this._pred(BSJSParser._isKeyword(x))}).call(this)},
"name":function(){var $elf=this,_fromIdx=this.input.idx,n;return (function(){n=this._apply("iName");this._not((function(){return this._applyWithArgs("isKeyword",n)}));return ["name",((n == "self")?"$elf":n)]}).call(this)},
"keyword":function(){var $elf=this,_fromIdx=this.input.idx,k;return (function(){k=this._apply("iName");this._applyWithArgs("isKeyword",k);return [k,k]}).call(this)},
"hexDigit":function(){var $elf=this,_fromIdx=this.input.idx,x,v;return (function(){x=this._apply("char");v=this["hexDigits"].indexOf(x.toLowerCase());this._pred((v >= (0)));return v}).call(this)},
"hexLit":function(){var $elf=this,_fromIdx=this.input.idx,n,d;return this._or((function(){return (function(){n=this._apply("hexLit");d=this._apply("hexDigit");return ((n * (16)) + d)}).call(this)}),(function(){return this._apply("hexDigit")}))},
"number":function(){var $elf=this,_fromIdx=this.input.idx,n,ws,fs;return this._or((function(){return (function(){switch(this._apply('anything')){case "0":return (function(){this._applyWithArgs("exactly","x");"0x";n=this._apply("hexLit");return ["number",n]}).call(this);default: throw fail}}).call(this)}),(function(){return (function(){ws=this._many1((function(){return this._apply("digit")}));fs=this._or((function(){return (function(){switch(this._apply('anything')){case ".":return this._many1((function(){return this._apply("digit")}));default: throw fail}}).call(this)}),(function(){return (function(){this._apply("empty");return []}).call(this)}));return ["number",parseFloat(((ws.join("") + ".") + fs.join("")))]}).call(this)}))},
"escapeChar":function(){var $elf=this,_fromIdx=this.input.idx,c;return (function(){this._applyWithArgs("exactly","\\");c=this._apply("char");return unescape(("\\" + c))}).call(this)},
"str":function(){var $elf=this,_fromIdx=this.input.idx,cs,cs,cs,n;return this._or((function(){return (function(){switch(this._apply('anything')){case "\"":return this._or((function(){return (function(){switch(this._apply('anything')){case "\"":return (function(){this._applyWithArgs("exactly","\"");"\"\"\"";cs=this._many((function(){return this._or((function(){return this._apply("escapeChar")}),(function(){return (function(){this._not((function(){return (function(){this._applyWithArgs("exactly","\"");this._applyWithArgs("exactly","\"");this._applyWithArgs("exactly","\"");return "\"\"\""}).call(this)}));return this._apply("char")}).call(this)}))}));this._applyWithArgs("exactly","\"");this._applyWithArgs("exactly","\"");this._applyWithArgs("exactly","\"");"\"\"\"";return ["string",cs.join("")]}).call(this);default: throw fail}}).call(this)}),(function(){return (function(){cs=this._many((function(){return this._or((function(){return this._apply("escapeChar")}),(function(){return (function(){this._not((function(){return this._applyWithArgs("exactly","\"")}));return this._apply("char")}).call(this)}))}));this._applyWithArgs("exactly","\"");return ["string",cs.join("")]}).call(this)}));case "\'":return (function(){cs=this._many((function(){return this._or((function(){return this._apply("escapeChar")}),(function(){return (function(){this._not((function(){return this._applyWithArgs("exactly","\'")}));return this._apply("char")}).call(this)}))}));this._applyWithArgs("exactly","\'");return ["string",cs.join("")]}).call(this);default: throw fail}}).call(this)}),(function(){return (function(){(function(){switch(this._apply('anything')){case "#":return "#";case "`":return "`";default: throw fail}}).call(this);n=this._apply("iName");return ["string",n]}).call(this)}))},
"special":function(){var $elf=this,_fromIdx=this.input.idx,s;return (function(){s=(function(){switch(this._apply('anything')){case "(":return "(";case ")":return ")";case "{":return "{";case "}":return "}";case "[":return "[";case "]":return "]";case ",":return ",";case ";":return ";";case "?":return "?";case ":":return ":";case "!":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return "!==";default: throw fail}}).call(this)}),(function(){return "!="}));default: throw fail}}).call(this)}),(function(){return "!"}));case "=":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return "===";default: throw fail}}).call(this)}),(function(){return "=="}));default: throw fail}}).call(this)}),(function(){return "="}));case ">":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return ">=";default: throw fail}}).call(this)}),(function(){return ">"}));case "<":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return "<=";default: throw fail}}).call(this)}),(function(){return "<"}));case "+":return this._or((function(){return (function(){switch(this._apply('anything')){case "+":return "++";case "=":return "+=";default: throw fail}}).call(this)}),(function(){return "+"}));case "-":return this._or((function(){return (function(){switch(this._apply('anything')){case "-":return "--";case "=":return "-=";default: throw fail}}).call(this)}),(function(){return "-"}));case "*":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return "*=";default: throw fail}}).call(this)}),(function(){return "*"}));case "/":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return "/=";default: throw fail}}).call(this)}),(function(){return "/"}));case "%":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return "%=";default: throw fail}}).call(this)}),(function(){return "%"}));case "&":return (function(){switch(this._apply('anything')){case "&":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return "&&=";default: throw fail}}).call(this)}),(function(){return "&&"}));default: throw fail}}).call(this);case "|":return (function(){switch(this._apply('anything')){case "|":return this._or((function(){return (function(){switch(this._apply('anything')){case "=":return "||=";default: throw fail}}).call(this)}),(function(){return "||"}));default: throw fail}}).call(this);case ".":return ".";default: throw fail}}).call(this);return [s,s]}).call(this)},
"tok":function(){var $elf=this,_fromIdx=this.input.idx;return (function(){this._apply("spaces");return this._or((function(){return this._apply("name")}),(function(){return this._apply("keyword")}),(function(){return this._apply("number")}),(function(){return this._apply("str")}),(function(){return this._apply("special")}))}).call(this)},
"toks":function(){var $elf=this,_fromIdx=this.input.idx,ts;return (function(){ts=this._many((function(){return this._apply("token")}));this._apply("spaces");this._apply("end");return ts}).call(this)},
"token":function(){var $elf=this,_fromIdx=this.input.idx,tt,t;return (function(){tt=this._apply("anything");t=this._apply("tok");this._pred((t[(0)] == tt));return t[(1)]}).call(this)},
"spacesNoNl":function(){var $elf=this,_fromIdx=this.input.idx;return this._many((function(){return (function(){this._not((function(){return this._applyWithArgs("exactly","\n")}));return this._apply("space")}).call(this)}))},
"expr":function(){var $elf=this,_fromIdx=this.input.idx,e,t,f,rhs,rhs,rhs,rhs,rhs,rhs,rhs,rhs;return (function(){e=this._apply("orExpr");return this._or((function(){return (function(){this._applyWithArgs("token","?");t=this._apply("expr");this._applyWithArgs("token",":");f=this._apply("expr");return ["condExpr",e,t,f]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","=");rhs=this._apply("expr");return ["set",e,rhs]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","+=");rhs=this._apply("expr");return ["mset",e,"+",rhs]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","-=");rhs=this._apply("expr");return ["mset",e,"-",rhs]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","*=");rhs=this._apply("expr");return ["mset",e,"*",rhs]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","/=");rhs=this._apply("expr");return ["mset",e,"/",rhs]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","%=");rhs=this._apply("expr");return ["mset",e,"%",rhs]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","&&=");rhs=this._apply("expr");return ["mset",e,"&&",rhs]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","||=");rhs=this._apply("expr");return ["mset",e,"||",rhs]}).call(this)}),(function(){return (function(){this._apply("empty");return e}).call(this)}))}).call(this)},
"orExpr":function(){var $elf=this,_fromIdx=this.input.idx,x,y;return this._or((function(){return (function(){x=this._apply("orExpr");this._applyWithArgs("token","||");y=this._apply("andExpr");return ["binop","||",x,y]}).call(this)}),(function(){return this._apply("andExpr")}))},
"andExpr":function(){var $elf=this,_fromIdx=this.input.idx,x,y;return this._or((function(){return (function(){x=this._apply("andExpr");this._applyWithArgs("token","&&");y=this._apply("eqExpr");return ["binop","&&",x,y]}).call(this)}),(function(){return this._apply("eqExpr")}))},
"eqExpr":function(){var $elf=this,_fromIdx=this.input.idx,x,y,y,y,y;return this._or((function(){return (function(){x=this._apply("eqExpr");return this._or((function(){return (function(){this._applyWithArgs("token","==");y=this._apply("relExpr");return ["binop","==",x,y]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","!=");y=this._apply("relExpr");return ["binop","!=",x,y]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","===");y=this._apply("relExpr");return ["binop","===",x,y]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","!==");y=this._apply("relExpr");return ["binop","!==",x,y]}).call(this)}))}).call(this)}),(function(){return this._apply("relExpr")}))},
"relExpr":function(){var $elf=this,_fromIdx=this.input.idx,x,y,y,y,y,y;return this._or((function(){return (function(){x=this._apply("relExpr");return this._or((function(){return (function(){this._applyWithArgs("token",">");y=this._apply("addExpr");return ["binop",">",x,y]}).call(this)}),(function(){return (function(){this._applyWithArgs("token",">=");y=this._apply("addExpr");return ["binop",">=",x,y]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","<");y=this._apply("addExpr");return ["binop","<",x,y]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","<=");y=this._apply("addExpr");return ["binop","<=",x,y]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","instanceof");y=this._apply("addExpr");return ["binop","instanceof",x,y]}).call(this)}))}).call(this)}),(function(){return this._apply("addExpr")}))},
"addExpr":function(){var $elf=this,_fromIdx=this.input.idx,x,y,x,y;return this._or((function(){return (function(){x=this._apply("addExpr");this._applyWithArgs("token","+");y=this._apply("mulExpr");return ["binop","+",x,y]}).call(this)}),(function(){return (function(){x=this._apply("addExpr");this._applyWithArgs("token","-");y=this._apply("mulExpr");return ["binop","-",x,y]}).call(this)}),(function(){return this._apply("mulExpr")}))},
"mulExpr":function(){var $elf=this,_fromIdx=this.input.idx,x,y,x,y,x,y;return this._or((function(){return (function(){x=this._apply("mulExpr");this._applyWithArgs("token","*");y=this._apply("unary");return ["binop","*",x,y]}).call(this)}),(function(){return (function(){x=this._apply("mulExpr");this._applyWithArgs("token","/");y=this._apply("unary");return ["binop","/",x,y]}).call(this)}),(function(){return (function(){x=this._apply("mulExpr");this._applyWithArgs("token","%");y=this._apply("unary");return ["binop","%",x,y]}).call(this)}),(function(){return this._apply("unary")}))},
"unary":function(){var $elf=this,_fromIdx=this.input.idx,p,p,p,p,p,p,p,p;return this._or((function(){return (function(){this._applyWithArgs("token","-");p=this._apply("postfix");return ["unop","-",p]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","+");p=this._apply("postfix");return ["unop","+",p]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","++");p=this._apply("postfix");return ["preop","++",p]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","--");p=this._apply("postfix");return ["preop","--",p]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","!");p=this._apply("unary");return ["unop","!",p]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","void");p=this._apply("unary");return ["unop","void",p]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","delete");p=this._apply("unary");return ["unop","delete",p]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","typeof");p=this._apply("unary");return ["unop","typeof",p]}).call(this)}),(function(){return this._apply("postfix")}))},
"postfix":function(){var $elf=this,_fromIdx=this.input.idx,p;return (function(){p=this._apply("primExpr");return this._or((function(){return (function(){this._apply("spacesNoNl");this._applyWithArgs("token","++");return ["postop","++",p]}).call(this)}),(function(){return (function(){this._apply("spacesNoNl");this._applyWithArgs("token","--");return ["postop","--",p]}).call(this)}),(function(){return (function(){this._apply("empty");return p}).call(this)}))}).call(this)},
"primExpr":function(){var $elf=this,_fromIdx=this.input.idx,p,i,m,as,f,as;return this._or((function(){return (function(){p=this._apply("primExpr");return this._or((function(){return (function(){this._applyWithArgs("token","[");i=this._apply("expr");this._applyWithArgs("token","]");return ["getp",i,p]}).call(this)}),(function(){return (function(){this._applyWithArgs("token",".");m=this._applyWithArgs("token","name");this._applyWithArgs("token","(");as=this._applyWithArgs("listOf","expr",",");this._applyWithArgs("token",")");return ["send",m,p].concat(as)}).call(this)}),(function(){return (function(){this._applyWithArgs("token",".");f=this._applyWithArgs("token","name");return ["getp",["string",f],p]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","(");as=this._applyWithArgs("listOf","expr",",");this._applyWithArgs("token",")");return ["call",p].concat(as)}).call(this)}))}).call(this)}),(function(){return this._apply("primExprHd")}))},
"primExprHd":function(){var $elf=this,_fromIdx=this.input.idx,e,n,n,s,n,as,es;return this._or((function(){return (function(){this._applyWithArgs("token","(");e=this._apply("expr");this._applyWithArgs("token",")");return e}).call(this)}),(function(){return (function(){this._applyWithArgs("token","this");return ["this"]}).call(this)}),(function(){return (function(){n=this._applyWithArgs("token","name");return ["get",n]}).call(this)}),(function(){return (function(){n=this._applyWithArgs("token","number");return ["number",n]}).call(this)}),(function(){return (function(){s=this._applyWithArgs("token","string");return ["string",s]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","function");return this._apply("funcRest")}).call(this)}),(function(){return (function(){this._applyWithArgs("token","new");n=this._applyWithArgs("token","name");this._applyWithArgs("token","(");as=this._applyWithArgs("listOf","expr",",");this._applyWithArgs("token",")");return ["new",n].concat(as)}).call(this)}),(function(){return (function(){this._applyWithArgs("token","[");es=this._applyWithArgs("listOf","expr",",");this._applyWithArgs("token","]");return ["arr"].concat(es)}).call(this)}),(function(){return this._apply("json")}))},
"json":function(){var $elf=this,_fromIdx=this.input.idx,bs;return (function(){this._applyWithArgs("token","{");bs=this._applyWithArgs("listOf","jsonBinding",",");this._applyWithArgs("token","}");return ["json"].concat(bs)}).call(this)},
"jsonBinding":function(){var $elf=this,_fromIdx=this.input.idx,n,v;return (function(){n=this._apply("jsonPropName");this._applyWithArgs("token",":");v=this._apply("expr");return ["binding",n,v]}).call(this)},
"jsonPropName":function(){var $elf=this,_fromIdx=this.input.idx;return this._or((function(){return this._applyWithArgs("token","name")}),(function(){return this._applyWithArgs("token","number")}),(function(){return this._applyWithArgs("token","string")}))},
"formal":function(){var $elf=this,_fromIdx=this.input.idx;return (function(){this._apply("spaces");return this._applyWithArgs("token","name")}).call(this)},
"funcRest":function(){var $elf=this,_fromIdx=this.input.idx,fs,body;return (function(){this._applyWithArgs("token","(");fs=this._applyWithArgs("listOf","formal",",");this._applyWithArgs("token",")");this._applyWithArgs("token","{");body=this._apply("srcElems");this._applyWithArgs("token","}");return ["func",fs,body]}).call(this)},
"sc":function(){var $elf=this,_fromIdx=this.input.idx;return this._or((function(){return (function(){this._apply("spacesNoNl");return this._or((function(){return (function(){switch(this._apply('anything')){case "\n":return "\n";default: throw fail}}).call(this)}),(function(){return this._lookahead((function(){return this._applyWithArgs("exactly","}")}))}),(function(){return this._apply("end")}))}).call(this)}),(function(){return this._applyWithArgs("token",";")}))},
"binding":function(){var $elf=this,_fromIdx=this.input.idx,n,v;return (function(){n=this._applyWithArgs("token","name");v=this._or((function(){return (function(){this._applyWithArgs("token","=");return this._apply("expr")}).call(this)}),(function(){return (function(){this._apply("empty");return ["get","undefined"]}).call(this)}));return ["var",n,v]}).call(this)},
"block":function(){var $elf=this,_fromIdx=this.input.idx,ss;return (function(){this._applyWithArgs("token","{");ss=this._apply("srcElems");this._applyWithArgs("token","}");return ss}).call(this)},
"stmt":function(){var $elf=this,_fromIdx=this.input.idx,bs,c,t,f,c,s,s,c,i,c,u,s,n,v,e,s,e,c,cs,cs,cs,e,t,e,c,f,e,x,s,e;return this._or((function(){return this._apply("block")}),(function(){return (function(){this._applyWithArgs("token","var");bs=this._applyWithArgs("listOf","binding",",");this._apply("sc");return ["begin"].concat(bs)}).call(this)}),(function(){return (function(){this._applyWithArgs("token","if");this._applyWithArgs("token","(");c=this._apply("expr");this._applyWithArgs("token",")");t=this._apply("stmt");f=this._or((function(){return (function(){this._applyWithArgs("token","else");return this._apply("stmt")}).call(this)}),(function(){return (function(){this._apply("empty");return ["get","undefined"]}).call(this)}));return ["if",c,t,f]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","while");this._applyWithArgs("token","(");c=this._apply("expr");this._applyWithArgs("token",")");s=this._apply("stmt");return ["while",c,s]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","do");s=this._apply("stmt");this._applyWithArgs("token","while");this._applyWithArgs("token","(");c=this._apply("expr");this._applyWithArgs("token",")");this._apply("sc");return ["doWhile",s,c]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","for");this._applyWithArgs("token","(");i=this._or((function(){return (function(){this._applyWithArgs("token","var");return this._apply("binding")}).call(this)}),(function(){return this._apply("expr")}),(function(){return (function(){this._apply("empty");return ["get","undefined"]}).call(this)}));this._applyWithArgs("token",";");c=this._or((function(){return this._apply("expr")}),(function(){return (function(){this._apply("empty");return ["get","true"]}).call(this)}));this._applyWithArgs("token",";");u=this._or((function(){return this._apply("expr")}),(function(){return (function(){this._apply("empty");return ["get","undefined"]}).call(this)}));this._applyWithArgs("token",")");s=this._apply("stmt");return ["for",i,c,u,s]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","for");this._applyWithArgs("token","(");v=this._or((function(){return (function(){this._applyWithArgs("token","var");n=this._applyWithArgs("token","name");return ["var",n,["get","undefined"]]}).call(this)}),(function(){return this._apply("expr")}));this._applyWithArgs("token","in");e=this._apply("expr");this._applyWithArgs("token",")");s=this._apply("stmt");return ["forIn",v,e,s]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","switch");this._applyWithArgs("token","(");e=this._apply("expr");this._applyWithArgs("token",")");this._applyWithArgs("token","{");cs=this._many((function(){return this._or((function(){return (function(){this._applyWithArgs("token","case");c=this._apply("expr");this._applyWithArgs("token",":");cs=this._apply("srcElems");return ["case",c,cs]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","default");this._applyWithArgs("token",":");cs=this._apply("srcElems");return ["default",cs]}).call(this)}))}));this._applyWithArgs("token","}");return ["switch",e].concat(cs)}).call(this)}),(function(){return (function(){this._applyWithArgs("token","break");this._apply("sc");return ["break"]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","continue");this._apply("sc");return ["continue"]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","throw");this._apply("spacesNoNl");e=this._apply("expr");this._apply("sc");return ["throw",e]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","try");t=this._apply("block");this._applyWithArgs("token","catch");this._applyWithArgs("token","(");e=this._applyWithArgs("token","name");this._applyWithArgs("token",")");c=this._apply("block");f=this._or((function(){return (function(){this._applyWithArgs("token","finally");return this._apply("block")}).call(this)}),(function(){return (function(){this._apply("empty");return ["get","undefined"]}).call(this)}));return ["try",t,e,c,f]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","return");e=this._or((function(){return this._apply("expr")}),(function(){return (function(){this._apply("empty");return ["get","undefined"]}).call(this)}));this._apply("sc");return ["return",e]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","with");this._applyWithArgs("token","(");x=this._apply("expr");this._applyWithArgs("token",")");s=this._apply("stmt");return ["with",x,s]}).call(this)}),(function(){return (function(){e=this._apply("expr");this._apply("sc");return e}).call(this)}),(function(){return (function(){this._applyWithArgs("token",";");return ["get","undefined"]}).call(this)}))},
"srcElem":function(){var $elf=this,_fromIdx=this.input.idx,n,f;return this._or((function(){return (function(){this._applyWithArgs("token","function");n=this._applyWithArgs("token","name");f=this._apply("funcRest");return ["var",n,f]}).call(this)}),(function(){return this._apply("stmt")}))},
"srcElems":function(){var $elf=this,_fromIdx=this.input.idx,ss;return (function(){ss=this._many((function(){return this._apply("srcElem")}));return ["begin"].concat(ss)}).call(this)},
"topLevel":function(){var $elf=this,_fromIdx=this.input.idx,r;return (function(){r=this._apply("srcElems");this._apply("spaces");this._apply("end");return r}).call(this)}});(BSJSParser["hexDigits"]="0123456789abcdef");(BSJSParser["keywords"]=({}));(keywords=["break","case","catch","continue","default","delete","do","else","finally","for","function","if","in","instanceof","new","return","switch","this","throw","try","typeof","var","void","while","with","ometa"]);for(var idx=(0);(idx < keywords["length"]);idx++){(BSJSParser["keywords"][keywords[idx]]=true)}(BSJSParser["_isKeyword"]=(function (k){return (this["keywords"].hasOwnProperty(k))}));BSSemActionParser=objectThatDelegatesTo(BSJSParser,{
"curlySemAction":function(){var $elf=this,_fromIdx=this.input.idx,r,s,ss,r,s;return this._or((function(){return (function(){this._applyWithArgs("token","{");r=this._apply("expr");this._apply("sc");this._applyWithArgs("token","}");this._apply("spaces");return r}).call(this)}),(function(){return (function(){this._applyWithArgs("token","{");ss=this._many((function(){return (function(){s=this._apply("srcElem");this._lookahead((function(){return this._apply("srcElem")}));return s}).call(this)}));s=this._or((function(){return (function(){r=this._apply("expr");this._apply("sc");return ["return",r]}).call(this)}),(function(){return this._apply("srcElem")}));ss.push(s);this._applyWithArgs("token","}");this._apply("spaces");return ["send","call",["func",[],["begin"].concat(ss)],["this"]]}).call(this)}))},
"semAction":function(){var $elf=this,_fromIdx=this.input.idx,r;return this._or((function(){return this._apply("curlySemAction")}),(function(){return (function(){r=this._apply("primExpr");this._apply("spaces");return r}).call(this)}))}});BSJSTranslator=objectThatDelegatesTo(OMeta,{
"trans":function(){var $elf=this,_fromIdx=this.input.idx,t,ans;return (function(){this._form((function(){return (function(){t=this._apply("anything");return ans=this._applyWithArgs("apply",t)}).call(this)}));return ans}).call(this)},
"curlyTrans":function(){var $elf=this,_fromIdx=this.input.idx,r,rs,r;return this._or((function(){return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly","begin");return r=this._apply("curlyTrans")}).call(this)}));return r}).call(this)}),(function(){return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly","begin");return rs=this._many((function(){return this._apply("trans")}))}).call(this)}));return (("{" + rs.join(";")) + "}")}).call(this)}),(function(){return (function(){r=this._apply("trans");return (("{" + r) + "}")}).call(this)}))},
"this":function(){var $elf=this,_fromIdx=this.input.idx;return "this"},
"break":function(){var $elf=this,_fromIdx=this.input.idx;return "break"},
"continue":function(){var $elf=this,_fromIdx=this.input.idx;return "continue"},
"number":function(){var $elf=this,_fromIdx=this.input.idx,n;return (function(){n=this._apply("anything");return (("(" + n) + ")")}).call(this)},
"string":function(){var $elf=this,_fromIdx=this.input.idx,s;return (function(){s=this._apply("anything");return s.toProgramString()}).call(this)},
"arr":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){xs=this._many((function(){return this._apply("trans")}));return (("[" + xs.join(",")) + "]")}).call(this)},
"unop":function(){var $elf=this,_fromIdx=this.input.idx,op,x;return (function(){op=this._apply("anything");x=this._apply("trans");return (((("(" + op) + " ") + x) + ")")}).call(this)},
"getp":function(){var $elf=this,_fromIdx=this.input.idx,fd,x;return (function(){fd=this._apply("trans");x=this._apply("trans");return (((x + "[") + fd) + "]")}).call(this)},
"get":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("anything");return x}).call(this)},
"set":function(){var $elf=this,_fromIdx=this.input.idx,lhs,rhs;return (function(){lhs=this._apply("trans");rhs=this._apply("trans");return (((("(" + lhs) + "=") + rhs) + ")")}).call(this)},
"mset":function(){var $elf=this,_fromIdx=this.input.idx,lhs,op,rhs;return (function(){lhs=this._apply("trans");op=this._apply("anything");rhs=this._apply("trans");return ((((("(" + lhs) + op) + "=") + rhs) + ")")}).call(this)},
"binop":function(){var $elf=this,_fromIdx=this.input.idx,op,x,y;return (function(){op=this._apply("anything");x=this._apply("trans");y=this._apply("trans");return (((((("(" + x) + " ") + op) + " ") + y) + ")")}).call(this)},
"preop":function(){var $elf=this,_fromIdx=this.input.idx,op,x;return (function(){op=this._apply("anything");x=this._apply("trans");return (op + x)}).call(this)},
"postop":function(){var $elf=this,_fromIdx=this.input.idx,op,x;return (function(){op=this._apply("anything");x=this._apply("trans");return (x + op)}).call(this)},
"return":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ("return " + x)}).call(this)},
"with":function(){var $elf=this,_fromIdx=this.input.idx,x,s;return (function(){x=this._apply("trans");s=this._apply("curlyTrans");return ((("with(" + x) + ")") + s)}).call(this)},
"if":function(){var $elf=this,_fromIdx=this.input.idx,cond,t,e;return (function(){cond=this._apply("trans");t=this._apply("curlyTrans");e=this._apply("curlyTrans");return ((((("if(" + cond) + ")") + t) + "else") + e)}).call(this)},
"condExpr":function(){var $elf=this,_fromIdx=this.input.idx,cond,t,e;return (function(){cond=this._apply("trans");t=this._apply("trans");e=this._apply("trans");return (((((("(" + cond) + "?") + t) + ":") + e) + ")")}).call(this)},
"while":function(){var $elf=this,_fromIdx=this.input.idx,cond,body;return (function(){cond=this._apply("trans");body=this._apply("curlyTrans");return ((("while(" + cond) + ")") + body)}).call(this)},
"doWhile":function(){var $elf=this,_fromIdx=this.input.idx,body,cond;return (function(){body=this._apply("curlyTrans");cond=this._apply("trans");return (((("do" + body) + "while(") + cond) + ")")}).call(this)},
"for":function(){var $elf=this,_fromIdx=this.input.idx,init,cond,upd,body;return (function(){init=this._apply("trans");cond=this._apply("trans");upd=this._apply("trans");body=this._apply("curlyTrans");return ((((((("for(" + init) + ";") + cond) + ";") + upd) + ")") + body)}).call(this)},
"forIn":function(){var $elf=this,_fromIdx=this.input.idx,x,arr,body;return (function(){x=this._apply("trans");arr=this._apply("trans");body=this._apply("curlyTrans");return ((((("for(" + x) + " in ") + arr) + ")") + body)}).call(this)},
"begin":function(){var $elf=this,_fromIdx=this.input.idx,x,x,xs;return this._or((function(){return (function(){x=this._apply("trans");this._apply("end");return x}).call(this)}),(function(){return (function(){xs=this._many((function(){return (function(){x=this._apply("trans");return this._or((function(){return (function(){this._or((function(){return this._pred((x[(x["length"] - (1))] == "}"))}),(function(){return this._apply("end")}));return x}).call(this)}),(function(){return (function(){this._apply("empty");return (x + ";")}).call(this)}))}).call(this)}));return (("{" + xs.join("")) + "}")}).call(this)}))},
"func":function(){var $elf=this,_fromIdx=this.input.idx,args,body;return (function(){args=this._apply("anything");body=this._apply("curlyTrans");return (((("(function (" + args.join(",")) + ")") + body) + ")")}).call(this)},
"call":function(){var $elf=this,_fromIdx=this.input.idx,fn,args;return (function(){fn=this._apply("trans");args=this._many((function(){return this._apply("trans")}));return (((fn + "(") + args.join(",")) + ")")}).call(this)},
"send":function(){var $elf=this,_fromIdx=this.input.idx,msg,recv,args;return (function(){msg=this._apply("anything");recv=this._apply("trans");args=this._many((function(){return this._apply("trans")}));return (((((recv + ".") + msg) + "(") + args.join(",")) + ")")}).call(this)},
"new":function(){var $elf=this,_fromIdx=this.input.idx,cls,args;return (function(){cls=this._apply("anything");args=this._many((function(){return this._apply("trans")}));return (((("new " + cls) + "(") + args.join(",")) + ")")}).call(this)},
"var":function(){var $elf=this,_fromIdx=this.input.idx,name,val;return (function(){name=this._apply("anything");val=this._apply("trans");return ((("var " + name) + "=") + val)}).call(this)},
"throw":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ("throw " + x)}).call(this)},
"try":function(){var $elf=this,_fromIdx=this.input.idx,x,name,c,f;return (function(){x=this._apply("curlyTrans");name=this._apply("anything");c=this._apply("curlyTrans");f=this._apply("curlyTrans");return ((((((("try " + x) + "catch(") + name) + ")") + c) + "finally") + f)}).call(this)},
"json":function(){var $elf=this,_fromIdx=this.input.idx,props;return (function(){props=this._many((function(){return this._apply("trans")}));return (("({" + props.join(",")) + "})")}).call(this)},
"binding":function(){var $elf=this,_fromIdx=this.input.idx,name,val;return (function(){name=this._apply("anything");val=this._apply("trans");return ((name.toProgramString() + ": ") + val)}).call(this)},
"switch":function(){var $elf=this,_fromIdx=this.input.idx,x,cases;return (function(){x=this._apply("trans");cases=this._many((function(){return this._apply("trans")}));return (((("switch(" + x) + "){") + cases.join(";")) + "}")}).call(this)},
"case":function(){var $elf=this,_fromIdx=this.input.idx,x,y;return (function(){x=this._apply("trans");y=this._apply("trans");return ((("case " + x) + ": ") + y)}).call(this)},
"default":function(){var $elf=this,_fromIdx=this.input.idx,y;return (function(){y=this._apply("trans");return ("default: " + y)}).call(this)}})}
+211
View File
@@ -0,0 +1,211 @@
ometa BSJSParser <: Parser {
fromTo :x :y = seq(x) (~seq(y) char)* seq(y),
space = ^space | fromTo('//', '\n') | fromTo('/*', '*/'),
nameFirst = letter | '$' | '_',
nameRest = nameFirst | digit,
iName = firstAndRest(#nameFirst, #nameRest):r -> r.join(''),
isKeyword :x = ?BSJSParser._isKeyword(x),
name = iName:n ~isKeyword(n) -> [#name, n=='self' ? '$elf' : n],
keyword = iName:k isKeyword(k) -> [k, k],
hexDigit = char:x {this.hexDigits.indexOf(x.toLowerCase())}:v ?(v >= 0) -> v,
hexLit = hexLit:n hexDigit:d -> (n * 16 + d)
| hexDigit,
number = ``0x'' hexLit:n -> [#number, n]
| digit+:ws ('.' digit+ | empty -> []):fs -> [#number, parseFloat(ws.join('') + '.' +
fs.join(''))],
escapeChar = '\\' char:c -> unescape('\\' + c),
str = seq('"""') (escapeChar | ~seq('"""') char)*:cs seq('"""') -> [#string, cs.join('')]
| '\'' (escapeChar | ~'\'' char)*:cs '\'' -> [#string, cs.join('')]
| '"' (escapeChar | ~'"' char)*:cs '"' -> [#string, cs.join('')]
| ('#' | '`') iName:n -> [#string, n],
special = ( '(' | ')' | '{' | '}' | '[' | ']' | ','
| ';' | '?' | ':' | ``!=='' | ``!='' | ``==='' | ``==''
| ``='' | ``>='' | '>' | ``<='' | '<' | ``++'' | ``+=''
| '+' | ``--'' | ``-='' | '-' | ``*='' | '*' | ``/=''
| '/' | ``%='' | '%' | ``&&='' | ``&&'' | ``||='' | ``||''
| '.' | '!' ):s -> [s, s],
tok = spaces (name | keyword | number | str | special),
toks = token*:ts spaces end -> ts,
token :tt = tok:t ?(t[0] == tt) -> t[1],
spacesNoNl = (~'\n' space)*,
expr = orExpr:e ( "?" expr:t ":" expr:f -> [#condExpr, e, t, f]
| "=" expr:rhs -> [#set, e, rhs]
| "+=" expr:rhs -> [#mset, e, "+", rhs]
| "-=" expr:rhs -> [#mset, e, "-", rhs]
| "*=" expr:rhs -> [#mset, e, "*", rhs]
| "/=" expr:rhs -> [#mset, e, "/", rhs]
| "%=" expr:rhs -> [#mset, e, "%", rhs]
| "&&=" expr:rhs -> [#mset, e, "&&", rhs]
| "||=" expr:rhs -> [#mset, e, "||", rhs]
| empty -> e
),
orExpr = orExpr:x "||" andExpr:y -> [#binop, "||", x, y]
| andExpr,
andExpr = andExpr:x "&&" eqExpr:y -> [#binop, "&&", x, y]
| eqExpr,
eqExpr = eqExpr:x ( "==" relExpr:y -> [#binop, "==", x, y]
| "!=" relExpr:y -> [#binop, "!=", x, y]
| "===" relExpr:y -> [#binop, "===", x, y]
| "!==" relExpr:y -> [#binop, "!==", x, y]
)
| relExpr,
relExpr = relExpr:x ( ">" addExpr:y -> [#binop, ">", x, y]
| ">=" addExpr:y -> [#binop, ">=", x, y]
| "<" addExpr:y -> [#binop, "<", x, y]
| "<=" addExpr:y -> [#binop, "<=", x, y]
| "instanceof" addExpr:y -> [#binop, "instanceof", x, y]
)
| addExpr,
addExpr = addExpr:x "+" mulExpr:y -> [#binop, "+", x, y]
| addExpr:x "-" mulExpr:y -> [#binop, "-", x, y]
| mulExpr,
mulExpr = mulExpr:x "*" unary:y -> [#binop, "*", x, y]
| mulExpr:x "/" unary:y -> [#binop, "/", x, y]
| mulExpr:x "%" unary:y -> [#binop, "%", x, y]
| unary,
unary = "-" postfix:p -> [#unop, "-", p]
| "+" postfix:p -> [#unop, "+", p]
| "++" postfix:p -> [#preop, "++", p]
| "--" postfix:p -> [#preop, "--", p]
| "!" unary:p -> [#unop, "!", p]
| "void" unary:p -> [#unop, "void", p]
| "delete" unary:p -> [#unop, "delete", p]
| "typeof" unary:p -> [#unop, "typeof", p]
| postfix,
postfix = primExpr:p ( spacesNoNl "++" -> [#postop, "++", p]
| spacesNoNl "--" -> [#postop, "--", p]
| empty -> p
),
primExpr = primExpr:p ( "[" expr:i "]" -> [#getp, i, p]
| "." "name":m "(" listOf(#expr, ','):as ")" -> [#send, m, p].concat(as)
| "." "name":f -> [#getp, [#string, f], p]
| "(" listOf(#expr, ','):as ")" -> [#call, p].concat(as)
)
| primExprHd,
primExprHd = "(" expr:e ")" -> e
| "this" -> [#this]
| "name":n -> [#get, n]
| "number":n -> [#number, n]
| "string":s -> [#string, s]
| "function" funcRest
| "new" "name":n "(" listOf(#expr, ','):as ")" -> [#new, n].concat(as)
| "[" listOf(#expr, ','):es "]" -> [#arr].concat(es)
| json,
json = "{" listOf(#jsonBinding, ','):bs "}" -> [#json].concat(bs),
jsonBinding = jsonPropName:n ":" expr:v -> [#binding, n, v],
jsonPropName = "name" | "number" | "string",
formal = spaces "name",
funcRest = "(" listOf(#formal, ','):fs ")" "{" srcElems:body "}" -> [#func, fs, body],
sc = spacesNoNl ('\n' | &'}' | end)
| ";",
binding = "name":n ( "=" expr
| empty -> [#get, 'undefined'] ):v -> [#var, n, v],
block = "{" srcElems:ss "}" -> ss,
stmt = block
| "var" listOf(#binding, ','):bs sc -> [#begin].concat(bs)
| "if" "(" expr:c ")" stmt:t ( "else" stmt
| empty -> [#get, 'undefined'] ):f -> [#if, c, t, f]
| "while" "(" expr:c ")" stmt:s -> [#while, c, s]
| "do" stmt:s "while" "(" expr:c ")" sc -> [#doWhile, s, c]
| "for" "(" ( "var" binding
| expr
| empty -> [#get, 'undefined'] ):i
";" ( expr
| empty -> [#get, 'true'] ):c
";" ( expr
| empty -> [#get, 'undefined'] ):u
")" stmt:s -> [#for, i, c, u, s]
| "for" "(" ( "var" "name":n -> [#var, n, [#get, 'undefined']]
| expr ):v
"in" expr:e
")" stmt:s -> [#forIn, v, e, s]
| "switch" "(" expr:e ")" "{"
( "case" expr:c ":" srcElems:cs -> [#case, c, cs]
| "default" ":" srcElems:cs -> [#default, cs] )*:cs
"}" -> [#switch, e].concat(cs)
| "break" sc -> [#break]
| "continue" sc -> [#continue]
| "throw" spacesNoNl expr:e sc -> [#throw, e]
| "try" block:t "catch" "(" "name":e ")" block:c
( "finally" block
| empty -> [#get, 'undefined'] ):f -> [#try, t, e, c, f]
| "return" ( expr
| empty -> [#get, 'undefined'] ):e sc -> [#return, e]
| "with" "(" expr:x ")" stmt:s -> [#with, x, s]
| expr:e sc -> e
| ";" -> [#get, "undefined"],
srcElem = "function" "name":n funcRest:f -> [#var, n, f]
| stmt,
srcElems = srcElem*:ss -> [#begin].concat(ss),
topLevel = srcElems:r spaces end -> r
}
BSJSParser.hexDigits = "0123456789abcdef"
BSJSParser.keywords = { }
keywords = ["break", "case", "catch", "continue", "default", "delete", "do", "else", "finally", "for", "function", "if", "in",
"instanceof", "new", "return", "switch", "this", "throw", "try", "typeof", "var", "void", "while", "with", "ometa"]
for (var idx = 0; idx < keywords.length; idx++)
BSJSParser.keywords[keywords[idx]] = true
BSJSParser._isKeyword = function(k) { return this.keywords.hasOwnProperty(k) }
ometa BSSemActionParser <: BSJSParser {
curlySemAction = "{" expr:r sc "}" spaces -> r
| "{" (srcElem:s &srcElem -> s)*:ss
( expr:r sc -> [#return, r] | srcElem):s {ss.push(s)}
"}" spaces -> [#send, #call,
[#func, [], [#begin].concat(ss)],
[#this]],
semAction = curlySemAction
| primExpr:r spaces -> r
}
ometa BSJSTranslator {
trans = [:t apply(t):ans] -> ans,
curlyTrans = [#begin curlyTrans:r] -> r
| [#begin trans*:rs] -> ('{' + rs.join(';') + '}')
| trans:r -> ('{' + r + '}'),
this -> 'this',
break -> 'break',
continue -> 'continue',
number :n -> ('(' + n + ')'),
string :s -> s.toProgramString(),
arr trans*:xs -> ('[' + xs.join(',') + ']'),
unop :op trans:x -> ('(' + op + ' ' + x + ')'),
getp trans:fd trans:x -> (x + '[' + fd + ']'),
get :x -> x,
set trans:lhs trans:rhs -> ('(' + lhs + '=' + rhs + ')'),
mset trans:lhs :op trans:rhs -> ('(' + lhs + op + '=' + rhs + ')'),
binop :op trans:x trans:y -> ('(' + x + ' ' + op + ' ' + y + ')'),
preop :op trans:x -> (op + x),
postop :op trans:x -> (x + op),
return trans:x -> ('return ' + x),
with trans:x curlyTrans:s -> ('with(' + x + ')' + s),
if trans:cond curlyTrans:t curlyTrans:e -> ('if(' + cond + ')' + t + 'else' + e),
condExpr trans:cond trans:t trans:e -> ('(' + cond + '?' + t + ':' + e + ')'),
while trans:cond curlyTrans:body -> ('while(' + cond + ')' + body),
doWhile curlyTrans:body trans:cond -> ('do' + body + 'while(' + cond + ')'),
for trans:init trans:cond trans:upd
curlyTrans:body -> ('for(' + init + ';' + cond + ';' + upd + ')' + body),
forIn trans:x trans:arr curlyTrans:body -> ('for(' + x + ' in ' + arr + ')' + body),
begin trans:x end -> x,
begin (trans:x
( (?(x[x.length - 1] == '}') | end) -> x
| empty -> (x + ';')
)
)*:xs -> ('{' + xs.join('') + '}'),
func :args curlyTrans:body -> ('(function (' + args.join(',') + ')' + body + ')'),
call trans:fn trans*:args -> (fn + '(' + args.join(',') + ')'),
send :msg trans:recv trans*:args -> (recv + '.' + msg + '(' + args.join(',') + ')'),
new :cls trans*:args -> ('new ' + cls + '(' + args.join(',') + ')'),
var :name trans:val -> ('var ' + name + '=' + val),
throw trans:x -> ('throw ' + x),
try curlyTrans:x :name curlyTrans:c curlyTrans:f -> ('try ' + x + 'catch(' + name + ')' + c + 'finally' + f),
json trans*:props -> ('({' + props.join(',') + '})'),
binding :name trans:val -> (name.toProgramString() + ': ' + val),
switch trans:x trans*:cases -> ('switch(' + x + '){' + cases.join(';') + '}'),
case trans:x trans:y -> ('case ' + x + ': '+ y),
default trans:y -> ('default: ' + y)
}
+62
View File
@@ -0,0 +1,62 @@
var StringBuffer = StringBuffer || require('./lib').StringBuffer;
{BSOMetaParser=objectThatDelegatesTo(Parser,{
"fromTo":function(){var $elf=this,_fromIdx=this.input.idx,x,y;return (function(){x=this._apply("anything");y=this._apply("anything");this._applyWithArgs("seq",x);this._many((function(){return (function(){this._not((function(){return this._applyWithArgs("seq",y)}));return this._apply("char")}).call(this)}));return this._applyWithArgs("seq",y)}).call(this)},
"space":function(){var $elf=this,_fromIdx=this.input.idx;return this._or((function(){return Parser._superApplyWithArgs(this,'space')}),(function(){return this._applyWithArgs("fromTo","//","\n")}),(function(){return this._applyWithArgs("fromTo","/*","*/")}))},
"nameFirst":function(){var $elf=this,_fromIdx=this.input.idx;return this._or((function(){return (function(){switch(this._apply('anything')){case "_":return "_";case "$":return "$";default: throw fail}}).call(this)}),(function(){return this._apply("letter")}))},
"nameRest":function(){var $elf=this,_fromIdx=this.input.idx;return this._or((function(){return this._apply("nameFirst")}),(function(){return this._apply("digit")}))},
"tsName":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){xs=this._applyWithArgs("firstAndRest","nameFirst","nameRest");return xs.join("")}).call(this)},
"name":function(){var $elf=this,_fromIdx=this.input.idx;return (function(){this._apply("spaces");return this._apply("tsName")}).call(this)},
"eChar":function(){var $elf=this,_fromIdx=this.input.idx,c;return this._or((function(){return (function(){switch(this._apply('anything')){case "\\":return (function(){c=this._apply("char");return unescape(("\\" + c))}).call(this);default: throw fail}}).call(this)}),(function(){return this._apply("char")}))},
"tsString":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){this._applyWithArgs("exactly","\'");xs=this._many((function(){return (function(){this._not((function(){return this._applyWithArgs("exactly","\'")}));return this._apply("eChar")}).call(this)}));this._applyWithArgs("exactly","\'");return xs.join("")}).call(this)},
"characters":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){this._applyWithArgs("exactly","`");this._applyWithArgs("exactly","`");xs=this._many((function(){return (function(){this._not((function(){return (function(){this._applyWithArgs("exactly","\'");return this._applyWithArgs("exactly","\'")}).call(this)}));return this._apply("eChar")}).call(this)}));this._applyWithArgs("exactly","\'");this._applyWithArgs("exactly","\'");return ["App","seq",xs.join("").toProgramString()]}).call(this)},
"sCharacters":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){this._applyWithArgs("exactly","\"");xs=this._many((function(){return (function(){this._not((function(){return this._applyWithArgs("exactly","\"")}));return this._apply("eChar")}).call(this)}));this._applyWithArgs("exactly","\"");return ["App","token",xs.join("").toProgramString()]}).call(this)},
"string":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){xs=this._or((function(){return (function(){(function(){switch(this._apply('anything')){case "#":return "#";case "`":return "`";default: throw fail}}).call(this);return this._apply("tsName")}).call(this)}),(function(){return this._apply("tsString")}));return ["App","exactly",xs.toProgramString()]}).call(this)},
"number":function(){var $elf=this,_fromIdx=this.input.idx,sign,ds;return (function(){sign=this._or((function(){return (function(){switch(this._apply('anything')){case "-":return "-";default: throw fail}}).call(this)}),(function(){return (function(){this._apply("empty");return ""}).call(this)}));ds=this._many1((function(){return this._apply("digit")}));return ["App","exactly",(sign + ds.join(""))]}).call(this)},
"keyword":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){xs=this._apply("anything");this._applyWithArgs("token",xs);this._not((function(){return this._apply("letterOrDigit")}));return xs}).call(this)},
"args":function(){var $elf=this,_fromIdx=this.input.idx,xs;return this._or((function(){return (function(){switch(this._apply('anything')){case "(":return (function(){xs=this._applyWithArgs("listOf","hostExpr",",");this._applyWithArgs("token",")");return xs}).call(this);default: throw fail}}).call(this)}),(function(){return (function(){this._apply("empty");return []}).call(this)}))},
"application":function(){var $elf=this,_fromIdx=this.input.idx,rule,as,grm,rule,as,rule,as;return this._or((function(){return (function(){this._applyWithArgs("token","^");rule=this._apply("name");as=this._apply("args");return ["App","super",(("\'" + rule) + "\'")].concat(as)}).call(this)}),(function(){return (function(){grm=this._apply("name");this._applyWithArgs("token",".");rule=this._apply("name");as=this._apply("args");return ["App","foreign",grm,(("\'" + rule) + "\'")].concat(as)}).call(this)}),(function(){return (function(){rule=this._apply("name");as=this._apply("args");return ["App",rule].concat(as)}).call(this)}))},
"hostExpr":function(){var $elf=this,_fromIdx=this.input.idx,r;return (function(){r=this._applyWithArgs("foreign",BSSemActionParser,'expr');return this._applyWithArgs("foreign",BSJSTranslator,'trans',r)}).call(this)},
"curlyHostExpr":function(){var $elf=this,_fromIdx=this.input.idx,r;return (function(){r=this._applyWithArgs("foreign",BSSemActionParser,'curlySemAction');return this._applyWithArgs("foreign",BSJSTranslator,'trans',r)}).call(this)},
"primHostExpr":function(){var $elf=this,_fromIdx=this.input.idx,r;return (function(){r=this._applyWithArgs("foreign",BSSemActionParser,'semAction');return this._applyWithArgs("foreign",BSJSTranslator,'trans',r)}).call(this)},
"atomicHostExpr":function(){var $elf=this,_fromIdx=this.input.idx;return this._or((function(){return this._apply("curlyHostExpr")}),(function(){return this._apply("primHostExpr")}))},
"semAction":function(){var $elf=this,_fromIdx=this.input.idx,x,x;return this._or((function(){return (function(){x=this._apply("curlyHostExpr");return ["Act",x]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","!");x=this._apply("atomicHostExpr");return ["Act",x]}).call(this)}))},
"arrSemAction":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){this._applyWithArgs("token","->");x=this._apply("atomicHostExpr");return ["Act",x]}).call(this)},
"semPred":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){this._applyWithArgs("token","?");x=this._apply("atomicHostExpr");return ["Pred",x]}).call(this)},
"expr":function(){var $elf=this,_fromIdx=this.input.idx,x,xs,x,xs;return this._or((function(){return (function(){x=this._applyWithArgs("expr5",true);xs=this._many1((function(){return (function(){this._applyWithArgs("token","|");return this._applyWithArgs("expr5",true)}).call(this)}));return ["Or",x].concat(xs)}).call(this)}),(function(){return (function(){x=this._applyWithArgs("expr5",true);xs=this._many1((function(){return (function(){this._applyWithArgs("token","||");return this._applyWithArgs("expr5",true)}).call(this)}));return ["XOr",x].concat(xs)}).call(this)}),(function(){return this._applyWithArgs("expr5",false)}))},
"expr5":function(){var $elf=this,_fromIdx=this.input.idx,ne,x,xs;return (function(){ne=this._apply("anything");return this._or((function(){return (function(){x=this._apply("interleavePart");xs=this._many1((function(){return (function(){this._applyWithArgs("token","&&");return this._apply("interleavePart")}).call(this)}));return ["Interleave",x].concat(xs)}).call(this)}),(function(){return this._applyWithArgs("expr4",ne)}))}).call(this)},
"interleavePart":function(){var $elf=this,_fromIdx=this.input.idx,part,part;return this._or((function(){return (function(){this._applyWithArgs("token","(");part=this._applyWithArgs("expr4",true);this._applyWithArgs("token",")");return ["1",part]}).call(this)}),(function(){return (function(){part=this._applyWithArgs("expr4",true);return this._applyWithArgs("modedIPart",part)}).call(this)}))},
"modedIPart":function(){var $elf=this,_fromIdx=this.input.idx,part,part,part,part;return this._or((function(){return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly","And");return this._form((function(){return (function(){this._applyWithArgs("exactly","Many");return part=this._apply("anything")}).call(this)}))}).call(this)}));return ["*",part]}).call(this)}),(function(){return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly","And");return this._form((function(){return (function(){this._applyWithArgs("exactly","Many1");return part=this._apply("anything")}).call(this)}))}).call(this)}));return ["+",part]}).call(this)}),(function(){return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly","And");return this._form((function(){return (function(){this._applyWithArgs("exactly","Opt");return part=this._apply("anything")}).call(this)}))}).call(this)}));return ["?",part]}).call(this)}),(function(){return (function(){part=this._apply("anything");return ["1",part]}).call(this)}))},
"expr4":function(){var $elf=this,_fromIdx=this.input.idx,ne,xs,act,xs,xs;return (function(){ne=this._apply("anything");return this._or((function(){return (function(){xs=this._many((function(){return this._apply("expr3")}));act=this._apply("arrSemAction");return ["And"].concat(xs).concat([act])}).call(this)}),(function(){return (function(){this._pred(ne);xs=this._many1((function(){return this._apply("expr3")}));return ["And"].concat(xs)}).call(this)}),(function(){return (function(){this._pred((ne == false));xs=this._many((function(){return this._apply("expr3")}));return ["And"].concat(xs)}).call(this)}))}).call(this)},
"optIter":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("anything");return this._or((function(){return (function(){switch(this._apply('anything')){case "*":return ["Many",x];case "+":return ["Many1",x];case "?":return ["Opt",x];default: throw fail}}).call(this)}),(function(){return (function(){this._apply("empty");return x}).call(this)}))}).call(this)},
"optBind":function(){var $elf=this,_fromIdx=this.input.idx,x,n;return (function(){x=this._apply("anything");return this._or((function(){return (function(){switch(this._apply('anything')){case ":":return (function(){n=this._apply("name");return (function (){this["locals"].push(n);return ["Set",n,x]}).call(this)}).call(this);default: throw fail}}).call(this)}),(function(){return (function(){this._apply("empty");return x}).call(this)}))}).call(this)},
"expr3":function(){var $elf=this,_fromIdx=this.input.idx,n,x,e;return this._or((function(){return (function(){this._applyWithArgs("token",":");n=this._apply("name");return (function (){this["locals"].push(n);return ["Set",n,["App","anything"]]}).call(this)}).call(this)}),(function(){return (function(){e=this._or((function(){return (function(){x=this._apply("expr2");return this._applyWithArgs("optIter",x)}).call(this)}),(function(){return this._apply("semAction")}));return this._applyWithArgs("optBind",e)}).call(this)}),(function(){return this._apply("semPred")}))},
"expr2":function(){var $elf=this,_fromIdx=this.input.idx,x,x;return this._or((function(){return (function(){this._applyWithArgs("token","~");x=this._apply("expr2");return ["Not",x]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","&");x=this._apply("expr1");return ["Lookahead",x]}).call(this)}),(function(){return this._apply("expr1")}))},
"expr1":function(){var $elf=this,_fromIdx=this.input.idx,x,x,x,x,x;return this._or((function(){return this._apply("application")}),(function(){return (function(){x=this._or((function(){return this._applyWithArgs("keyword","undefined")}),(function(){return this._applyWithArgs("keyword","nil")}),(function(){return this._applyWithArgs("keyword","true")}),(function(){return this._applyWithArgs("keyword","false")}));return ["App","exactly",x]}).call(this)}),(function(){return (function(){this._apply("spaces");return this._or((function(){return this._apply("characters")}),(function(){return this._apply("sCharacters")}),(function(){return this._apply("string")}),(function(){return this._apply("number")}))}).call(this)}),(function(){return (function(){this._applyWithArgs("token","[");x=this._apply("expr");this._applyWithArgs("token","]");return ["Form",x]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","<");x=this._apply("expr");this._applyWithArgs("token",">");return ["ConsBy",x]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","@<");x=this._apply("expr");this._applyWithArgs("token",">");return ["IdxConsBy",x]}).call(this)}),(function(){return (function(){this._applyWithArgs("token","(");x=this._apply("expr");this._applyWithArgs("token",")");return x}).call(this)}))},
"ruleName":function(){var $elf=this,_fromIdx=this.input.idx;return this._or((function(){return this._apply("name")}),(function(){return (function(){this._apply("spaces");return this._apply("tsString")}).call(this)}))},
"rule":function(){var $elf=this,_fromIdx=this.input.idx,n,x,xs;return (function(){this._lookahead((function(){return n=this._apply("ruleName")}));(this["locals"]=["$elf=this","_fromIdx=this.input.idx"]);x=this._applyWithArgs("rulePart",n);xs=this._many((function(){return (function(){this._applyWithArgs("token",",");return this._applyWithArgs("rulePart",n)}).call(this)}));return ["Rule",n,this["locals"],["Or",x].concat(xs)]}).call(this)},
"rulePart":function(){var $elf=this,_fromIdx=this.input.idx,rn,n,b1,b2;return (function(){rn=this._apply("anything");n=this._apply("ruleName");this._pred((n == rn));b1=this._apply("expr4");return this._or((function(){return (function(){this._applyWithArgs("token","=");b2=this._apply("expr");return ["And",b1,b2]}).call(this)}),(function(){return (function(){this._apply("empty");return b1}).call(this)}))}).call(this)},
"grammar":function(){var $elf=this,_fromIdx=this.input.idx,n,sn,rs;return (function(){this._applyWithArgs("keyword","ometa");n=this._apply("name");sn=this._or((function(){return (function(){this._applyWithArgs("token","<:");return this._apply("name")}).call(this)}),(function(){return (function(){this._apply("empty");return "OMeta"}).call(this)}));this._applyWithArgs("token","{");rs=this._applyWithArgs("listOf","rule",",");this._applyWithArgs("token","}");return this._applyWithArgs("foreign",BSOMetaOptimizer,'optimizeGrammar',["Grammar",n,sn].concat(rs))}).call(this)}});BSOMetaTranslator=objectThatDelegatesTo(OMeta,{
"App":function(){var $elf=this,_fromIdx=this.input.idx,args,rule,args,rule;return this._or((function(){return (function(){switch(this._apply('anything')){case "super":return (function(){args=this._many1((function(){return this._apply("anything")}));return [this["sName"],"._superApplyWithArgs(this,",args.join(","),")"].join("")}).call(this);default: throw fail}}).call(this)}),(function(){return (function(){rule=this._apply("anything");args=this._many1((function(){return this._apply("anything")}));return ["this._applyWithArgs(\"",rule,"\",",args.join(","),")"].join("")}).call(this)}),(function(){return (function(){rule=this._apply("anything");return ["this._apply(\"",rule,"\")"].join("")}).call(this)}))},
"Act":function(){var $elf=this,_fromIdx=this.input.idx,expr;return (function(){expr=this._apply("anything");return expr}).call(this)},
"Pred":function(){var $elf=this,_fromIdx=this.input.idx,expr;return (function(){expr=this._apply("anything");return ["this._pred(",expr,")"].join("")}).call(this)},
"Or":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){xs=this._many((function(){return this._apply("transFn")}));return ["this._or(",xs.join(","),")"].join("")}).call(this)},
"XOr":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){xs=this._many((function(){return this._apply("transFn")}));xs.unshift(((this["name"] + ".") + this["rName"]).toProgramString());return ["this._xor(",xs.join(","),")"].join("")}).call(this)},
"And":function(){var $elf=this,_fromIdx=this.input.idx,xs,y;return this._or((function(){return (function(){xs=this._many((function(){return this._applyWithArgs("notLast","trans")}));y=this._apply("trans");xs.push(("return " + y));return ["(function(){",xs.join(";"),"}).call(this)"].join("")}).call(this)}),(function(){return "undefined"}))},
"Opt":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("transFn");return ["this._opt(",x,")"].join("")}).call(this)},
"Many":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("transFn");return ["this._many(",x,")"].join("")}).call(this)},
"Many1":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("transFn");return ["this._many1(",x,")"].join("")}).call(this)},
"Set":function(){var $elf=this,_fromIdx=this.input.idx,n,v;return (function(){n=this._apply("anything");v=this._apply("trans");return [n,"=",v].join("")}).call(this)},
"Not":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("transFn");return ["this._not(",x,")"].join("")}).call(this)},
"Lookahead":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("transFn");return ["this._lookahead(",x,")"].join("")}).call(this)},
"Form":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("transFn");return ["this._form(",x,")"].join("")}).call(this)},
"ConsBy":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("transFn");return ["this._consumedBy(",x,")"].join("")}).call(this)},
"IdxConsBy":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("transFn");return ["this._idxConsumedBy(",x,")"].join("")}).call(this)},
"JumpTable":function(){var $elf=this,_fromIdx=this.input.idx,cases;return (function(){cases=this._many((function(){return this._apply("jtCase")}));return this.jumpTableCode(cases)}).call(this)},
"Interleave":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){xs=this._many((function(){return this._apply("intPart")}));return ["this._interleave(",xs.join(","),")"].join("")}).call(this)},
"Rule":function(){var $elf=this,_fromIdx=this.input.idx,name,ls,body;return (function(){name=this._apply("anything");(this["rName"]=name);ls=this._apply("locals");body=this._apply("trans");return ["\n\"",name,"\":function(){",ls,"return ",body,"}"].join("")}).call(this)},
"Grammar":function(){var $elf=this,_fromIdx=this.input.idx,name,sName,rules;return (function(){name=this._apply("anything");sName=this._apply("anything");(this["name"]=name);(this["sName"]=sName);rules=this._many((function(){return this._apply("trans")}));return [name,"=objectThatDelegatesTo(",sName,",{",rules.join(","),"})"].join("")}).call(this)},
"intPart":function(){var $elf=this,_fromIdx=this.input.idx,mode,part;return (function(){this._form((function(){return (function(){mode=this._apply("anything");return part=this._apply("transFn")}).call(this)}));return ((mode.toProgramString() + ",") + part)}).call(this)},
"jtCase":function(){var $elf=this,_fromIdx=this.input.idx,x,e;return (function(){this._form((function(){return (function(){x=this._apply("anything");return e=this._apply("trans")}).call(this)}));return [x.toProgramString(),e]}).call(this)},
"locals":function(){var $elf=this,_fromIdx=this.input.idx,vs;return this._or((function(){return (function(){this._form((function(){return vs=this._many1((function(){return this._apply("string")}))}));return ["var ",vs.join(","),";"].join("")}).call(this)}),(function(){return (function(){this._form((function(){return undefined}));return ""}).call(this)}))},
"trans":function(){var $elf=this,_fromIdx=this.input.idx,t,ans;return (function(){this._form((function(){return (function(){t=this._apply("anything");return ans=this._applyWithArgs("apply",t)}).call(this)}));return ans}).call(this)},
"transFn":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ["(function(){return ",x,"})"].join("")}).call(this)}});(BSOMetaTranslator["jumpTableCode"]=(function (cases){var buf=new StringBuffer();buf.nextPutAll("(function(){switch(this._apply(\'anything\')){");for(var i=(0);(i < cases["length"]);(i+=(1))){buf.nextPutAll((((("case " + cases[i][(0)]) + ":return ") + cases[i][(1)]) + ";"))};buf.nextPutAll("default: throw fail}}).call(this)");return buf.contents()}))}
+124
View File
@@ -0,0 +1,124 @@
ometa BSOMetaParser <: Parser {
fromTo :x :y = seq(x) (~seq(y) char)* seq(y),
space = ^space | fromTo('//', '\n') | fromTo('/*', '*/'),
nameFirst = '_' | '$' | letter,
nameRest = nameFirst | digit,
tsName = firstAndRest(#nameFirst, #nameRest):xs -> xs.join(''),
name = spaces tsName,
eChar = '\\' char:c -> unescape('\\' +c)
| char,
tsString = '\'' (~'\'' eChar)*:xs '\'' -> xs.join(''),
characters = '`' '`' (~('\'' '\'') eChar)*:xs '\'' '\'' -> [#App, #seq, xs.join('').toProgramString()],
sCharacters = '"' (~'"' eChar)*:xs '"' -> [#App, #token, xs.join('').toProgramString()],
string = (('#' | '`') tsName | tsString):xs -> [#App, #exactly, xs.toProgramString()],
number = ('-' | empty -> ''):sign digit+:ds -> [#App, #exactly, sign + ds.join('')],
keyword :xs = token(xs) ~letterOrDigit -> xs,
args = '(' listOf(#hostExpr, ','):xs ")" -> xs
| empty -> [],
application = "^" name:rule args:as -> [#App, "super", "'" + rule + "'"].concat(as)
| name:grm "." name:rule args:as -> [#App, "foreign", grm, "'" + rule + "'"].concat(as)
| name:rule args:as -> [#App, rule].concat(as),
hostExpr = BSSemActionParser.expr:r BSJSTranslator.trans(r),
curlyHostExpr = BSSemActionParser.curlySemAction:r BSJSTranslator.trans(r),
primHostExpr = BSSemActionParser.semAction:r BSJSTranslator.trans(r),
atomicHostExpr = curlyHostExpr | primHostExpr,
semAction = curlyHostExpr:x -> [#Act, x]
| "!" atomicHostExpr:x -> [#Act, x],
arrSemAction = "->" atomicHostExpr:x -> [#Act, x],
semPred = "?" atomicHostExpr:x -> [#Pred, x],
expr = expr5(true):x ("|" expr5(true))+:xs -> [#Or, x].concat(xs)
| expr5(true):x ("||" expr5(true))+:xs -> [#XOr, x].concat(xs)
| expr5(false),
expr5 :ne = interleavePart:x ("&&" interleavePart)+:xs -> [#Interleave, x].concat(xs)
| expr4(ne),
interleavePart = "(" expr4(true):part ")" -> ["1", part]
| expr4(true):part modedIPart(part),
modedIPart = [#And [#Many :part]] -> ["*", part]
| [#And [#Many1 :part]] -> ["+", part]
| [#And [#Opt :part]] -> ["?", part]
| :part -> ["1", part],
expr4 :ne = expr3*:xs arrSemAction:act -> [#And].concat(xs).concat([act])
| ?ne expr3+:xs -> [#And].concat(xs)
| ?(ne == false) expr3*:xs -> [#And].concat(xs),
optIter :x = '*' -> [#Many, x]
| '+' -> [#Many1, x]
| '?' -> [#Opt, x]
| empty -> x,
optBind :x = ':' name:n -> { this.locals.push(n); [#Set, n, x] }
| empty -> x,
expr3 = ":" name:n -> { this.locals.push(n); [#Set, n, [#App, #anything]] }
| (expr2:x optIter(x) | semAction):e optBind(e)
| semPred,
expr2 = "~" expr2:x -> [#Not, x]
| "&" expr1:x -> [#Lookahead, x]
| expr1,
expr1 = application
| ( keyword('undefined') | keyword('nil')
| keyword('true') | keyword('false') ):x -> [#App, #exactly, x]
| spaces (characters | sCharacters | string | number)
| "[" expr:x "]" -> [#Form, x]
| "<" expr:x ">" -> [#ConsBy, x]
| "@<" expr:x ">" -> [#IdxConsBy, x]
| "(" expr:x ")" -> x,
ruleName = name
| spaces tsString,
rule = &(ruleName:n) !(this.locals = ['$elf=this', '_fromIdx=this.input.idx'])
rulePart(n):x ("," rulePart(n))*:xs -> [#Rule, n, this.locals, [#Or, x].concat(xs)],
rulePart :rn = ruleName:n ?(n == rn) expr4:b1 ( "=" expr:b2 -> [#And, b1, b2]
| empty -> b1
),
grammar = keyword('ometa') name:n
( "<:" name | empty -> 'OMeta' ):sn
"{" listOf(#rule, ','):rs "}" BSOMetaOptimizer.optimizeGrammar(
[#Grammar, n, sn].concat(rs)
)
}
// By dispatching on the head of a list, the following idiom allows translators to avoid doing a linear search.
// (Note that the "=" in a rule definition is optional, so you can give your rules an "ML feel".)
ometa BSOMetaTranslator {
App 'super' anything+:args -> [this.sName, '._superApplyWithArgs(this,', args.join(','), ')'] .join(''),
App :rule anything+:args -> ['this._applyWithArgs("', rule, '",', args.join(','), ')'] .join(''),
App :rule -> ['this._apply("', rule, '")'] .join(''),
Act :expr -> expr,
Pred :expr -> ['this._pred(', expr, ')'] .join(''),
Or transFn*:xs -> ['this._or(', xs.join(','), ')'] .join(''),
XOr transFn*:xs {xs.unshift((this.name + "." + this.rName).toProgramString())}
-> ['this._xor(', xs.join(','), ')'] .join(''),
And notLast(#trans)*:xs trans:y
{xs.push('return ' + y)} -> ['(function(){', xs.join(';'), '}).call(this)'] .join(''),
And -> 'undefined',
Opt transFn:x -> ['this._opt(', x, ')'] .join(''),
Many transFn:x -> ['this._many(', x, ')'] .join(''),
Many1 transFn:x -> ['this._many1(', x, ')'] .join(''),
Set :n trans:v -> [n, '=', v] .join(''),
Not transFn:x -> ['this._not(', x, ')'] .join(''),
Lookahead transFn:x -> ['this._lookahead(', x, ')'] .join(''),
Form transFn:x -> ['this._form(', x, ')'] .join(''),
ConsBy transFn:x -> ['this._consumedBy(', x, ')'] .join(''),
IdxConsBy transFn:x -> ['this._idxConsumedBy(', x, ')'] .join(''),
JumpTable jtCase*:cases -> this.jumpTableCode(cases),
Interleave intPart*:xs -> ['this._interleave(', xs.join(','), ')'] .join(''),
Rule :name {this.rName = name}
locals:ls trans:body -> ['\n"', name, '":function(){', ls, 'return ', body, '}'] .join(''),
Grammar :name :sName
{this.name = name}
{this.sName = sName}
trans*:rules -> [name, '=objectThatDelegatesTo(', sName, ',{', rules.join(','), '})'].join(''),
intPart = [:mode transFn:part] -> (mode.toProgramString() + "," + part),
jtCase = [:x trans:e] -> [x.toProgramString(), e],
locals = [string+:vs] -> ['var ', vs.join(','), ';'] .join('')
| [] -> '',
trans = [:t apply(t):ans] -> ans,
transFn = trans:x -> ['(function(){return ', x, '})'] .join('')
}
BSOMetaTranslator.jumpTableCode = function(cases) {
var buf = new StringBuffer()
buf.nextPutAll("(function(){switch(this._apply('anything')){")
for (var i = 0; i < cases.length; i += 1)
buf.nextPutAll("case " + cases[i][0] + ":return " + cases[i][1] + ";")
buf.nextPutAll("default: throw fail}}).call(this)")
return buf.contents()
}
+3
View File
@@ -0,0 +1,3 @@
{BSOMetaJSParser=objectThatDelegatesTo(BSJSParser,{
"srcElem":function(){var $elf=this,_fromIdx=this.input.idx,r;return this._or((function(){return (function(){this._apply("spaces");r=this._applyWithArgs("foreign",BSOMetaParser,'grammar');this._apply("sc");return r}).call(this)}),(function(){return BSJSParser._superApplyWithArgs(this,'srcElem')}))}});BSOMetaJSTranslator=objectThatDelegatesTo(BSJSTranslator,{
"Grammar":function(){var $elf=this,_fromIdx=this.input.idx;return this._applyWithArgs("foreign",BSOMetaTranslator,'Grammar')}})}
+9
View File
@@ -0,0 +1,9 @@
ometa BSOMetaJSParser <: BSJSParser {
srcElem = spaces BSOMetaParser.grammar:r sc -> r
| ^srcElem
}
ometa BSOMetaJSTranslator <: BSJSTranslator {
Grammar = BSOMetaTranslator.Grammar
}
+37
View File
@@ -0,0 +1,37 @@
{BSNullOptimization=objectThatDelegatesTo(OMeta,{
"setHelped":function(){var $elf=this,_fromIdx=this.input.idx;return (this["_didSomething"]=true)},
"helped":function(){var $elf=this,_fromIdx=this.input.idx;return this._pred(this["_didSomething"])},
"trans":function(){var $elf=this,_fromIdx=this.input.idx,t,ans;return (function(){this._form((function(){return (function(){t=this._apply("anything");this._pred((this[t] != undefined));return ans=this._applyWithArgs("apply",t)}).call(this)}));return ans}).call(this)},
"optimize":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");this._apply("helped");return x}).call(this)},
"App":function(){var $elf=this,_fromIdx=this.input.idx,rule,args;return (function(){rule=this._apply("anything");args=this._many((function(){return this._apply("anything")}));return ["App",rule].concat(args)}).call(this)},
"Act":function(){var $elf=this,_fromIdx=this.input.idx,expr;return (function(){expr=this._apply("anything");return ["Act",expr]}).call(this)},
"Pred":function(){var $elf=this,_fromIdx=this.input.idx,expr;return (function(){expr=this._apply("anything");return ["Pred",expr]}).call(this)},
"Or":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){xs=this._many((function(){return this._apply("trans")}));return ["Or"].concat(xs)}).call(this)},
"XOr":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){xs=this._many((function(){return this._apply("trans")}));return ["XOr"].concat(xs)}).call(this)},
"And":function(){var $elf=this,_fromIdx=this.input.idx,xs;return (function(){xs=this._many((function(){return this._apply("trans")}));return ["And"].concat(xs)}).call(this)},
"Opt":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ["Opt",x]}).call(this)},
"Many":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ["Many",x]}).call(this)},
"Many1":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ["Many1",x]}).call(this)},
"Set":function(){var $elf=this,_fromIdx=this.input.idx,n,v;return (function(){n=this._apply("anything");v=this._apply("trans");return ["Set",n,v]}).call(this)},
"Not":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ["Not",x]}).call(this)},
"Lookahead":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ["Lookahead",x]}).call(this)},
"Form":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ["Form",x]}).call(this)},
"ConsBy":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ["ConsBy",x]}).call(this)},
"IdxConsBy":function(){var $elf=this,_fromIdx=this.input.idx,x;return (function(){x=this._apply("trans");return ["IdxConsBy",x]}).call(this)},
"JumpTable":function(){var $elf=this,_fromIdx=this.input.idx,c,e,ces;return (function(){ces=this._many((function(){return (function(){this._form((function(){return (function(){c=this._apply("anything");return e=this._apply("trans")}).call(this)}));return [c,e]}).call(this)}));return ["JumpTable"].concat(ces)}).call(this)},
"Interleave":function(){var $elf=this,_fromIdx=this.input.idx,m,p,xs;return (function(){xs=this._many((function(){return (function(){this._form((function(){return (function(){m=this._apply("anything");return p=this._apply("trans")}).call(this)}));return [m,p]}).call(this)}));return ["Interleave"].concat(xs)}).call(this)},
"Rule":function(){var $elf=this,_fromIdx=this.input.idx,name,ls,body;return (function(){name=this._apply("anything");ls=this._apply("anything");body=this._apply("trans");return ["Rule",name,ls,body]}).call(this)}});(BSNullOptimization["initialize"]=(function (){(this["_didSomething"]=false)}));BSAssociativeOptimization=objectThatDelegatesTo(BSNullOptimization,{
"And":function(){var $elf=this,_fromIdx=this.input.idx,x,xs;return this._or((function(){return (function(){x=this._apply("trans");this._apply("end");this._apply("setHelped");return x}).call(this)}),(function(){return (function(){xs=this._applyWithArgs("transInside","And");return ["And"].concat(xs)}).call(this)}))},
"Or":function(){var $elf=this,_fromIdx=this.input.idx,x,xs;return this._or((function(){return (function(){x=this._apply("trans");this._apply("end");this._apply("setHelped");return x}).call(this)}),(function(){return (function(){xs=this._applyWithArgs("transInside","Or");return ["Or"].concat(xs)}).call(this)}))},
"XOr":function(){var $elf=this,_fromIdx=this.input.idx,x,xs;return this._or((function(){return (function(){x=this._apply("trans");this._apply("end");this._apply("setHelped");return x}).call(this)}),(function(){return (function(){xs=this._applyWithArgs("transInside","XOr");return ["XOr"].concat(xs)}).call(this)}))},
"transInside":function(){var $elf=this,_fromIdx=this.input.idx,t,xs,ys,x,xs;return (function(){t=this._apply("anything");return this._or((function(){return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly",t);return xs=this._applyWithArgs("transInside",t)}).call(this)}));ys=this._applyWithArgs("transInside",t);this._apply("setHelped");return xs.concat(ys)}).call(this)}),(function(){return (function(){x=this._apply("trans");xs=this._applyWithArgs("transInside",t);return [x].concat(xs)}).call(this)}),(function(){return []}))}).call(this)}});BSSeqInliner=objectThatDelegatesTo(BSNullOptimization,{
"App":function(){var $elf=this,_fromIdx=this.input.idx,s,cs,rule,args;return this._or((function(){return (function(){switch(this._apply('anything')){case "seq":return (function(){s=this._apply("anything");this._apply("end");cs=this._applyWithArgs("seqString",s);this._apply("setHelped");return ["And"].concat(cs).concat([["Act",s]])}).call(this);default: throw fail}}).call(this)}),(function(){return (function(){rule=this._apply("anything");args=this._many((function(){return this._apply("anything")}));return ["App",rule].concat(args)}).call(this)}))},
"inlineChar":function(){var $elf=this,_fromIdx=this.input.idx,c;return (function(){c=this._applyWithArgs("foreign",BSOMetaParser,'eChar');this._not((function(){return this._apply("end")}));return ["App","exactly",c.toProgramString()]}).call(this)},
"seqString":function(){var $elf=this,_fromIdx=this.input.idx,s,cs,cs;return (function(){this._lookahead((function(){return (function(){s=this._apply("anything");return this._pred(((typeof s) === "string"))}).call(this)}));return this._or((function(){return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly","\"");cs=this._many((function(){return this._apply("inlineChar")}));return this._applyWithArgs("exactly","\"")}).call(this)}));return cs}).call(this)}),(function(){return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly","\'");cs=this._many((function(){return this._apply("inlineChar")}));return this._applyWithArgs("exactly","\'")}).call(this)}));return cs}).call(this)}))}).call(this)}});(JumpTable=(function (choiceOp,choice){(this["choiceOp"]=choiceOp);(this["choices"]=({}));this.add(choice)}));(JumpTable["prototype"]["add"]=(function (choice){{var c=choice[(0)];var t=choice[(1)]};if(this["choices"][c]){if((this["choices"][c][(0)] == this["choiceOp"])){this["choices"][c].push(t)}else{(this["choices"][c]=[this["choiceOp"],this["choices"][c],t])}}else{(this["choices"][c]=t)}}));(JumpTable["prototype"]["toTree"]=(function (){{var r=["JumpTable"];var choiceKeys=ownPropertyNames(this["choices"])};for(var i=(0);(i < choiceKeys["length"]);(i+=(1))){r.push([choiceKeys[i],this["choices"][choiceKeys[i]]])};return r}));BSJumpTableOptimization=objectThatDelegatesTo(BSNullOptimization,{
"Or":function(){var $elf=this,_fromIdx=this.input.idx,cs;return (function(){cs=this._many((function(){return this._or((function(){return this._applyWithArgs("jtChoices","Or")}),(function(){return this._apply("trans")}))}));return ["Or"].concat(cs)}).call(this)},
"XOr":function(){var $elf=this,_fromIdx=this.input.idx,cs;return (function(){cs=this._many((function(){return this._or((function(){return this._applyWithArgs("jtChoices","XOr")}),(function(){return this._apply("trans")}))}));return ["XOr"].concat(cs)}).call(this)},
"quotedString":function(){var $elf=this,_fromIdx=this.input.idx,c,cs,c,cs;return (function(){this._lookahead((function(){return this._apply("string")}));this._form((function(){return (function(){switch(this._apply('anything')){case "\"":return (function(){cs=this._many((function(){return (function(){c=this._applyWithArgs("foreign",BSOMetaParser,'eChar');this._not((function(){return this._apply("end")}));return c}).call(this)}));return this._applyWithArgs("exactly","\"")}).call(this);case "\'":return (function(){cs=this._many((function(){return (function(){c=this._applyWithArgs("foreign",BSOMetaParser,'eChar');this._not((function(){return this._apply("end")}));return c}).call(this)}));return this._applyWithArgs("exactly","\'")}).call(this);default: throw fail}}).call(this)}));return cs.join("")}).call(this)},
"jtChoice":function(){var $elf=this,_fromIdx=this.input.idx,x,rest,x;return this._or((function(){return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly","And");this._form((function(){return (function(){this._applyWithArgs("exactly","App");this._applyWithArgs("exactly","exactly");return x=this._apply("quotedString")}).call(this)}));return rest=this._many((function(){return this._apply("anything")}))}).call(this)}));return [x,["And"].concat(rest)]}).call(this)}),(function(){return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly","App");this._applyWithArgs("exactly","exactly");return x=this._apply("quotedString")}).call(this)}));return [x,["Act",x.toProgramString()]]}).call(this)}))},
"jtChoices":function(){var $elf=this,_fromIdx=this.input.idx,op,c,jt,c;return (function(){op=this._apply("anything");c=this._apply("jtChoice");jt=new JumpTable(op,c);this._many((function(){return (function(){c=this._apply("jtChoice");return jt.add(c)}).call(this)}));this._apply("setHelped");return jt.toTree()}).call(this)}});BSOMetaOptimizer=objectThatDelegatesTo(OMeta,{
"optimizeGrammar":function(){var $elf=this,_fromIdx=this.input.idx,n,sn,rs;return (function(){this._form((function(){return (function(){this._applyWithArgs("exactly","Grammar");n=this._apply("anything");sn=this._apply("anything");return rs=this._many((function(){return this._apply("optimizeRule")}))}).call(this)}));return ["Grammar",n,sn].concat(rs)}).call(this)},
"optimizeRule":function(){var $elf=this,_fromIdx=this.input.idx,r,r,r,r;return (function(){r=this._apply("anything");this._or((function(){return r=this._applyWithArgs("foreign",BSSeqInliner,'optimize',r)}),(function(){return this._apply("empty")}));this._many((function(){return this._or((function(){return r=this._applyWithArgs("foreign",BSAssociativeOptimization,'optimize',r)}),(function(){return r=this._applyWithArgs("foreign",BSJumpTableOptimization,'optimize',r)}))}));return r}).call(this)}})}
+93
View File
@@ -0,0 +1,93 @@
// TODO: turn off the "seq" inliner when G.seq !== OMeta.seq (will require some refactoring)
// TODO: add a factorizing optimization (will make jumptables more useful)
ometa BSNullOptimization {
setHelped = !(this._didSomething = true),
helped = ?this._didSomething,
trans = [:t ?(this[t] != undefined) apply(t):ans] -> ans,
optimize = trans:x helped -> x,
App :rule anything*:args -> ['App', rule].concat(args),
Act :expr -> ['Act', expr],
Pred :expr -> ['Pred', expr],
Or trans*:xs -> ['Or'].concat(xs),
XOr trans*:xs -> ['XOr'].concat(xs),
And trans*:xs -> ['And'].concat(xs),
Opt trans:x -> ['Opt', x],
Many trans:x -> ['Many', x],
Many1 trans:x -> ['Many1', x],
Set :n trans:v -> ['Set', n, v],
Not trans:x -> ['Not', x],
Lookahead trans:x -> ['Lookahead', x],
Form trans:x -> ['Form', x],
ConsBy trans:x -> ['ConsBy', x],
IdxConsBy trans:x -> ['IdxConsBy', x],
JumpTable ([:c trans:e] -> [c, e])*:ces -> ['JumpTable'].concat(ces),
Interleave ([:m trans:p] -> [m, p])*:xs -> ['Interleave'].concat(xs),
Rule :name :ls trans:body -> ['Rule', name, ls, body]
}
BSNullOptimization.initialize = function() { this._didSomething = false }
ometa BSAssociativeOptimization <: BSNullOptimization {
And trans:x end setHelped -> x,
And transInside('And'):xs -> ['And'].concat(xs),
Or trans:x end setHelped -> x,
Or transInside('Or'):xs -> ['Or'].concat(xs),
XOr trans:x end setHelped -> x,
XOr transInside('XOr'):xs -> ['XOr'].concat(xs),
transInside :t = [exactly(t) transInside(t):xs] transInside(t):ys setHelped -> xs.concat(ys)
| trans:x transInside(t):xs -> [x].concat(xs)
| -> []
}
ometa BSSeqInliner <: BSNullOptimization {
App = 'seq' :s end seqString(s):cs setHelped -> ['And'].concat(cs).concat([['Act', s]])
| :rule anything*:args -> ['App', rule].concat(args),
inlineChar = BSOMetaParser.eChar:c ~end -> ['App', 'exactly', c.toProgramString()],
seqString = &(:s ?(typeof s === 'string'))
( ['"' inlineChar*:cs '"' ] -> cs
| ['\'' inlineChar*:cs '\''] -> cs
)
}
JumpTable = function(choiceOp, choice) {
this.choiceOp = choiceOp
this.choices = {}
this.add(choice)
}
JumpTable.prototype.add = function(choice) {
var c = choice[0], t = choice[1]
if (this.choices[c]) {
if (this.choices[c][0] == this.choiceOp)
this.choices[c].push(t)
else
this.choices[c] = [this.choiceOp, this.choices[c], t]
}
else
this.choices[c] = t
}
JumpTable.prototype.toTree = function() {
var r = ['JumpTable'], choiceKeys = ownPropertyNames(this.choices)
for (var i = 0; i < choiceKeys.length; i += 1)
r.push([choiceKeys[i], this.choices[choiceKeys[i]]])
return r
}
ometa BSJumpTableOptimization <: BSNullOptimization {
Or (jtChoices('Or') | trans)*:cs -> ['Or'].concat(cs),
XOr (jtChoices('XOr') | trans)*:cs -> ['XOr'].concat(cs),
quotedString = &string [ '"' (BSOMetaParser.eChar:c ~end -> c)*:cs '"'
| '\'' (BSOMetaParser.eChar:c ~end -> c)*:cs '\''] -> cs.join(''),
jtChoice = ['And' ['App' 'exactly' quotedString:x] anything*:rest] -> [x, ['And'].concat(rest)]
| ['App' 'exactly' quotedString:x] -> [x, ['Act', x.toProgramString()]],
jtChoices :op = jtChoice:c {new JumpTable(op, c)}:jt (jtChoice:c {jt.add(c)})* setHelped -> jt.toTree()
}
ometa BSOMetaOptimizer {
optimizeGrammar = ['Grammar' :n :sn optimizeRule*:rs] -> ['Grammar', n, sn].concat(rs),
optimizeRule = :r (BSSeqInliner.optimize(r):r | empty)
( BSAssociativeOptimization.optimize(r):r
| BSJumpTableOptimization.optimize(r):r
)* -> r
}
+3
View File
@@ -0,0 +1,3 @@
ProjectListParser=objectThatDelegatesTo(BSJSParser,{
"proj":function(){var $elf=this,_fromIdx=this.input.idx;return (function(){this._apply("spaces");return this._apply("iName")}).call(this)},
"projs":function(){var $elf=this,_fromIdx=this.input.idx,x,xs;return (function(){x=this._apply("proj");xs=this._many((function(){return (function(){this._apply("spaces");this._applyWithArgs("exactly",",");return this._apply("proj")}).call(this)}));return [x].concat(xs)}).call(this)}})
+5
View File
@@ -0,0 +1,5 @@
ometa ProjectListParser <: BSJSParser {
proj = spaces iName,
projs = proj:x (spaces ',' proj)*:xs -> [x].concat(xs)
}
+166
View File
@@ -0,0 +1,166 @@
<!--
Copyright (c) 2007-2010 Alessandro Warth <[email protected]>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
!-->
<html>
<head>
<title>OMeta/JS 2.0 Workspace</title>
<script src="prototype.js"></script>
<script src="prototype-fix.js"></script>
<script src="lib.js"></script>
<script src="ometa-base.js"></script>
<script src="parser.js"></script>
<script src="bs-js-compiler.js"></script>
<script src="bs-ometa-compiler.js"></script>
<script src="bs-ometa-optimizer.js"></script>
<script src="bs-ometa-js-compiler.js"></script>
<script src="bs-project-list-parser.js"></script>
<script src="workspace.js"></script>
<script src="wiki.js"></script>
<script>
function toggleVisible(id) {
var style = document.getElementById(id).style
style.visibility = style.visibility == "hidden" ? "visible" : "hidden"
style.display = style.display == "block" ? "none" : "block"
}
function initializeThisPage() {
$('workspaceForm').source.onkeydown = onShortCutKey
var makeProjectSelector = function(id) {
$(id + "Home").innerHTML =
"<select id=" + id +
" onChange='loadProject(this.options[this.selectedIndex].value)'><option value=''>(nevermind)</option></select>"
}
var addOption = function(toId, x) {
var option = document.createElement("option")
option.innerHTML = x.replace(/_/g, " ")
option.value = x
$(toId).appendChild(option)
}
makeProjectSelector('infoSelector')
addOption('infoSelector', 'Sample_Project')
addOption('infoSelector', 'Not_Quite_JS')
addOption('infoSelector', 'Things_You_Should_Know')
addOption('infoSelector', 'OMeta_Tutorial')
addOption('infoSelector', 'Memoizing_Parameterized_Rules')
addOption('infoSelector', 'Project_Listing')
makeProjectSelector('projectSelector')
var ps = $('projectSelector')
try {
var projects = ProjectListParser.matchAll(readFile("Project_Listing"), "projs")
for (var idx = 0; idx < projects.length; idx++)
addOption('projectSelector', projects[idx])
}
catch (e) { }
$('workspaceForm').source.value = $('workspaceForm').source.origValue = ''
$('workspaceForm').translation.value = ''
$('workspaceForm').transcript.value = ''
loadProject()
}
saveIt = saveProject
if (!document.location.hash)
document.location.hash = "#Sample_Project"
titleRest = " - <nobr><span title='In case you are wondering, this is\n" +
"(OMeta/JS) 2.0, not OMeta/(JS 2.0).\n" +
"In other words, it has nothing to do\n" +
"with JS 2 / EcmaScript 2.'>OMeta/JS 2.0</span> Workspace</nobr>"
function translateCode(s) {
var translationError = function(m, i) { alert("Translation error - please tell Alex about this!"); throw fail },
tree = BSOMetaJSParser.matchAll(s, "topLevel", undefined, function(m, i) { throw objectThatDelegatesTo(fail, {errorPos: i}) })
return BSOMetaJSTranslator.match(tree, "trans", undefined, translationError)
}
function include(fileName) {
return eval(readFile(fileName))
}
</script>
</head>
<body onLoad="initializeThisPage()">
<table border=0 align=right>
<tr><td align=right><b>important info: </b></td><td><span id=infoSelectorHome></span></td></tr>
<tr><td align=right><b>go to project: </b></td><td><span id=projectSelectorHome></span></td></tr>
<tr><td colspan=2 align=right><input type=button value="previous versions of this project" onClick="document.location = 'http://www.tinlizzie.org/ometa-js/websvn/log.php?repname=ometa-js-projects&path=%2F' + document.location.hash.substring(1) + '.txt&rev=0&sc=0&isdir=0'"><br>
</td></tr>
</table>
<table border=0><tr><td><h2 id=title>OMeta/JS 2.0 Workspace<!-- <small><font color=lightgray>(not to be confused with JS 2 / EcmaScript 4)</font></small>--></h2></td></tr></table>
<b>Instructions</b>
<input type=button value="+/-" onClick="toggleVisible('instructions')">
<br>
<div id=instructions style="visibility: visible; display: block">
<table bgcolor=#f9f9f9 cellpadding=4
style="border: 1px solid #333333; padding: .2em .2em .2em .2em; margin-bottom: .4em; margin-top: .1em">
<tr><td>
The text area below (<b>source</b>) works like a Smalltalk workspace:
<bl><li>
To evaluate some code, just select it and press the <input type=button value="do it" onClick="doIt()"> button.
</li><li>
Pressing <input type=button value="do it" onClick="doIt()"> without a selection evaluates the line that the cursor is on.
</li><li>
<input type=button value="print it" onClick="printIt()"> is like <input type=button value="do it" onClick="doIt()">,
but it also prints the result.
</li></bl>
Also, you can press <input type=button value="save it" onClick="saveIt()"> to save the current project.
</td></tr></table>
</div>
<b><span title="A useful place to add new HTMLElements - see Canvas project for an example">Play Area</span></b>
<input type=button value="+/-" onClick="toggleVisible('playArea')">
<br>
<div id=playArea style="visibility: visible; display: block"></div>
<form id=workspaceForm>
<b>Source</b>
<input type=button value="+/-" onClick="toggleVisible('source')">
<br>
<div id=source style="visibility: visible; display: block">
<textarea cols=132 rows=24 name=source style="font-family:monaco, monospace; font-size: 10pt"></textarea><br>
<input type=button value="print it (ctrl+p)" onClick="printIt()" style="margin-bottom: .4em">
<input type=button value="do it (ctrl+d)" onClick="doIt()" style="margin-bottom: .4em">
<input type=button value="save it (ctrl + s)" onClick="saveProject()" style="margin-bottom: .4em"><br>
</div>
<b><span title="Shows the JavaScript translation of the last thing that was evaluated above">Translation</span></b>
<input type=button value="+/-" onClick="toggleVisible('translation')">
<br>
<div id=translation style="visibility: hidden; display: none">
<textarea cols=132 rows=4 name=translation style="font-family:monaco, monospace; font-size: 10pt; margin-bottom: .4em">
</textArea>
</div>
<b>Transcript</b>
<input type=button value="+/-" onClick="toggleVisible('transcript')">
<br>
<div id=transcript style="visibility: hidden; display: none">
<textarea cols=132 rows=4 name=transcript
style="font-family:monaco, monospace; font-size: 10pt; margin-bottom: .4em"></textArea>
</div>
</form>
To learn more about OMeta, click <a href=http://www.tinlizzie.org/ometa/>here</a>.<br>
</body>
</html>
+20
View File
@@ -0,0 +1,20 @@
var ometa = require('./ometa-node');
var createParser = function(grammar, parserCallback) {
var parser;
try {
parser = ometa(grammar);
parserCallback(null, {
parse: function(code, rule, callback) {
callback(null, parser(code, rule));
}
});
}
catch(err) {
parserCallback({
inner: err
});
}
};
module.exports.createParser = createParser;
Generated Vendored
+183
View File
@@ -0,0 +1,183 @@
/*
Copyright (c) 2007-2010 Alessandro Warth <[email protected]>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
// try to use StringBuffer instead of string concatenation to improve performance
function StringBuffer() {
this.strings = []
for (var idx = 0; idx < arguments.length; idx++)
this.nextPutAll(arguments[idx])
}
StringBuffer.prototype.nextPutAll = function(s) { this.strings.push(s) }
StringBuffer.prototype.contents = function() { return this.strings.join("") }
String.prototype.writeStream = function() { return new StringBuffer(this) }
// make Arrays print themselves sensibly
printOn = function(x, ws) {
if (x === undefined || x === null)
ws.nextPutAll("" + x)
else if (x.constructor === Array) {
ws.nextPutAll("[")
for (var idx = 0; idx < x.length; idx++) {
if (idx > 0)
ws.nextPutAll(", ")
printOn(x[idx], ws)
}
ws.nextPutAll("]")
}
else
ws.nextPutAll(x.toString())
}
Array.prototype.toString = function() { var ws = "".writeStream(); printOn(this, ws); return ws.contents() }
// delegation
objectThatDelegatesTo = function(x, props) {
var f = function() { }
f.prototype = x
var r = new f()
for (var p in props)
if (props.hasOwnProperty(p))
r[p] = props[p]
return r
}
// some reflective stuff
ownPropertyNames = function(x) {
var r = []
for (name in x)
if (x.hasOwnProperty(name))
r.push(name)
return r
}
isImmutable = function(x) {
return x === null || x === undefined || typeof x === "boolean" || typeof x === "number" || typeof x === "string"
}
String.prototype.digitValue = function() { return this.charCodeAt(0) - "0".charCodeAt(0) }
isSequenceable = function(x) { return typeof x == "string" || x.constructor === Array }
// some functional programming stuff
if(!Array.prototype.map) {
Array.prototype.map = function(f) {
var r = []
for (var idx = 0; idx < this.length; idx++)
r[idx] = f(this[idx])
return r
}
}
Array.prototype.reduce = function(f, z) {
var r = z
for (var idx = 0; idx < this.length; idx++)
r = f(r, this[idx])
return r
}
Array.prototype.delimWith = function(d) {
return this.reduce(
function(xs, x) {
if (xs.length > 0)
xs.push(d)
xs.push(x)
return xs
},
[])
}
// Squeak's ReadStream, kind of
function ReadStream(anArrayOrString) {
this.src = anArrayOrString
this.pos = 0
}
ReadStream.prototype.atEnd = function() { return this.pos >= this.src.length }
ReadStream.prototype.next = function() { return this.src.at(this.pos++) }
// escape characters
escapeStringFor = new Object()
for (var c = 0; c < 256; c++)
escapeStringFor[c] = String.fromCharCode(c)
escapeStringFor["\\".charCodeAt(0)] = "\\\\"
escapeStringFor['"'.charCodeAt(0)] = '\\"'
escapeStringFor["'".charCodeAt(0)] = "\\'"
escapeStringFor["\r".charCodeAt(0)] = "\\r"
escapeStringFor["\n".charCodeAt(0)] = "\\n"
escapeStringFor["\t".charCodeAt(0)] = "\\t"
escapeChar = function(c) {
var charCode = c.charCodeAt(0)
return charCode > 255 ? String.fromCharCode(charCode) : escapeStringFor[charCode]
}
function unescape(s) {
if (s.charAt(0) == '\\')
switch (s.charAt(1)) {
case '\\': return '\\'
case 'r': return '\r'
case 'n': return '\n'
case 't': return '\t'
default: return s.charAt(1)
}
else
return s
}
String.prototype.toProgramString = function() {
var ws = "\"".writeStream()
for (var idx = 0; idx < this.length; idx++)
ws.nextPutAll(escapeChar(this.charAt(idx)))
ws.nextPutAll("\"")
return ws.contents()
}
// C-style tempnam function
function tempnam(s) { return (s ? s : "_tmpnam_") + tempnam.n++ }
tempnam.n = 0
// unique tags for objects (useful for making "hash tables")
getTag = (function() {
var numIdx = 0
return function(x) {
if (x === null || x === undefined)
return x
switch (typeof x) {
case "boolean": return x == true ? "Btrue" : "Bfalse"
case "string": return "S" + x
case "number": return "N" + x
default: return x.hasOwnProperty("_id_") ? x._id_ : x._id_ = "R" + numIdx++
}
}
})()
module.exports.StringBuffer = StringBuffer;
+45
View File
@@ -0,0 +1,45 @@
Copyright (c) 2010 Brian Mavity <brian@brianmavity.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Except as contained in this notice, the name(s) of the above copyright
holders shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written authorization.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Copyright (c) 2007-2010 Alessandro Warth <awarth@cs.ucla.edu>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+4
View File
@@ -0,0 +1,4 @@
ometa T <: Parser {
t = '\n' -> '\n',
selectors_group = (t | anything)*
}
+35
View File
@@ -0,0 +1,35 @@
var sys = require('sys'),
fs = require('fs'),
ometa = require(__dirname + '/index.js');
rawGrammar = "ometa T <: Parser { t = '\n' -> 'wtf', a = (t | anything)* }";
var parse = function(grammar, stringToParse, rule) {
ometa.createParser(grammar, function(err, parser) {
if(err) {
sys.puts(err.inner.toString());
} else {
parser.parse('ican\'t\ndothis\n', 'a', function(err, result) {
if(err) {
console.log(err);
} else {
console.log(result);
}
});
}
});
};
var compare = function() {
var rawFile = fs.readFileSync(__dirname + '/newLineGrammar.ometa', 'utf8'),
file = rawFile.slice(1).replace(/\\n/g, '\n'),
maxChars = file.length >= rawGrammar.length ? file.length : rawGrammar.length,
i;
parse(file);
for(i = 0; i < maxChars; i += 1) {
console.log(file[i] + ' :: ' + rawGrammar[i]);
}
};
module.exports.parse = parse;
parse(rawGrammar);
compare();
+508
View File
@@ -0,0 +1,508 @@
/*
Copyright (c) 2007-2010 Alessandro Warth <[email protected]>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
/*
new syntax:
#foo and `foo match the string object 'foo' (it's also accepted in my JS)
'abc' match the string object 'abc'
'c' match the string object 'c'
``abc'' match the sequence of string objects 'a', 'b', 'c'
"abc" token('abc')
[1 2 3] match the array object [1, 2, 3]
foo(bar) apply rule foo with argument bar
-> ... semantic actions written in JS (see OMetaParser's atomicHostExpr rule)
*/
/*
ometa M {
number = number:n digit:d -> { n * 10 + d.digitValue() }
| digit:d -> { d.digitValue() }
}
translates to...
M = objectThatDelegatesTo(OMeta, {
number: function() {
return this._or(function() {
var n = this._apply("number"),
d = this._apply("digit")
return n * 10 + d.digitValue()
},
function() {
var d = this._apply("digit")
return d.digitValue()
}
)
}
})
M.matchAll("123456789", "number")
*/
// the failure exception
fail = { toString: function() { return "match failed" } }
// streams and memoization
function OMInputStream(hd, tl) {
this.memo = { }
this.lst = tl.lst
this.idx = tl.idx
this.hd = hd
this.tl = tl
}
OMInputStream.prototype.head = function() { return this.hd }
OMInputStream.prototype.tail = function() { return this.tl }
OMInputStream.prototype.type = function() { return this.lst.constructor }
OMInputStream.prototype.upTo = function(that) {
var r = [], curr = this
while (curr != that) {
r.push(curr.head())
curr = curr.tail()
}
return this.type() == String ? r.join('') : r
}
function OMInputStreamEnd(lst, idx) {
this.memo = { }
this.lst = lst
this.idx = idx
}
OMInputStreamEnd.prototype = objectThatDelegatesTo(OMInputStream.prototype)
OMInputStreamEnd.prototype.head = function() { throw fail }
OMInputStreamEnd.prototype.tail = function() { throw fail }
// This is necessary b/c in IE, you can't say "foo"[idx]
Array.prototype.at = function(idx) { return this[idx] }
String.prototype.at = String.prototype.charAt
function ListOMInputStream(lst, idx) {
this.memo = { }
this.lst = lst
this.idx = idx
this.hd = lst.at(idx)
}
ListOMInputStream.prototype = objectThatDelegatesTo(OMInputStream.prototype)
ListOMInputStream.prototype.head = function() { return this.hd }
ListOMInputStream.prototype.tail = function() { return this.tl || (this.tl = makeListOMInputStream(this.lst, this.idx + 1)) }
function makeListOMInputStream(lst, idx) { return new (idx < lst.length ? ListOMInputStream : OMInputStreamEnd)(lst, idx) }
Array.prototype.toOMInputStream = function() { return makeListOMInputStream(this, 0) }
String.prototype.toOMInputStream = function() { return makeListOMInputStream(this, 0) }
function makeOMInputStreamProxy(target) {
return objectThatDelegatesTo(target, {
memo: { },
target: target,
tail: function() { return makeOMInputStreamProxy(target.tail()) }
})
}
// Failer (i.e., that which makes things fail) is used to detect (direct) left recursion and memoize failures
function Failer() { }
Failer.prototype.used = false
// the OMeta "class" and basic functionality
OMeta = {
_apply: function(rule) {
var memoRec = this.input.memo[rule]
if (memoRec == undefined) {
var origInput = this.input,
failer = new Failer()
if (this[rule] === undefined)
throw 'tried to apply undefined rule "' + rule + '"'
this.input.memo[rule] = failer
this.input.memo[rule] = memoRec = {ans: this[rule].call(this), nextInput: this.input}
if (failer.used) {
var sentinel = this.input
while (true) {
try {
this.input = origInput
var ans = this[rule].call(this)
if (this.input == sentinel)
throw fail
memoRec.ans = ans
memoRec.nextInput = this.input
}
catch (f) {
if (f != fail)
throw f
break
}
}
}
}
else if (memoRec instanceof Failer) {
memoRec.used = true
throw fail
}
this.input = memoRec.nextInput
return memoRec.ans
},
// note: _applyWithArgs and _superApplyWithArgs are not memoized, so they can't be left-recursive
_applyWithArgs: function(rule) {
for (var idx = arguments.length - 1; idx > 0; idx--)
this._prependInput(arguments[idx])
return this[rule].call(this)
},
_superApplyWithArgs: function(recv, rule) {
for (var idx = arguments.length - 1; idx > 1; idx--)
recv._prependInput(arguments[idx])
return this[rule].call(recv)
},
_prependInput: function(v) {
this.input = new OMInputStream(v, this.input)
},
// if you want your grammar (and its subgrammars) to memoize parameterized rules, invoke this method on it:
memoizeParameterizedRules: function() {
this._prependInput = function(v) {
var newInput
if (isImmutable(v)) {
newInput = this.input[getTag(v)]
if (!newInput) {
newInput = new OMInputStream(v, this.input)
this.input[getTag(v)] = newInput
}
}
else newInput = new OMInputStream(v, this.input)
this.input = newInput
}
this._applyWithArgs = function(rule) {
for (var idx = arguments.length - 1; idx > 0; idx--)
this._prependInput(arguments[idx])
return this._apply(rule)
}
},
_pred: function(b) {
if (b)
return true
throw fail
},
_not: function(x) {
var origInput = this.input
try { x.call(this) }
catch (f) {
if (f != fail)
throw f
this.input = origInput
return true
}
throw fail
},
_lookahead: function(x) {
var origInput = this.input,
r = x.call(this)
this.input = origInput
return r
},
_or: function() {
var origInput = this.input
for (var idx = 0; idx < arguments.length; idx++)
try { this.input = origInput; return arguments[idx].call(this) }
catch (f) {
if (f != fail)
throw f
}
throw fail
},
_xor: function(ruleName) {
var origInput = this.input, idx = 1, newInput, ans
while (idx < arguments.length) {
try {
this.input = origInput
ans = arguments[idx].call(this)
if (newInput)
throw 'more than one choice matched by "exclusive-OR" in ' + ruleName
newInput = this.input
}
catch (f) {
if (f != fail)
throw f
}
idx++
}
if (newInput) {
this.input = newInput
return ans
}
else
throw fail
},
disableXORs: function() {
this._xor = function(ruleName) {
var origInput = this.input
for (var idx = 1; idx < arguments.length; idx++)
try { this.input = origInput; return arguments[idx].call(this) }
catch (f) {
if (f != fail)
throw f
}
throw fail
}
},
_opt: function(x) {
var origInput = this.input, ans
try { ans = x.call(this) }
catch (f) {
if (f != fail)
throw f
this.input = origInput
}
return ans
},
_many: function(x) {
var ans = arguments[1] != undefined ? [arguments[1]] : []
while (true) {
var origInput = this.input
try { ans.push(x.call(this)) }
catch (f) {
if (f != fail)
throw f
this.input = origInput
break
}
}
return ans
},
_many1: function(x) { return this._many(x, x.call(this)) },
_form: function(x) {
var v = this._apply("anything")
if (!isSequenceable(v))
throw fail
var origInput = this.input
this.input = v.toOMInputStream()
var r = x.call(this)
this._apply("end")
this.input = origInput
return v
},
_consumedBy: function(x) {
var origInput = this.input
x.call(this)
return origInput.upTo(this.input)
},
_idxConsumedBy: function(x) {
var origInput = this.input
x.call(this)
return {fromIdx: origInput.idx, toIdx: this.input.idx}
},
_interleave: function(mode1, part1, mode2, part2 /* ..., moden, partn */) {
var currInput = this.input, ans = []
for (var idx = 0; idx < arguments.length; idx += 2)
ans[idx / 2] = (arguments[idx] == "*" || arguments[idx] == "+") ? [] : undefined
while (true) {
var idx = 0, allDone = true
while (idx < arguments.length) {
if (arguments[idx] != "0")
try {
this.input = currInput
switch (arguments[idx]) {
case "*": ans[idx / 2].push(arguments[idx + 1].call(this)); break
case "+": ans[idx / 2].push(arguments[idx + 1].call(this)); arguments[idx] = "*"; break
case "?": ans[idx / 2] = arguments[idx + 1].call(this); arguments[idx] = "0"; break
case "1": ans[idx / 2] = arguments[idx + 1].call(this); arguments[idx] = "0"; break
default: throw "invalid mode '" + arguments[idx] + "' in OMeta._interleave"
}
currInput = this.input
break
}
catch (f) {
if (f != fail)
throw f
// if this (failed) part's mode is "1" or "+", we're not done yet
allDone = allDone && (arguments[idx] == "*" || arguments[idx] == "?")
}
idx += 2
}
if (idx == arguments.length) {
if (allDone)
return ans
else
throw fail
}
}
},
_currIdx: function() { return this.input.idx },
// some basic rules
anything: function() {
var r = this.input.head()
this.input = this.input.tail()
return r
},
end: function() {
return this._not(function() { return this._apply("anything") })
},
pos: function() {
return this.input.idx
},
empty: function() { return true },
apply: function() {
var r = this._apply("anything")
return this._apply(r)
},
foreign: function() {
var g = this._apply("anything"),
r = this._apply("anything"),
gi = objectThatDelegatesTo(g, {input: makeOMInputStreamProxy(this.input)})
gi.initialize();
var ans = gi._apply(r)
this.input = gi.input.target
return ans
},
// some useful "derived" rules
exactly: function() {
var wanted = this._apply("anything")
if (wanted === this._apply("anything"))
return wanted
throw fail
},
"true": function() {
var r = this._apply("anything")
this._pred(r === true)
return r
},
"false": function() {
var r = this._apply("anything")
this._pred(r === false)
return r
},
"undefined": function() {
var r = this._apply("anything")
this._pred(r === undefined)
return r
},
number: function() {
var r = this._apply("anything")
this._pred(typeof r === "number")
return r
},
string: function() {
var r = this._apply("anything")
this._pred(typeof r === "string")
return r
},
"char": function() {
var r = this._apply("anything")
this._pred(typeof r === "string" && r.length == 1)
return r
},
space: function() {
var r = this._apply("char")
this._pred(r.charCodeAt(0) <= 32)
return r
},
spaces: function() {
return this._many(function() { return this._apply("space") })
},
digit: function() {
var r = this._apply("char")
this._pred(r >= "0" && r <= "9")
return r
},
lower: function() {
var r = this._apply("char")
this._pred(r >= "a" && r <= "z")
return r
},
upper: function() {
var r = this._apply("char")
this._pred(r >= "A" && r <= "Z")
return r
},
letter: function() {
return this._or(function() { return this._apply("lower") },
function() { return this._apply("upper") })
},
letterOrDigit: function() {
return this._or(function() { return this._apply("letter") },
function() { return this._apply("digit") })
},
firstAndRest: function() {
var first = this._apply("anything"),
rest = this._apply("anything")
return this._many(function() { return this._apply(rest) }, this._apply(first))
},
seq: function() {
var xs = this._apply("anything")
for (var idx = 0; idx < xs.length; idx++)
this._applyWithArgs("exactly", xs.at(idx))
return xs
},
notLast: function() {
var rule = this._apply("anything"),
r = this._apply(rule)
this._lookahead(function() { return this._apply(rule) })
return r
},
initialize: function() { },
// match and matchAll are a grammar's "public interface"
_genericMatch: function(input, rule, args, matchFailed) {
if (args == undefined)
args = []
var realArgs = [rule]
for (var idx = 0; idx < args.length; idx++)
realArgs.push(args[idx])
var m = objectThatDelegatesTo(this, {input: input})
m.initialize()
try { return realArgs.length == 1 ? m._apply.call(m, realArgs[0]) : m._applyWithArgs.apply(m, realArgs) }
catch (f) {
if (f == fail && matchFailed != undefined) {
var input = m.input
if (input.idx != undefined) {
while (input.tl != undefined && input.tl.idx != undefined)
input = input.tl
input.idx--
}
return matchFailed(m, input.idx)
}
throw f
}
},
match: function(obj, rule, args, matchFailed) {
return this._genericMatch([obj].toOMInputStream(), rule, args, matchFailed)
},
matchAll: function(listyObj, rule, args, matchFailed) {
return this._genericMatch(listyObj.toOMInputStream(), rule, args, matchFailed)
},
createInstance: function() {
var m = objectThatDelegatesTo(this)
m.initialize()
m.matchAll = function(listyObj, aRule) {
m.input = listyObj.toOMInputStream()
return m._apply(aRule)
}
return m
}
}
+23
View File
@@ -0,0 +1,23 @@
var lib = require("./lib");
require("./ometa-base")
require("./parser")
require("./bs-js-compiler")
require("./bs-ometa-compiler")
require("./bs-ometa-optimizer")
require("./bs-ometa-js-compiler")
var translateCode = function(s) {
var translationError = function(m, i) { alert("Translation error - please tell Alex about this!"); throw fail },
tree = BSOMetaJSParser.matchAll(s, "topLevel", undefined, function(m, i) { throw objectThatDelegatesTo(fail, {errorPos: i}) })
return BSOMetaJSTranslator.match(tree, "trans", undefined, translationError)
}
var parse = function(grammarString) {
var parser = eval(translateCode(grammarString));
return function(stringToParse, rule) {
return eval(parser.matchAll(stringToParse, rule));
};
};
module.exports = parse;
+19
View File
@@ -0,0 +1,19 @@
load("lib.js")
load("ometa-base.js")
load("parser.js")
load("bs-js-compiler.js")
load("bs-ometa-compiler.js")
load("bs-ometa-optimizer.js")
load("bs-ometa-js-compiler.js")
alert = print
translateCode = function(s) {
var translationError = function(m, i) { alert("Translation error - please tell Alex about this!"); throw fail },
tree = BSOMetaJSParser.matchAll(s, "topLevel", undefined, function(m, i) {
throw objectThatDelegatesTo(fail, {errorPos: i}) })
return BSOMetaJSTranslator.match(tree, "trans", undefined, translationError)
}
ometa = function(s) { return eval(translateCode(s)) }
+21
View File
@@ -0,0 +1,21 @@
function translateCode(s) {
var translationError = function(m, i) { alert("Translation error - please tell Alex about this!"); throw fail },
tree = BSOMetaJSParser.matchAll(s, "topLevel", undefined, function(m, i) {
throw objectThatDelegatesTo(fail, {errorPos: i}) })
return BSOMetaJSTranslator.match(tree, "trans", undefined, translationError)
}
origOnload = window.onload
window.onload = function() {
var scripts = document.getElementsByTagName("script")
for (var idx = 0; idx < scripts.length; idx++) {
var script = scripts[idx]
if (script.type === "text/x-ometa-js")
eval(translateCode(script.innerHTML))
}
if (typeof origOnload === "string")
eval(origOnload)
else if (typeof origOnload === "function")
origOnload()
}
Generated Vendored
+2
View File
@@ -0,0 +1,2 @@
./v8 ometa-rhino.js $@ --shell
+10
View File
@@ -0,0 +1,10 @@
{
"name": "ometa"
, "contributors": [
{ "name": "Brian Mavity", "email": "[email protected]" }
]
, "description": "JavaScript Implementation of OMeta Parsing Language"
, "engines": { "node": ">= 0.2.0" }
, "main": "./index.js"
, "version": "0.2.2"
}
+46
View File
@@ -0,0 +1,46 @@
/*
Copyright (c) 2007, 2008 Alessandro Warth <[email protected]>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
Parser = objectThatDelegatesTo(OMeta, {
listOf: function() {
var rule = this._apply("anything"),
delim = this._apply("anything")
return this._or(function() {
var r = this._apply(rule)
return this._many(function() {
this._applyWithArgs("token", delim)
return this._apply(rule)
},
r)
},
function() { return [] })
},
token: function() {
var cs = this._apply("anything")
this._apply("spaces")
return this._applyWithArgs("seq", cs)
}
})
+91
View File
@@ -0,0 +1,91 @@
// Override prototype.js' Ajax
// To allow PUT and PROPFIND method
Ajax.Request.prototype.request = function(url) {
this.url = url;
this.method = this.options.method;
var params = Object.clone(this.options.parameters);
if (!['get', 'post', 'put', 'propfind'].include(this.method)) {
// if (!['get', 'post'].include(this.method)) {
// simulate other verbs over post
params['_method'] = this.method;
this.method = 'post';
}
this.parameters = params;
if (params = Hash.toQueryString(params)) {
// when GET, append parameters to URL
if (this.method == 'get')
this.url += (this.url.include('?') ? '&' : '?') + params;
else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
params += '&_=';
}
try {
if (this.options.onCreate) this.options.onCreate(this.transport);
Ajax.Responders.dispatch('onCreate', this, this.transport);
this.transport.open(this.method.toUpperCase(), this.url,
this.options.asynchronous);
if (this.options.asynchronous)
setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
this.transport.onreadystatechange = this.onStateChange.bind(this);
this.setRequestHeaders();
this.body = (['post', 'put'].include(this.method)) ? (this.options.postBody || params) : null;
this.transport.send(this.body);
/* Force Firefox to handle ready state 4 for synchronous requests */
if (!this.options.asynchronous && this.transport.overrideMimeType)
this.onStateChange();
}
catch (e) {
this.dispatchException(e);
}
}
// To avoid properties added to Object by ometa.
Ajax.Request.prototype.setRequestHeaders = function(url) {
var headers = {
'X-Requested-With': 'XMLHttpRequest',
'X-Prototype-Version': Prototype.Version,
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
};
if (this.method == 'post') {
headers['Content-type'] = this.options.contentType +
(this.options.encoding ? '; charset=' + this.options.encoding : '');
/* Force "Connection: close" for older Mozilla browsers to work
* around a bug where XMLHttpRequest sends an incorrect
* Content-length header. See Mozilla Bugzilla #246651.
*/
if (this.transport.overrideMimeType &&
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
headers['Connection'] = 'close';
}
// user-defined headers
if (typeof this.options.requestHeaders == 'object') {
var extras = this.options.requestHeaders;
if (typeof extras.push == 'function')
for (var i = 0, length = extras.length; i < length; i += 2)
headers[extras[i]] = extras[i+1];
else
$H(extras).each(function(pair) { headers[pair.key] = pair.value });
}
for (var name in headers) {
if (typeof headers[name] == "string") {
this.transport.setRequestHeader(name, headers[name]);
}
}
}
+4222
View File
File diff suppressed because it is too large. Load diff
+10
View File
@@ -0,0 +1,10 @@
To use OMeta under Rhino:
Monad:~/prog/ometa-js awarth$ java org.mozilla.javascript.tools.shell.Main
Rhino 1.7 release 1 2008 03 06
js> load("ometa-rhino.js")
js> ometa("ometa M { ones = 1* }")
[object Object]
js> M.matchAll([1, 1, 1, 1, 1], "ones")
[1, 1, 1, 1, 1]
+154
View File
@@ -0,0 +1,154 @@
<html>
<head>
<script src="lib.js"></script>
<script src="ometa-base.js"></script>
<script src="parser.js"></script>
<script src="bs-js-compiler.js"></script>
<script src="bs-ometa-compiler.js"></script>
<script src="bs-ometa-optimizer.js"></script>
<script src="bs-ometa-js-compiler.js"></script>
<script src="ometa-script-tag.js"></script>
<script type="text/x-ometa-js">
ometa CssSelector <: Parser {
crChar = '\r',
ffChar = '\f',
nlChar = '\n',
tabChar = '\t',
lineEnding = crChar | ffChar | nlChar,
tabOrLineEnding = tabChar | lineEnding,
ident = '-' nmstart:s nmchar*:cs -> { '-' + s + cs.join('') }
| nmstart:s nmchar*:cs -> { s + cs.join('') },
name = nmchar+:n -> { n.join('') },
nmstart = ('_' | letter | nonascii | escape):n -> { n },
nonascii = '',
unicode = '',
escape = unicode | '',
nmchar = '_' | '-' | letterOrDigit | nonascii | escape,
num = digit+: d -> d.join('')
| digit* '.' digit+,
string = (string1 | string2):s -> { s },
//string1 = '\"' (~(lineEnding | '\"') | '\\' nl | nonascii | escape)*:s '\"' -> { '\"' + s.join('') + '\"' },
string1 = '"' letter*:s '"' -> { '"' + s.join('') + '"' },
string2 = '\'' (~(lineEnding | '\'') | '\\' nl | nonascii | escape)*:s '\'' -> { '\'' + s.join('') + '\'' },
//invalid = invalid1 | invalid2,
//invalid1 = '\"' (~(lineEnding | '\"') | '\\' nl | nonascii | escape)*,
//invalid2 = '\'' (~(lineEnding | '\'') | '\\' nl | nonascii | escape)*,
nl = crChar nlChar
| lineEnding,
D = 'd' | 'D',
E = 'e' | 'E',
N = 'n' | 'N',
O = 'o' | 'O',
T = 't' | 'T',
V = 'v' | 'V',
S = ' ' -> { ' ' }
| '\n' -> { '\n' },
INCLUDES = '~' '=' -> { '~=' },
DASHMATCH = '|' '=' -> { '|=' },
PREFIXMATCH = '^' '=' -> { '^=' },
SUFFIXMATCH = '$' '=' -> { '$=' },
SUBSTRINGMATCH = '*' '=' -> { '*=' },
IDENT = ident,
STRING = string:s -> { s },
FUNCTION = ident:i '(' -> { i + '(' },
NUMBER = num:n -> { n },
HASH = '#' name:n -> { '#' + n },
PLUS = S+ '+' -> { ' +' }
| '+' -> { '+' },
// First line of next selector is a Css Hack
GREATER = '>' '>' -> { '> >' }
| S+ '>' -> { ' >' }
| '>' -> { '>' },
COMMA = S+ ',' -> { ' ,' }
| ',' -> { ',' },
TILDE = S+ '~' -> { ' ~' }
| '~' -> { '~' },
NOT = ':' N O T '(' -> { ':not(' },
ATKEYWORD = '@' ident,
INVALID = invalid,
PERCENTAGE = num:n '%' -> { n + '%' },
DIMENSION = num:n ident:i -> { n + i },
CDO = '<' '!' '-' '-',
CDC = '-' '-' '>',
selectors_group = selector:pre comma_separated_selector*:post -> { self.add(pre + post.join('')); self },
comma_separated_selector = COMMA:com S*:spacing selector:sel -> { com + spacing.join('') + sel },
selector = simple_selector_sequence:sim (combined_sequence)*:additional -> { sim + additional.join('') }
// Css Hack
| combined_sequence*:comb -> { comb.join('') },
combinator = PLUS:p S+ -> { p + ' ' }
| PLUS:p -> { p }
| GREATER:g S+ -> { g + ' ' }
| GREATER:g -> { g }
| TILDE:t S+ -> { t + ' ' }
| TILDE:t -> { t }
| S+:spacing -> { spacing.join('') },
combined_sequence = combinator:comb simple_selector_sequence:sel -> { comb + sel }
| combinator+:comb simple_selector_sequence:sel -> { comb.join('') + sel },
non_namespaced_selector = (HASH | class | attrib | negation | pseudo):sel -> { sel },
simple_selector_sequence = namespace_prefix:pre '*' non_namespaced_selector*:post -> { pre + '*' + post.join('') }
| namespace_prefix:pre element_name:ele non_namespaced_selector*:post -> { pre + ele + post.join('') }
| '*' non_namespaced_selector*:post -> { '*' + post.join('') }
| element_name:ele non_namespaced_selector*:post -> { ele + post.join('') }
| non_namespaced_selector+:sels -> { sels.join('') }
// Css Hack
| expression:ex -> { ex },
namespace_prefix = ('*' | IDENT):pre '|' -> { pre + '|' }
| '|' -> { '|' },
// First line of the next selector is a Css Hack
element_name = IDENT:i '*' -> { i + '*' }
| IDENT:i -> { i },
class = '.' IDENT:i -> { '.' + i },
attrib = '[' S* possible_namespaced_attrib:att ']' -> { '[' + att + ']' },
possible_namespaced_attrib = namespace_prefix:pre ident_with_possible_postfix:post -> { pre + post }
| ident_with_possible_postfix:post -> { post },
ident_with_possible_postfix = IDENT:left S* attrib_match:match S* (IDENT | STRING):right S* -> { left + match + right }
| IDENT:i S* -> { i },
attrib_match = (PREFIXMATCH | SUFFIXMATCH | SUBSTRINGMATCH | equals_match | INCLUDES | DASHMATCH):m -> { m },
equals_match = '=' -> { '=' },
pseudo = ':' ':' (functional_pseudo | IDENT):i -> { '::' + i }
| ':' (functional_pseudo | IDENT):i -> { ':' + i },
functional_pseudo = FUNCTION:f S* full_expression:e ')' -> { f + e + ')' }
// Css Hack for :-moz-any(...)
| FUNCTION:f S* selectors_group:sel ')' -> { f + sel + ')' },
expression_content = (PLUS | '-' | PERCENTAGE | DIMENSION | NUMBER | STRING | IDENT):e -> { e },
expression = expression_content:ec S+ expression:e -> { ec + ' ' + e }
| expression_content:ec expression:e -> { ec + e }
| expression_content:ec S* -> { ec },
full_expression = (expression)+:ea -> { ea.join('') },
negation = NOT:n S* negation_arg:na S* ')' -> { n + na + ')' },
//negation_arg = (type_selector | universal | HASH | class | attrib | pseudo):na -> { na }
//Technically not allowed, but here for scss compatibility
negation_arg = (selectors_group):na -> { na }
}
CssSelector.initialize = function() {
var s;
this.toString = function() {
return s;
};
this.add = function(st) {
s = st;
};
};
console.log(CssSelector.matchAll("E,\nF", "selectors_group").toString());
console.log(CssSelector.matchAll("E\nF", "selectors_group").toString());
console.log(CssSelector.matchAll("E, F\nG, H", "selectors_group").toString());
</script>
<body>
hello world
</body>
</html>
+320
View File
@@ -0,0 +1,320 @@
// Support for translateCode added by Alex Warth <[email protected]>
// Copyright 2009 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <v8.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
v8::Handle<v8::Context> context;
void RunShell(v8::Handle<v8::Context> context);
bool ExecuteString(v8::Handle<v8::String> source,
v8::Handle<v8::Value> name,
bool print_result,
bool report_exceptions);
v8::Handle<v8::Value> Print(const v8::Arguments& args);
v8::Handle<v8::Value> Read(const v8::Arguments& args);
v8::Handle<v8::Value> Load(const v8::Arguments& args);
v8::Handle<v8::Value> Quit(const v8::Arguments& args);
v8::Handle<v8::Value> Version(const v8::Arguments& args);
v8::Handle<v8::String> ReadFile(const char* name);
void ReportException(v8::TryCatch* handler);
int RunMain(int argc, char* argv[]) {
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
v8::HandleScope handle_scope;
// Create a template for the global object.
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
// Bind the global 'print' function to the C++ Print callback.
global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
// Bind the global 'read' function to the C++ Read callback.
global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
// Bind the global 'load' function to the C++ Load callback.
global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
// Bind the 'quit' function
global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
// Bind the 'version' function
global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
// Create a new execution environment containing the built-in
// functions
context = v8::Context::New(NULL, global);
// Enter the newly created execution environment.
v8::Context::Scope context_scope(context);
bool run_shell = (argc == 1);
for (int i = 1; i < argc; i++) {
const char* str = argv[i];
if (strcmp(str, "--shell") == 0) {
run_shell = true;
} else if (strcmp(str, "-f") == 0) {
// Ignore any -f flags for compatibility with the other stand-
// alone JavaScript engines.
continue;
} else if (strncmp(str, "--", 2) == 0) {
printf("Warning: unknown flag %s.\nTry --help for options\n", str);
} else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
// Execute argument given to -e option directly
v8::HandleScope handle_scope;
v8::Handle<v8::String> file_name = v8::String::New("unnamed");
v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
if (!ExecuteString(source, file_name, false, true))
return 1;
i++;
} else {
// Use all other arguments as names of files to load and run.
v8::HandleScope handle_scope;
v8::Handle<v8::String> file_name = v8::String::New(str);
v8::Handle<v8::String> source = ReadFile(str);
if (source.IsEmpty()) {
printf("Error reading '%s'\n", str);
return 1;
}
if (!ExecuteString(source, file_name, false, true))
return 1;
}
}
if (run_shell) RunShell(context);
return 0;
}
int main(int argc, char* argv[]) {
int result = RunMain(argc, argv);
v8::V8::Dispose();
return result;
}
// Extracts a C string from a V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
}
// The callback that is invoked by v8 whenever the JavaScript 'print'
// function is called. Prints its arguments on stdout separated by
// spaces and ending with a newline.
v8::Handle<v8::Value> Print(const v8::Arguments& args) {
bool first = true;
for (int i = 0; i < args.Length(); i++) {
v8::HandleScope handle_scope;
if (first) {
first = false;
} else {
printf(" ");
}
v8::String::Utf8Value str(args[i]);
const char* cstr = ToCString(str);
printf("%s", cstr);
}
printf("\n");
fflush(stdout);
return v8::Undefined();
}
// The callback that is invoked by v8 whenever the JavaScript 'read'
// function is called. This function loads the content of the file named in
// the argument into a JavaScript string.
v8::Handle<v8::Value> Read(const v8::Arguments& args) {
if (args.Length() != 1) {
return v8::ThrowException(v8::String::New("Bad parameters"));
}
v8::String::Utf8Value file(args[0]);
if (*file == NULL) {
return v8::ThrowException(v8::String::New("Error loading file"));
}
v8::Handle<v8::String> source = ReadFile(*file);
if (source.IsEmpty()) {
return v8::ThrowException(v8::String::New("Error loading file"));
}
return source;
}
// The callback that is invoked by v8 whenever the JavaScript 'load'
// function is called. Loads, compiles and executes its argument
// JavaScript file.
v8::Handle<v8::Value> Load(const v8::Arguments& args) {
for (int i = 0; i < args.Length(); i++) {
v8::HandleScope handle_scope;
v8::String::Utf8Value file(args[i]);
if (*file == NULL) {
return v8::ThrowException(v8::String::New("Error loading file"));
}
v8::Handle<v8::String> source = ReadFile(*file);
if (source.IsEmpty()) {
return v8::ThrowException(v8::String::New("Error loading file"));
}
if (!ExecuteString(source, v8::String::New(*file), false, false)) {
return v8::ThrowException(v8::String::New("Error executing file"));
}
}
return v8::Undefined();
}
// The callback that is invoked by v8 whenever the JavaScript 'quit'
// function is called. Quits.
v8::Handle<v8::Value> Quit(const v8::Arguments& args) {
// If not arguments are given args[0] will yield undefined which
// converts to the integer value 0.
int exit_code = args[0]->Int32Value();
exit(exit_code);
return v8::Undefined();
}
v8::Handle<v8::Value> Version(const v8::Arguments& args) {
return v8::String::New(v8::V8::GetVersion());
}
// Reads a file into a v8 string.
v8::Handle<v8::String> ReadFile(const char* name) {
FILE* file = fopen(name, "rb");
if (file == NULL) return v8::Handle<v8::String>();
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars = new char[size + 1];
chars[size] = '\0';
for (int i = 0; i < size;) {
int read = fread(&chars[i], 1, size - i, file);
i += read;
}
fclose(file);
v8::Handle<v8::String> result = v8::String::New(chars, size);
delete[] chars;
return result;
}
// The read-eval-execute loop of the shell.
void RunShell(v8::Handle<v8::Context> context) {
printf("V8 version %s\n", v8::V8::GetVersion());
static const int kBufferSize = 256;
while (true) {
char buffer[kBufferSize];
printf("> ");
char* str = fgets(buffer, kBufferSize, stdin);
if (str == NULL) break;
v8::HandleScope handle_scope;
ExecuteString(v8::String::New(str),
v8::String::New("(shell)"),
true,
true);
}
printf("\n");
}
bool iExecuteString(v8::Handle<v8::String> source,
v8::Handle<v8::Value> name,
v8::Handle<v8::Value> &result,
bool report_exceptions) {
v8::HandleScope handle_scope;
v8::TryCatch try_catch;
v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
if (script.IsEmpty()) {
// Print errors that happened during compilation.
if (report_exceptions)
ReportException(&try_catch);
return false;
} else {
result = script->Run();
if (result.IsEmpty()) {
// Print errors that happened during execution.
if (report_exceptions)
ReportException(&try_catch);
return false;
} else {
return true;
}
}
}
// Executes a string within the current v8 context.
bool ExecuteString(v8::Handle<v8::String> source,
v8::Handle<v8::Value> name,
bool print_result,
bool report_exceptions) {
v8::Handle<v8::Value> result;
context->Global()->Set(v8::String::New("__xy7z"), source);
bool ok = true;
ok = iExecuteString(v8::String::New("if ((function() { return this.translateCode })()) __xy7z = translateCode(__xy7z)"),
name, result, false);
if (ok)
ok = iExecuteString(v8::String::New("__xy7z = eval(__xy7z)"), name, result, report_exceptions);
else {
iExecuteString(v8::String::New("translateCode = undefined"), name, result, report_exceptions);
printf("error: translateCode failed and has been set to undefined in order to make the shell operational again\n");
}
if (ok && print_result && !result->IsUndefined())
iExecuteString(v8::String::New("print(__xy7z)"), name, result, report_exceptions);
return ok;
}
void ReportException(v8::TryCatch* try_catch) {
v8::HandleScope handle_scope;
v8::String::Utf8Value exception(try_catch->Exception());
const char* exception_string = ToCString(exception);
v8::Handle<v8::Message> message = try_catch->Message();
if (message.IsEmpty()) {
// V8 didn't provide any extra information about this error; just
// print the exception.
printf("%s\n", exception_string);
} else {
// Print (filename):(line number): (message).
v8::String::Utf8Value filename(message->GetScriptResourceName());
const char* filename_string = ToCString(filename);
int linenum = message->GetLineNumber();
printf("%s:%i: %s\n", filename_string, linenum, exception_string);
// Print line of source code.
v8::String::Utf8Value sourceline(message->GetSourceLine());
const char* sourceline_string = ToCString(sourceline);
printf("%s\n", sourceline_string);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn();
for (int i = 0; i < start; i++) {
printf(" ");
}
int end = message->GetEndColumn();
for (int i = start; i < end; i++) {
printf("^");
}
printf("\n");
}
}
Generated Vendored
+2
View File
@@ -0,0 +1,2 @@
./v8 Worlds2_Library.js ometa-rhino.js Worlds2.js arrays.wjs $@ --shell
Generated Vendored
+73
View File
@@ -0,0 +1,73 @@
function readFile(name) {
var r
new Ajax.Request("projects/" + name + ".txt", {
method: "get",
asynchronous: false,
onSuccess: function(transport) { r = transport.responseText },
onFailure: function(transport) { r = "" },
onException: function(x) { console.log(x) }
})
return r
}
function writeFile(name, text) {
var ok = true
new Ajax.Request("projects/" + name + ".txt", {
method: "put",
asynchronous: false,
postBody: text,
onFailure: function() { ok = false }
})
if (!ok)
throw "unable to write file '" + name + "'"
}
function projectIsDirty() { return $('workspaceForm').source.value != $('workspaceForm').source.origValue }
dirtyAreYouSureMessage = "The changes you have made to this project will be lost unless you press 'cancel' " +
"and save your work. Proceed?"
window.onbeforeunload = function() { if (projectIsDirty()) return dirtyAreYouSureMessage }
function loadProject() {
if (arguments.length > 0) {
if (arguments[0] == "" || "#" + arguments[0] == document.location.hash)
return
document.location.hash = hashChangedHandler.oldHash = "#" + arguments[0]
}
if (projectIsDirty() && !confirm(dirtyAreYouSureMessage))
return
var projName = document.location.hash.substring(1),
projData = readFile(projName)
$('workspaceForm').source.value = projData
$('workspaceForm').source.origValue = projData
$('title').innerHTML = "<font color=#000088>" + projName.replace(/_/g, " ") + "</font>" + titleRest
}
function saveProject() {
try {
var projName = document.location.hash.substring(1),
projData = $('workspaceForm').source.value
// the following is an ugly hack to fix a bug in prototype.js
if (projData == "")
projData = " "
writeFile(projName, projData)
$('workspaceForm').source.origValue = projData
alert("Project '" + projName + "' saved")
}
catch (e) {
alert("Error: " + e + "\n" +
"Please save your work locally (by cutting and pasting),\n" +
"and let Alex know about this problem.")
throw e
}
}
hashChangedHandler = function() {
if (document.location.hash == hashChangedHandler.oldHash)
return
hashChangedHandler.oldHash = document.location.hash
loadProject()
}
hashChangedHandler.oldHash = document.location.hash
hashChangedHandler.intervalId = setInterval(hashChangedHandler, 1000)
+223
View File
@@ -0,0 +1,223 @@
/*
Copyright (c) 2007, 2008 Alessandro Warth <[email protected]>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
// This code was adapted from Takashi Yamamiya's Javascript Workspace,
// which you can visit at http://metatoys.org/propella/js/workspace.js
// ---------------------------------------------------------------------------------------------------------------------------
// INSTRUCTIONS: a client page must (1) include something along these lines:
/*
<body onLoad="$('workspaceForm').onkeydown=onShortCutKey">
...
<form id=workspaceForm>
<b>Source</b><br>
<textarea cols=132 rows=24 name=source>...</textarea><br>
<input type=button value="print it (ctrl+p)" onClick="printIt()">
<input type=button value="do it (ctrl+d)" onClick="doIt()">
<br><br>
<b>Translation</b>
<br>
<div id=translation>
<textarea cols=132 rows=4 name=translation>
</textArea>
</div>
<b>Transcript</b>
<br>
<div id=transcript>
<textarea cols=132 rows=4 name=transcript></textArea>
</div>
</form>
...
</body>
*/
// and (2) define its own translateCode function
function translateCode(s) {
//throw { errorPos: 0 }
return s
}
// ---------------------------------------------------------------------------------------------------------------------------
/* event handler for short cut key */
function onShortCutKey(evt) {
evt = evt ? evt : window.event;
if (!evt)
return undefined;
if (!(evt.altKey || evt.ctrlKey || evt.metaKey))
return true;
var charCode = evt.charCode ? evt.charCode : evt.keyCode
try {
var handledIt = true
switch (charCode) {
case 68: doIt(); break
case 80: printIt(); break
case 83: saveIt(); break
default: handledIt = false; return true
}
}
finally {
if (handledIt) {
if (evt.preventDefault) {
evt.preventDefault()
evt.stopPropagation()
}
else {
evt.returnValue = false
evt.cancelBubble = true
}
}
}
return false
}
function printIt() {
var result = evalSelection()
if (!result)
return
var editor = result.source.editor,
end = result.source.end,
head = editor.value.substring(0, end),
tail = editor.value.substring(end),
oldScrollTop = editor.scrollTop
editor.value = head + result.result + tail;
editor.scrollTop = oldScrollTop
setCaretSelection(editor, end, head.length + result.result.length)
}
function doIt() {
var result = evalSelection()
if (result)
result.source.editor.focus()
}
function saveIt() { }
/* Get selection of textarea */
function getCaretSelection(field) {
field.focus();
var result = { start: 0, end: 0 };
// IE support based on http://groups.drupal.org/node/1210
if(typeof $('workspaceForm').source.selectionEnd == "undefined") {
var range = document.selection.createRange(),
rangeCopy = range.duplicate()
rangeCopy.moveToElementText(field)
rangeCopy.setEndPoint( 'EndToEnd', range )
result.start = rangeCopy.text.length - range.text.length
result.end = result.start + range.text.length
}
else {
result.start = field.selectionStart
result.end = field.selectionEnd
}
return result
}
/* Set selection of textarea */
function setCaretSelection(field, start, end) {
field.focus()
// IE
if(typeof $('workspaceForm').source.selectionEnd == "undefined") {
var range = field.createTextRange()
range.expand("textedit")
var dStart = start - (field.value.substring(0, start).split("\n").length - 1),
dEnd = end - field.value.length + field.value.substring(end + 1).split("\n").length - 1
range.moveStart("character", dStart)
range.moveEnd("character", dEnd)
range.select()
}
else {
field.selectionStart = start
field.selectionEnd = end
}
}
/* Get expression from textarea */
function getSource() {
var editor = $('workspaceForm').source,
selection = getCaretSelection(editor),
start = selection.start,
end = selection.end,
text = editor.value.substring(start, end)
if (start == end) {
var alltext = editor.value, index = 0
if (start > 0 && alltext.charAt(start) == "\n")
start--
while (start > 0 && alltext.charAt(start) != "\n")
start--
if (alltext.charAt(start) == "\n")
start++
while (end < alltext.length && alltext.charAt(end) != "\r" && alltext.charAt(end) != "\n")
end++
text = alltext.substring(start, end);
setCaretSelection(editor, start, end);
}
return {
editor: editor,
start: start,
end: end,
text: text
}
}
function evalSelection() {
var source = getSource()
try { $('workspaceForm').translation.value = translateCode(source.text) }
catch (e) {
if (e.errorPos != undefined) {
var errorPos = source.start + e.errorPos
errorMsg = " Parse error ->",
oldScrollTop = $('workspaceForm').source.scrollTop
$('workspaceForm').source.value = $('workspaceForm').source.value.substring(0, errorPos) + errorMsg +
$('workspaceForm').source.value.substring(errorPos, $('workspaceForm').source.value.length)
$('workspaceForm').source.scrollTop = oldScrollTop
setCaretSelection($('workspaceForm').source, errorPos, errorPos + errorMsg.length)
}
return undefined
}
try {
return {
source: source,
result: " " + eval($('workspaceForm').translation.value)
}
} catch (e) {
alert("Oops!\n\n" + e)
throw e
}
}
Transcript = {
show: function(x) {
$('workspaceForm').transcript.value = $('workspaceForm').transcript.value + x + "\n"
$('workspaceForm').transcript.scrollTop = $('workspaceForm').transcript.scrollHeight
},
clear: function() {
$('workspaceForm').transcript.value = ""
}
}