Archived
lastest
This commit is contained in:
1 parent
620fc5bda1
commit
bd3ef9f279
779 files changed
+202868
No files matched your search
+1
@@ -0,0 +1 @@
|
||||
*.swp
|
||||
+48
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,9 @@
|
||||
ometa BSOMetaJSParser <: BSJSParser {
|
||||
srcElem = spaces BSOMetaParser.grammar:r sc -> r
|
||||
| ^srcElem
|
||||
}
|
||||
|
||||
ometa BSOMetaJSTranslator <: BSJSTranslator {
|
||||
Grammar = BSOMetaTranslator.Grammar
|
||||
}
|
||||
|
||||
+37
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,5 @@
|
||||
ometa ProjectListParser <: BSJSParser {
|
||||
proj = spaces iName,
|
||||
projs = proj:x (spaces ',' proj)*:xs -> [x].concat(xs)
|
||||
}
|
||||
|
||||
+166
@@ -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
@@ -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;
|
||||
+183
@@ -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
@@ -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
@@ -0,0 +1,4 @@
|
||||
ometa T <: Parser {
|
||||
t = '\n' -> '\n',
|
||||
selectors_group = (t | anything)*
|
||||
}
|
||||
+35
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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()
|
||||
}
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
./v8 ometa-rhino.js $@ --shell
|
||||
|
||||
+10
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large.
Load diff
+10
@@ -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
@@ -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
@@ -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");
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
./v8 Worlds2_Library.js ometa-rhino.js Worlds2.js arrays.wjs $@ --shell
|
||||
|
||||
+73
@@ -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
@@ -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 = ""
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user