forked from veged/ometa-js-old
-
Notifications
You must be signed in to change notification settings - Fork 1
/
bs-ometa-compiler.txt
83 lines (82 loc) · 6.47 KB
/
bs-ometa-compiler.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
ometa BSOMetaParser <: Parser {
fromTo :x :y = seq(x) (~seq(y) char)* seq(y),
space = super(#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:rule args:as -> [#App, rule].concat(as),
hostExpr = foreign(BSJSParser, #expr):r foreign(BSJSTranslator, #trans, r),
atomicHostExpr = foreign(BSJSParser, #semAction):r foreign(BSJSTranslator, #trans, r),
curlyHostExpr = foreign(BSJSParser, #curlySemAction):r foreign(BSJSTranslator, #trans, r),
semAction = ("!" | "->") atomicHostExpr:x -> [#Act, x]
| curlyHostExpr:x -> [#Act, x],
semPred = "?" atomicHostExpr:x -> [#Pred, x],
expr = listOf(#expr4, '|'):xs -> [#Or].concat(xs),
expr4 = expr3*:xs -> [#And].concat(xs),
optIter :x = "*" -> [#Many, x]
| "+" -> [#Many1, x]
| empty -> x,
expr3 = expr2:x optIter(x):x ( ':' name:n -> { self.locals.push(n); [#Set, n, x] }
| empty -> x
)
| ":" name:n -> { self.locals.push(n); [#Set, n, [#App, #anything]] },
expr2 = "~" expr2:x -> [#Not, x]
| "&" expr1:x -> [#Lookahead, x]
| expr1,
expr1 = application | semAction | semPred
| ( keyword('undefined') | keyword('nil')
| keyword('true') | keyword('false') ):x -> [#App, #exactly, x]
| spaces (characters | sCharacters | string | number)
| "[" expr:x "]" -> [#Form, x]
| "(" expr:x ")" -> x,
ruleName = name
| spaces tsString,
rule = &(ruleName:n) !(self.locals = ['$elf=this'])
rulePart(n):x ("," rulePart(n))*:xs -> [#Rule, n, self.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 "}" foreign(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, which can be used to get an ML "feel".)
ometa BSOMetaTranslator {
trans [:t apply(t):ans] -> ans,
App 'super' anything+:args -> [self.sName, '._superApplyWithArgs($elf,', args.join(','), ')'].join(''),
App :rule anything+:args -> ['$elf._applyWithArgs("', rule, '",', args.join(','), ')'].join(''),
App :rule -> ['$elf._apply("', rule, '")'] .join(''),
Act :expr -> expr,
Pred :expr -> ['$elf._pred(', expr, ')'] .join(''),
Or transFn*:xs -> ['$elf._or(', xs.join(','), ')'] .join(''),
And notLast(#trans)*:xs trans:y -> { xs.push('return ' + y)
['(function(){', xs.join(';'), '})()'].join('') },
And -> '(function(){})',
Many trans:x -> ['$elf._many(function(){return ', x, '})'] .join(''),
Many1 trans:x -> ['$elf._many1(function(){return ', x, '})'] .join(''),
Set :n trans:v -> [n, '=', v].join(''),
Not trans:x -> ['$elf._not(function(){return ', x, '})'] .join(''),
Lookahead trans:x -> ['$elf._lookahead(function(){return ', x, '})'] .join(''),
Form trans:x -> ['$elf._form(function(){return ', x, '})'] .join(''),
Rule :name locals:ls trans:body -> ['"', name, '":function(){', ls, 'return ', body, '}'] .join(''),
Grammar :name :sName
!(self.sName = sName)
trans*:rules -> [name, '=', sName, '.delegated({', rules.join(','), '})'] .join(''),
locals = [string+:vs] -> ['var ', vs.join(','), ';'] .join('')
| [] -> '',
transFn = trans:x -> ['(function(){return ', x, '})'] .join('')
}