|
|
@ -0,0 +1,924 @@ |
|
|
|
// Utils |
|
|
|
|
|
|
|
println = (x) { |
|
|
|
if (!x) { |
|
|
|
print("\n"); |
|
|
|
} else { |
|
|
|
print(x, "\n", full: 1); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
Object.subtype(name) { self.new(__name__: name) } |
|
|
|
|
|
|
|
// Input stream |
|
|
|
|
|
|
|
Stream = Object.subtype(#Stream); |
|
|
|
|
|
|
|
newStream(string) { |
|
|
|
let self = Stream.new( |
|
|
|
content: string, |
|
|
|
position: 0, |
|
|
|
limit: len(string) |
|
|
|
); |
|
|
|
print("Created new stream object: { position: ", self.position, ", limit: ", self.limit, ", !atEnd(): ", !self.atEnd(), " }\n"); |
|
|
|
self; |
|
|
|
} |
|
|
|
|
|
|
|
Stream.atEnd() { self.position >= self.limit } |
|
|
|
Stream.peek() { !self.atEnd() && self.content[self.position] } |
|
|
|
Stream.inc() { !self.atEnd() && { self.position = self.position + 1; } } |
|
|
|
|
|
|
|
Stream.next() { |
|
|
|
!self.atEnd() && { |
|
|
|
let c = self.content[self.position]; |
|
|
|
self.position = self.position + 1; |
|
|
|
c; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Stream.setLastBegin = () { self.lastBegin = self.position; }; |
|
|
|
|
|
|
|
// Context |
|
|
|
|
|
|
|
Context = Object.subtype(#Context); |
|
|
|
Context.init() { self.variables = []; self; } |
|
|
|
Context.declareVariable(var) { |
|
|
|
let found = 0; |
|
|
|
for (key in self.variables.keys()) { |
|
|
|
if (key == var) { |
|
|
|
found = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
if (found == 0) { |
|
|
|
self.variables[var] = nil; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// ----- Grammar Constructs ----- |
|
|
|
|
|
|
|
// String Literal |
|
|
|
|
|
|
|
StringLiteral = Object.subtype(#StringLiteral); |
|
|
|
|
|
|
|
StringLiteral.match(stream, context, rules, actions) { |
|
|
|
|
|
|
|
let n = len(self.string); |
|
|
|
let i = 0; |
|
|
|
let success = 1; |
|
|
|
if (stream.atEnd()) { success = 0; } |
|
|
|
startPosition = stream.position; |
|
|
|
|
|
|
|
while(i < n && success == 1) { |
|
|
|
if (self.string[i] != stream.peek()) { |
|
|
|
success = 0; |
|
|
|
stream.position = startPosition; |
|
|
|
|
|
|
|
} else { |
|
|
|
i = i + 1; |
|
|
|
stream.inc(); |
|
|
|
} |
|
|
|
} |
|
|
|
success; |
|
|
|
} |
|
|
|
|
|
|
|
// Character Class |
|
|
|
|
|
|
|
CharacterClass = Object.subtype(#CharacterClass); |
|
|
|
|
|
|
|
CharacterClass.match(stream, context, rules, actions) { |
|
|
|
|
|
|
|
let classLength = len(self.value); |
|
|
|
let i = 0; |
|
|
|
let prevChar = nil; |
|
|
|
let success = 0; |
|
|
|
|
|
|
|
while (i < classLength && success == 0 && !stream.atEnd()) { |
|
|
|
|
|
|
|
// [a] case |
|
|
|
if (prevChar == nil) { |
|
|
|
// println("[a] case"); |
|
|
|
prevChar = self.value[i]; |
|
|
|
|
|
|
|
if (stream.peek() == self.value[i]) { |
|
|
|
success = 1; |
|
|
|
} |
|
|
|
|
|
|
|
} else if (prevChar != nil && self.value[i] == ord('-')) { |
|
|
|
|
|
|
|
// [a-z] case |
|
|
|
if (i+1 < classLength) { |
|
|
|
// println("[a-z] case"); |
|
|
|
rangeStart = prevChar; |
|
|
|
rangeEnd = self.value[i+1]; |
|
|
|
// print("Range Start: ", rangeStart, " | "); |
|
|
|
// print("Range End: ", rangeEnd, "\n"); |
|
|
|
if (stream.peek() >= rangeStart |
|
|
|
&& stream.peek() <= rangeEnd |
|
|
|
) { |
|
|
|
success = 1; |
|
|
|
} |
|
|
|
prevChar = nil; |
|
|
|
i = i + 1; |
|
|
|
|
|
|
|
// [a-] case |
|
|
|
} else { |
|
|
|
// println("[a-] case"); |
|
|
|
if (stream.peek() == ord('-')) { |
|
|
|
success = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// [ab] case |
|
|
|
} else if (prevChar != nil && self.value[i] != ord('-')) { |
|
|
|
// println("[ab] case"); |
|
|
|
prevChar = self.value[i]; |
|
|
|
if (stream.peek() == self.value[i]) { |
|
|
|
success = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
// print("prevChar: ", prevChar, "\n"); |
|
|
|
i = i + 1; |
|
|
|
} |
|
|
|
|
|
|
|
if (success == 1) { |
|
|
|
stream.inc(); |
|
|
|
} |
|
|
|
|
|
|
|
success; |
|
|
|
} |
|
|
|
|
|
|
|
// Dot |
|
|
|
|
|
|
|
Dot = Object.subtype(#Dot); |
|
|
|
|
|
|
|
Dot.match(stream, context, rules, actions) { |
|
|
|
if (!stream.atEnd()) { |
|
|
|
stream.inc(); |
|
|
|
1; |
|
|
|
} else { |
|
|
|
0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Begin |
|
|
|
|
|
|
|
Begin = Object.subtype(#Begin); |
|
|
|
|
|
|
|
Begin.match(stream, context, rules, actions) { |
|
|
|
stream.setLastBegin(); |
|
|
|
1; |
|
|
|
} |
|
|
|
|
|
|
|
// End |
|
|
|
|
|
|
|
End = Object.subtype(#End); |
|
|
|
|
|
|
|
End.match(stream, context, rules, actions) { |
|
|
|
context.variables.yytext = stream.content[stream.lastBegin..stream.position]; |
|
|
|
1; |
|
|
|
} |
|
|
|
|
|
|
|
// Optional (? postfix operator) |
|
|
|
|
|
|
|
Optional = Object.subtype(#Optional); |
|
|
|
|
|
|
|
Optional.match(stream, context, rules, actions) { |
|
|
|
let initialActionCount = actions.length(); |
|
|
|
let startingPosition = stream.position; |
|
|
|
let success = self.expression.match(stream, context, rules, actions); |
|
|
|
|
|
|
|
if (success == 0) { |
|
|
|
while (actions.length() > initialActionCount) { |
|
|
|
actions.pop(); |
|
|
|
} |
|
|
|
stream.position = startingPosition; |
|
|
|
} |
|
|
|
|
|
|
|
1; |
|
|
|
} |
|
|
|
|
|
|
|
// Star |
|
|
|
|
|
|
|
Star = Object.subtype(#Star); |
|
|
|
|
|
|
|
Star.match(stream, context, rules, actions) { |
|
|
|
while (self.expression.match(stream, context, rules, actions) == 1) {} |
|
|
|
1; |
|
|
|
} |
|
|
|
|
|
|
|
// Plus |
|
|
|
|
|
|
|
Plus = Object.subtype(#Plus); |
|
|
|
|
|
|
|
Plus.match(stream, context, rules, actions) { |
|
|
|
if (self.expression.match(stream, context, rules, actions) == 1) { |
|
|
|
while (self.expression.match(stream, context, rules, actions) == 1) {} |
|
|
|
1; |
|
|
|
} else { |
|
|
|
0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// And |
|
|
|
|
|
|
|
And = Object.subtype(#And); |
|
|
|
|
|
|
|
And.match(stream, context, rules, actions) { |
|
|
|
let position = stream.position; |
|
|
|
|
|
|
|
if (self.expression.match(stream, context, rules, actions) == 1) { |
|
|
|
stream.position = position; |
|
|
|
1; |
|
|
|
} else { |
|
|
|
0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Not |
|
|
|
|
|
|
|
Not = Object.subtype(#Not); |
|
|
|
|
|
|
|
Not.match(stream, context, rules, actions) { |
|
|
|
let position = stream.position; |
|
|
|
|
|
|
|
if (self.expression.match(stream, context, rules, actions) == 1) { |
|
|
|
stream.position = position; |
|
|
|
0; |
|
|
|
} else { |
|
|
|
1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Sequence |
|
|
|
|
|
|
|
Sequence = Object.subtype(#Sequence); |
|
|
|
|
|
|
|
Sequence.match(stream, context, rules, actions) { |
|
|
|
let i = 0; |
|
|
|
let match = 1; |
|
|
|
while (i < self.length() && match == 1) { |
|
|
|
match = self[i].match(stream, context, rules, actions); |
|
|
|
i = i + 1; |
|
|
|
} |
|
|
|
match; |
|
|
|
} |
|
|
|
|
|
|
|
// Alternation |
|
|
|
|
|
|
|
Alternation = Object.subtype(#Alternation); |
|
|
|
|
|
|
|
Alternation.match(stream, context, rules, actions) { |
|
|
|
let i = 0; |
|
|
|
let success = 0; |
|
|
|
while (i < self.length() && success == 0) { |
|
|
|
let initialActionCount = actions.length(); |
|
|
|
let startingPosition = stream.position; |
|
|
|
success = self[i].match(stream, context, rules, actions); |
|
|
|
|
|
|
|
if (success == 0) { |
|
|
|
while (actions.length() > initialActionCount) { |
|
|
|
actions.pop(); |
|
|
|
} |
|
|
|
stream.position = startingPosition; |
|
|
|
} |
|
|
|
|
|
|
|
i = i + 1; |
|
|
|
} |
|
|
|
success; |
|
|
|
} |
|
|
|
|
|
|
|
// Action |
|
|
|
|
|
|
|
Action = Object.subtype(#Action); |
|
|
|
|
|
|
|
Action.match(stream, context, rules, actions) { |
|
|
|
actions.push([action: self, context: context]); |
|
|
|
1; |
|
|
|
} |
|
|
|
|
|
|
|
Action.execute(context) { |
|
|
|
|
|
|
|
// Declare all variables that a value is set to in the context |
|
|
|
for (statement in self.parseTree.body) { |
|
|
|
if (statement.__name__ == "SetVar") { |
|
|
|
context.declareVariable(statement.name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Evaluate the parse tree and return to outer context if needed |
|
|
|
returnValue = eval(self.parseTree, env: context.variables); |
|
|
|
if (context.outerContext != nil) { |
|
|
|
context.outerContext.variables[context.returnValueName] = returnValue; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Assignment |
|
|
|
|
|
|
|
Assignment = Object.subtype(#Assignment); |
|
|
|
|
|
|
|
Assignment.match(stream, context, rules, actions) { |
|
|
|
context.declareVariable(self.name); |
|
|
|
innerContext = Context.new(outerContext: context, returnValueName: self.name).init(); |
|
|
|
self.rule.match(stream, innerContext, rules, actions); |
|
|
|
} |
|
|
|
|
|
|
|
// RuleCall |
|
|
|
|
|
|
|
RuleCall = Object.subtype(#RuleCall); |
|
|
|
|
|
|
|
RuleCall.match(stream, context, rules, actions) { |
|
|
|
rules[self.name].match(stream, context, rules, actions); |
|
|
|
} |
|
|
|
|
|
|
|
// ----- Grammar of Grammars ----- |
|
|
|
|
|
|
|
rules = []; |
|
|
|
|
|
|
|
|
|
|
|
// grammar = - g:mklist |
|
|
|
// ( d:definition { g.push(d); } |
|
|
|
// ) + end-of-file { print(g, full: Object.new()); } |
|
|
|
|
|
|
|
rules.grammar = Sequence.new() |
|
|
|
.push(RuleCall.new(name: #ws)) |
|
|
|
.push(Assignment.new(name: #g, rule: RuleCall.new(name: #mklist))) |
|
|
|
.push(Plus.new(expression: Sequence.new() |
|
|
|
.push(Assignment.new(name: #d, rule: RuleCall.new(name: #definition))) |
|
|
|
.push(Action.new(parseTree: `{ g[d.name] = d.expression; })) |
|
|
|
)) |
|
|
|
.push(RuleCall.new(name: #end_of_file)) |
|
|
|
.push(Action.new(parseTree: `{ print(g, full: Object.new()); })); |
|
|
|
|
|
|
|
|
|
|
|
Definition = Object.subtype(#Definition); |
|
|
|
|
|
|
|
// definition = i:identifier ASSIGN e:expression SEMI? { newDefinition(i, e); } |
|
|
|
|
|
|
|
rules.definition = Sequence.new() |
|
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #identifier))) |
|
|
|
.push(RuleCall.new(name: #assign)) |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #expression))) |
|
|
|
.push(Optional.new(expression: RuleCall.new(name: #semi))) |
|
|
|
.push(Action.new(parseTree: `{ Definition.new(name: i, expression: e); })); |
|
|
|
|
|
|
|
// expression = s1:sequence ( BAR s2:sequence { s1 = newAlternation(s1, s2); } |
|
|
|
// ) * { s1; } |
|
|
|
|
|
|
|
rules.expression = Sequence.new() |
|
|
|
.push(Assignment.new(name: #s1, rule: RuleCall.new(name: #sequence))) |
|
|
|
.push(Action.new(parseTree: `{ s1 = Alternation.new().push(s1); })) |
|
|
|
.push(Star.new(expression: Sequence.new() |
|
|
|
.push(RuleCall.new(name: #bar)) |
|
|
|
.push(Assignment.new(name: #s2, rule: RuleCall.new(name: #sequence))) |
|
|
|
.push(Action.new(parseTree: `{ s1.push(s2); })) |
|
|
|
)) |
|
|
|
.push(Action.new(parseTree: `{ s1; })); |
|
|
|
|
|
|
|
// sequence = p:prefix |
|
|
|
// ( q:prefix { p = newSequence(p, q); } |
|
|
|
// ) * { p; } |
|
|
|
|
|
|
|
rules.sequence = Sequence.new() |
|
|
|
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #prefix))) |
|
|
|
.push(Action.new(parseTree: `{ p = Sequence.new().push(p); })) |
|
|
|
.push(Star.new(expression: Sequence.new() |
|
|
|
.push(Assignment.new(name: #q, rule: RuleCall.new(name: #prefix))) |
|
|
|
.push(Action.new(parseTree: `{ p.push(q); })) |
|
|
|
)) |
|
|
|
.push(Action.new(parseTree: `{ p; })); |
|
|
|
|
|
|
|
// prefix = AND action |
|
|
|
// | |
|
|
|
// ( AND s:suffix { newAnd(s); } |
|
|
|
// | NOT s:suffix { newNot(s); } |
|
|
|
// | s:suffix { s; } |
|
|
|
// ) |
|
|
|
|
|
|
|
rules.prefix = Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #and)) |
|
|
|
.push(RuleCall.new(name: #action)) |
|
|
|
) |
|
|
|
.push(Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #and)) |
|
|
|
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #suffix))) |
|
|
|
.push(Action.new(parseTree: `{ And.new(expression: s); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #not)) |
|
|
|
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #suffix))) |
|
|
|
.push(Action.new(parseTree: `{ Not.new(expression: s); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #suffix))) |
|
|
|
.push(Action.new(parseTree: `{ s; })) |
|
|
|
) |
|
|
|
); |
|
|
|
|
|
|
|
// suffix = p:primary |
|
|
|
// ( QUERY { p = newOptional(p); } |
|
|
|
// | STAR { p = newStar(p); } |
|
|
|
// | PLUS { p = newPlus(p); } |
|
|
|
// ) ? { p; } |
|
|
|
|
|
|
|
rules.suffix = Sequence.new() |
|
|
|
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #primary))) |
|
|
|
.push(Optional.new(expression: Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #query)) |
|
|
|
.push(Action.new(parseTree: `{ p = Optional.new(expression: p); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #star)) |
|
|
|
.push(Action.new(parseTree: `{ p = Star.new(expression: p); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #plus)) |
|
|
|
.push(Action.new(parseTree: `{ p = Plus.new(expression: p); })) |
|
|
|
) |
|
|
|
)) |
|
|
|
.push(Action.new(parseTree: `{ p; })); |
|
|
|
|
|
|
|
// primary = i1:identifier COLON i2:ruleCallIdent !ASSIGN { newAssignment(i1, i2); } |
|
|
|
// | i:ruleCallIdent !ASSIGN { i; } |
|
|
|
// | LPAREN e:expression RPAREN { e; } |
|
|
|
// | l:literal { l; } |
|
|
|
// | c:class { c; } |
|
|
|
// | DOT { newDot(); } |
|
|
|
// | a:action { a; } |
|
|
|
// | BEGIN { newBegin(); } |
|
|
|
// | END { newEnd(); } |
|
|
|
|
|
|
|
rules.primary = Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #i1, rule: RuleCall.new(name: #identifier))) |
|
|
|
.push(RuleCall.new(name: #colon)) |
|
|
|
.push(Assignment.new(name: #i2, rule: RuleCall.new(name: #ruleCallIdent))) |
|
|
|
.push(Not.new(expression: RuleCall.new(name: #assign))) |
|
|
|
.push(Action.new(parseTree: `{ Assignment.new(name: i1, rule: i2); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #ruleCallIdent))) |
|
|
|
.push(Not.new(expression: RuleCall.new(name: #assign))) |
|
|
|
.push(Action.new(parseTree: `{ i; })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #lparen)) |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #expression))) |
|
|
|
.push(RuleCall.new(name: #rparen)) |
|
|
|
.push(Action.new(parseTree: `{ e; })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #l, rule: RuleCall.new(name: #literal))) |
|
|
|
.push(Action.new(parseTree: `{ l; })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #c, rule: RuleCall.new(name: #class))) |
|
|
|
.push(Action.new(parseTree: `{ c; })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #dot)) |
|
|
|
.push(Action.new(parseTree: `{ Dot.new(); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #action))) |
|
|
|
.push(Action.new(parseTree: `{ a; })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #begin)) |
|
|
|
.push(Action.new(parseTree: `{ Begin.new(); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #end)) |
|
|
|
.push(Action.new(parseTree: `{ End.new(); })) |
|
|
|
); |
|
|
|
|
|
|
|
// identifier = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { newStringEscaped(yytext); } |
|
|
|
|
|
|
|
rules.identifier = Sequence.new() |
|
|
|
.push(Begin.new()) |
|
|
|
.push(CharacterClass.new(value: "-a-zA-Z_")) |
|
|
|
.push(Star.new(expression: CharacterClass.new(value: "-a-zA-Z_0-9"))) |
|
|
|
.push(End.new()) |
|
|
|
.push(RuleCall.new(name: #ws)) |
|
|
|
.push(Action.new(parseTree: `{ yytext })); |
|
|
|
|
|
|
|
// ruleCallIdent = < [-a-zA-Z_][-a-zA-Z_0-9]* > - { newIdentifier(yytext); } |
|
|
|
|
|
|
|
rules.ruleCallIdent = Sequence.new() |
|
|
|
.push(Begin.new()) |
|
|
|
.push(CharacterClass.new(value: "-a-zA-Z_")) |
|
|
|
.push(Star.new(expression: CharacterClass.new(value: "-a-zA-Z_0-9"))) |
|
|
|
.push(End.new()) |
|
|
|
.push(RuleCall.new(name: #ws)) |
|
|
|
.push(Action.new(parseTree: `{ RuleCall.new(name: intern(yytext)); })); |
|
|
|
|
|
|
|
// literal = ['] < ( !['] char )* > ['] - { newStringEscaped(yytext); } |
|
|
|
// | ["] < ( !["] char )* > ["] - { newStringEscaped(yytext); } |
|
|
|
|
|
|
|
rules.literal = Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(CharacterClass.new(value: "\'")) |
|
|
|
.push(Begin.new()) |
|
|
|
.push(Star.new(expression: Sequence.new() |
|
|
|
.push(Not.new(expression: CharacterClass.new(value: "\'"))) |
|
|
|
.push(RuleCall.new(name: #char)) |
|
|
|
)) |
|
|
|
.push(End.new()) |
|
|
|
.push(CharacterClass.new(value: "\'")) |
|
|
|
.push(RuleCall.new(name: #ws)) |
|
|
|
.push(Action.new(parseTree: `{ StringLiteral.new(value: yytext); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(CharacterClass.new(value: '\"')) |
|
|
|
.push(Begin.new()) |
|
|
|
.push(Star.new(expression: Sequence.new() |
|
|
|
.push(Not.new(expression: CharacterClass.new(value: '\"'))) |
|
|
|
.push(RuleCall.new(name: #char)) |
|
|
|
)) |
|
|
|
.push(End.new()) |
|
|
|
.push(CharacterClass.new(value: '\"')) |
|
|
|
.push(RuleCall.new(name: #ws)) |
|
|
|
.push(Action.new(parseTree: `{ StringLiteral.new(value: yytext); })) |
|
|
|
); |
|
|
|
|
|
|
|
// class = '[' < ( !']' range )* > ']' - { newCharacterClass(yytext); } |
|
|
|
|
|
|
|
rules.class = Sequence.new() |
|
|
|
.push(StringLiteral.new(string: "[")) |
|
|
|
.push(Begin.new()) |
|
|
|
.push(Star.new(expression: Sequence.new() |
|
|
|
.push(Not.new(expression: StringLiteral.new(string: "]"))) |
|
|
|
.push(RuleCall.new(name: #range)) |
|
|
|
)) |
|
|
|
.push(End.new()) |
|
|
|
.push(StringLiteral.new(string: "]")) |
|
|
|
.push(RuleCall.new(name: #ws)) |
|
|
|
.push(Action.new(parseTree: `{ CharacterClass.new(value: yytext); })); |
|
|
|
|
|
|
|
// range = char '-' char | char |
|
|
|
|
|
|
|
rules.range = Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #char)) |
|
|
|
.push(StringLiteral.new(string: "-")) |
|
|
|
.push(RuleCall.new(name: #char)) |
|
|
|
) |
|
|
|
.push( |
|
|
|
RuleCall.new(name: #char) |
|
|
|
); |
|
|
|
|
|
|
|
// char = '\\' [abefnrtv'"\[\]\\] |
|
|
|
// | '\\' [0-3][0-7][0-7] |
|
|
|
// | '\\' [0-7][0-7]? |
|
|
|
// | !'\\' . |
|
|
|
|
|
|
|
rules.char = Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(StringLiteral.new(string: "\\")) |
|
|
|
.push(Alternation.new() |
|
|
|
.push(CharacterClass.new(value: "abefnrtv\'[]\\")) |
|
|
|
.push(CharacterClass.new(value: '\"')) // I hate this |
|
|
|
) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(StringLiteral.new(string: "\\")) |
|
|
|
.push(CharacterClass.new(value: "0-3")) |
|
|
|
.push(CharacterClass.new(value: "0-7")) |
|
|
|
.push(CharacterClass.new(value: "0-7")) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(StringLiteral.new(string: "\\")) |
|
|
|
.push(CharacterClass.new(value: "0-7")) |
|
|
|
.push(Optional.new(expression: CharacterClass.new(value: "0-7"))) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Not.new(expression: StringLiteral.new(string: "\\"))) |
|
|
|
.push(Dot.new()) |
|
|
|
); |
|
|
|
|
|
|
|
// action = m:metaBlock - { newAction(m); } |
|
|
|
|
|
|
|
rules.action = Sequence.new() |
|
|
|
.push(Assignment.new(name: #m, rule: RuleCall.new(name: #metaBlock))) |
|
|
|
.push(RuleCall.new(name: #ws)) |
|
|
|
.push(Action.new(parseTree: `{ Action.new(parseTree: m); })); |
|
|
|
|
|
|
|
// metaStatement = b:metaBlock { newBlock(b); } |
|
|
|
// | e:metaExpression SEMI { e; } |
|
|
|
|
|
|
|
rules.metaStatement = Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #b, rule: RuleCall.new(name: #metaBlock))) |
|
|
|
.push(Action.new(parseTree: `{ Block.new(b); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression))) |
|
|
|
.push(RuleCall.new(name: #semi)) |
|
|
|
.push(Action.new(parseTree: `{ e; })) |
|
|
|
); |
|
|
|
|
|
|
|
// metaExpression = p:metaPrimary |
|
|
|
// ( DOT i:metaId ASSIGN e:metaExpression # { $$ = newSetProp(p, i, e) } |
|
|
|
// | LBRAK i:metaExpression RBRAK ASSIGN e:metaExpression # { $$ = newSetArray(p, i, e) } |
|
|
|
// ) |
|
|
|
// | i:metaId ASSIGN e:metaExpression { newSetVar(i, e); } |
|
|
|
// | pf:metaPostfix { pf; } |
|
|
|
|
|
|
|
rules.metaExpression = Alternation.new(id: 1234) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #metaPrimary))) |
|
|
|
.push(Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #dot)) |
|
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId))) |
|
|
|
.push(RuleCall.new(name: #assign)) |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression))) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #lbrak)) |
|
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaExpression))) |
|
|
|
.push(RuleCall.new(name: #rbrak)) |
|
|
|
.push(RuleCall.new(name: #assign)) |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression))) |
|
|
|
.push(Action.new(parseTree: `{ SetArray.new(object: p, index: i, value: e); })) |
|
|
|
) |
|
|
|
) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId))) |
|
|
|
.push(RuleCall.new(name: #assign)) |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression))) |
|
|
|
.push(Action.new(parseTree: `{ SetVar.new(name: i, expr: e); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #pf, rule: RuleCall.new(name: #metaPostfix))) |
|
|
|
.push(Action.new(parseTree: `{ pf; })) |
|
|
|
); |
|
|
|
|
|
|
|
// metaPostfix = p:metaPrimary |
|
|
|
// ( DOT i:id a:args !ASSIGN !LBRACE { p = newInvoke(p, i, a) } |
|
|
|
// | DOT i:id !ASSIGN { p = newGetProp(p, i) } |
|
|
|
// | a:args !ASSIGN !LBRACE { p = newCall(p, a); } |
|
|
|
// ) * { p; } |
|
|
|
|
|
|
|
rules.metaPostfix = Sequence.new() |
|
|
|
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #metaPrimary))) |
|
|
|
.push(Star.new(expression: Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #dot)) |
|
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId))) |
|
|
|
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #args))) |
|
|
|
.push(Not.new(expression: RuleCall.new(name: #assign))) |
|
|
|
.push(Not.new(expression: RuleCall.new(name: #lbrace))) |
|
|
|
.push(Action.new(parseTree: `{ p = Invoke.new(self: p, method: i, arguments: a); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(RuleCall.new(name: #dot)) |
|
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId))) |
|
|
|
.push(Not.new(expression: RuleCall.new(name: #assign))) |
|
|
|
.push(Action.new(parseTree: `{ p = GetProp.new(object: p, key: i); })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #args))) |
|
|
|
.push(Not.new(expression: RuleCall.new(name: #assign))) |
|
|
|
.push(Not.new(expression: RuleCall.new(name: #lbrace))) |
|
|
|
.push(Action.new(parseTree: `{ p = Call.new(function: p, arguments: a); })) |
|
|
|
// TODO: Voir si c'est toujours bon avec le newApply() |
|
|
|
) |
|
|
|
)) |
|
|
|
.push(Action.new(parseTree: `{ p; })); |
|
|
|
|
|
|
|
// args = LPAREN a:mklist |
|
|
|
// ( |
|
|
|
|
|
|
|
// ( k:metaId COLON e:metaExpression { Object_put(a, k, e); } |
|
|
|
// | e:metaExpression { Object_push(a, e); } |
|
|
|
// ) |
|
|
|
|
|
|
|
// ( COMMA |
|
|
|
// ( k:metaId COLON e:metaExpression { Object_put(a, k, e); } |
|
|
|
// | e:metaExpression { Object_push(a, e); } |
|
|
|
// ) |
|
|
|
// ) * |
|
|
|
|
|
|
|
// ) ? RPAREN { a; } |
|
|
|
|
|
|
|
rules.args = Sequence.new() |
|
|
|
.push(RuleCall.new(name: #lparen)) |
|
|
|
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #mklist))) |
|
|
|
.push(Optional.new(expression: Sequence.new() |
|
|
|
.push(Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #k, rule: RuleCall.new(name: #metaId))) |
|
|
|
.push(RuleCall.new(name: #colon)) |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression))) |
|
|
|
.push(Action.new(parseTree: `{ a[k] = e; })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression))) |
|
|
|
.push(Action.new(parseTree: `{ a.push(e); })) |
|
|
|
) |
|
|
|
) |
|
|
|
.push(Star.new(expression: Sequence.new() |
|
|
|
.push(RuleCall.new(name: #comma)) |
|
|
|
.push(Alternation.new() |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #k, rule: RuleCall.new(name: #metaId))) |
|
|
|
.push(RuleCall.new(name: #colon)) |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression))) |
|
|
|
.push(Action.new(parseTree: `{ a[k] = e; })) |
|
|
|
) |
|
|
|
.push(Sequence.new() |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression))) |
|
|
|
.push(Action.new(parseTree: `{ a.push(e); })) |
|
|
|
) |
|
|
|
) |
|
|
|
)) |
|
|
|
)) |
|
|
|
.push(RuleCall.new(name: #rparen)) |
|
|
|
.push(Action.new(parseTree: `{ a; })); |
|
|
|
|
|
|
|
// mklist = { new(pObject); } |
|
|
|
|
|
|
|
// metaPrimary = nil | metaVar | metaSubExpr |
|
|
|
|
|
|
|
// metaSubExpr = LPAREN e:metaExpression RPAREN { e; } |
|
|
|
|
|
|
|
rules.mklist = Action.new(parseTree: `{ Object.new(); }); |
|
|
|
|
|
|
|
rules.metaPrimary = Alternation.new() |
|
|
|
.push(RuleCall.new(name: #nil)) |
|
|
|
.push(RuleCall.new(name: #metaVar)) |
|
|
|
.push(RuleCall.new(name: #metaSubExpr)); |
|
|
|
|
|
|
|
rules.metaSubExpr = Sequence.new() |
|
|
|
.push(RuleCall.new(name: #lparen)) |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression))) |
|
|
|
.push(RuleCall.new(name: #rparen)) |
|
|
|
.push(Action.new(parseTree = `{ e; })); |
|
|
|
|
|
|
|
// metaBlock = LBRACE b:mklist |
|
|
|
// ( e:metaStatement { b.push(e); } |
|
|
|
// ) * RBRACE { b; } |
|
|
|
|
|
|
|
rules.metaBlock = Sequence.new() |
|
|
|
.push(RuleCall.new(name: #lbrace)) |
|
|
|
.push(Assignment.new(name: #b, rule: RuleCall.new(name: #mklist))) |
|
|
|
.push( |
|
|
|
Star.new( |
|
|
|
expression: Sequence.new() |
|
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaStatement))) |
|
|
|
.push(Action.new(parseTree: `{ b.push(e); })) |
|
|
|
) |
|
|
|
) |
|
|
|
.push(RuleCall.new(name: #rbrace)) |
|
|
|
.push(Action.new(parseTree: `{ b; })); |
|
|
|
|
|
|
|
// metaVar = i:metaId { newGetVar(i); } |
|
|
|
// metaId = < LETTER ALNUM* > - { intern(yytext); } |
|
|
|
|
|
|
|
rules.metaVar = Sequence.new() |
|
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId))) |
|
|
|
.push(Action.new(parseTree: `{ GetVar.new(name: i); })); |
|
|
|
|
|
|
|
rules.metaId = Sequence.new() |
|
|
|
.push(Begin.new()) |
|
|
|
.push(RuleCall.new(name: #letter)) |
|
|
|
.push(Star.new(expression: RuleCall.new(name: #alnum))) |
|
|
|
.push(End.new()) |
|
|
|
.push(RuleCall.new(name: #ws)) |
|
|
|
.push(Action.new(parseTree: `{ intern(yytext); })); |
|
|
|
|
|
|
|
// Literal Terminators |
|
|
|
|
|
|
|
// BAR = '|' - |
|
|
|
// NOT = '!' - |
|
|
|
// QUERY = '?' - |
|
|
|
// BEGIN = '<' - |
|
|
|
// END = '>' - |
|
|
|
// TILDE = '~' - |
|
|
|
// RPERCENT = '%}' - |
|
|
|
|
|
|
|
rules.bar = Sequence.new().push(StringLiteral.new(string: "|")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.not = Sequence.new().push(StringLiteral.new(string: "!")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.query = Sequence.new().push(StringLiteral.new(string: "?")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.begin = Sequence.new().push(StringLiteral.new(string: "<")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.end = Sequence.new().push(StringLiteral.new(string: ">")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.tilde = Sequence.new().push(StringLiteral.new(string: "~")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.rpercent = Sequence.new().push(StringLiteral.new(string: "%}")).push(RuleCall.new(name: #ws)); |
|
|
|
|
|
|
|
// DIGIT = [0-9] |
|
|
|
// LETTER = [A-Za-z_] |
|
|
|
// ALNUM = LETTER | DIGIT |
|
|
|
// NIL = "nil" !ALNUM - |
|
|
|
|
|
|
|
rules.digit = CharacterClass.new(value: "0-9"); |
|
|
|
rules.letter = CharacterClass.new(value: "A-Za-z_"); |
|
|
|
rules.alnum = Alternation.new() |
|
|
|
.push(RuleCall.new(name: #letter)) |
|
|
|
.push(RuleCall.new(name: #digit)); |
|
|
|
rules.nil = Sequence.new() |
|
|
|
.push(StringLiteral.new(string: "nil")) |
|
|
|
.push(Not.new(expression: RuleCall.new(name: #alnum))) |
|
|
|
.push(RuleCall.new(name: #ws)); |
|
|
|
|
|
|
|
// SEMI = ";" - |
|
|
|
// COMMA = "," - |
|
|
|
// COLON = ":" - |
|
|
|
// LPAREN = "(" - |
|
|
|
// RPAREN = ")" - |
|
|
|
// LBRAK = "[" - |
|
|
|
// RBRAK = "]" - |
|
|
|
// LBRACE = "{" - |
|
|
|
// RBRACE = "}" - |
|
|
|
// ASSIGN = "=" ![=] - |
|
|
|
// AND = "&" ![&=] - |
|
|
|
// PLUS = "+" ![+=] - |
|
|
|
// STAR = "*" ![=] - |
|
|
|
// DOT = "." ![.] - |
|
|
|
|
|
|
|
rules.semi = Sequence.new().push(StringLiteral.new(string: ";")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.comma = Sequence.new().push(StringLiteral.new(string: ",")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.colon = Sequence.new().push(StringLiteral.new(string: ":")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.lparen = Sequence.new().push(StringLiteral.new(string: "(")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.rparen = Sequence.new().push(StringLiteral.new(string: ")")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.lbrak = Sequence.new().push(StringLiteral.new(string: "[")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.rbrak = Sequence.new().push(StringLiteral.new(string: "]")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.lbrace = Sequence.new().push(StringLiteral.new(string: "{")).push(RuleCall.new(name: #ws)); |
|
|
|
rules.rbrace = Sequence.new().push(StringLiteral.new(string: "}")).push(RuleCall.new(name: #ws)); |
|
|
|
|
|
|
|
rules.assign = Sequence.new() |
|
|
|
.push(StringLiteral.new(string: "=")) |
|
|
|
.push(Not.new(expression: CharacterClass.new(value: "="))) |
|
|
|
.push(RuleCall.new(name: #ws)); |
|
|
|
rules.and = Sequence.new() |
|
|
|
.push(StringLiteral.new(string: "&")) |
|
|
|
.push(Not.new(expression: CharacterClass.new(value: "&="))) |
|
|
|
.push(RuleCall.new(name: #ws)); |
|
|
|
rules.plus = Sequence.new() |
|
|
|
.push(StringLiteral.new(string: "+")) |
|
|
|
.push(Not.new(expression: CharacterClass.new(value: "+="))) |
|
|
|
.push(RuleCall.new(name: #ws)); |
|
|
|
rules.star = Sequence.new() |
|
|
|
.push(StringLiteral.new(string: "*")) |
|
|
|
.push(Not.new(expression: CharacterClass.new(value: "="))) |
|
|
|
.push(RuleCall.new(name: #ws)); |
|
|
|
rules.dot = Sequence.new() |
|
|
|
.push(StringLiteral.new(string: ".")) |
|
|
|
.push(Not.new(expression: CharacterClass.new(value: "."))) |
|
|
|
.push(RuleCall.new(name: #ws)); |
|
|
|
|
|
|
|
// Whitespace |
|
|
|
|
|
|
|
// - = ( space | comment )* |
|
|
|
// space = ' ' | '\t' | end-of-line |
|
|
|
// comment = '#' ( !end-of-line . )* end-of-line |
|
|
|
// end-of-line = '\r\n' | '\n' | '\r' |
|
|
|
// end-of-file = !. |
|
|
|
|
|
|
|
rules.end_of_file = Not.new(expression: Dot.new()); |
|
|
|
|
|
|
|
rules.end_of_line = Alternation.new() |
|
|
|
.push(StringLiteral.new(string: "\r\n")) |
|
|
|
.push(StringLiteral.new(string: "\n")) |
|
|
|
.push(StringLiteral.new(string: "\r")); |
|
|
|
|
|
|
|
rules.comment = Sequence.new() |
|
|
|
.push(StringLiteral.new(string: "#")) |
|
|
|
.push(Star.new(expression: |
|
|
|
Sequence.new() |
|
|
|
.push(Not.new(expression: RuleCall.new(name: #end_of_line))) |
|
|
|
.push(Dot.new()) |
|
|
|
)) |
|
|
|
.push(RuleCall.new(name: #end_of_line)); |
|
|
|
|
|
|
|
rules.space = Alternation.new() |
|
|
|
.push(StringLiteral.new(string: " ")) |
|
|
|
.push(StringLiteral.new(string: "\t")) |
|
|
|
.push(RuleCall.new(name: #end_of_line)); |
|
|
|
|
|
|
|
rules.ws = Star.new(expression: Alternation.new() |
|
|
|
.push(RuleCall.new(name: #space)) |
|
|
|
.push(RuleCall.new(name: #comment)) |
|
|
|
); |
|
|
|
|
|
|
|
// ----- Main ----- |
|
|
|
|
|
|
|
stream = newStream(readfile("rawgrammar.leg")); |
|
|
|
//stream = newStream("rule1 = rule2* | b:rule3 {a = b;} rule4 = 'hello' "); |
|
|
|
context = Context.new(outerContext: nil).init(); |
|
|
|
actions = []; |
|
|
|
|
|
|
|
print("\nMatching : ", rules.grammar.match(stream, context, rules, actions), "\n"); |
|
|
|
|
|
|
|
// Execute all actions after all matching |
|
|
|
|
|
|
|
for (actionAndContext in actions) { |
|
|
|
//println(actionAndContext.action.parseTree); |
|
|
|
actionAndContext.action.execute(actionAndContext.context); |
|
|
|
} |
|
|
|
println(); |
|
|
|
|