// ----- Utils -----
|
|
|
|
true = (1 == 1);
|
|
false = (1 == 0);
|
|
|
|
Object.contains(item) {
|
|
for (i in self.length()) {
|
|
if (self[i] == item) {
|
|
return 1;
|
|
}
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
with(namespace) {
|
|
|
|
//print("--- With ", namespace, " ---\n\n");
|
|
|
|
if (__namespaces__.length() == 0) {
|
|
__namespaces__.push([]);
|
|
}
|
|
|
|
if (!__namespaces__.keys().contains(namespace)) {
|
|
let newNamespace = [__nsname__: namespace];
|
|
__namespaces__[namespace] = newNamespace;
|
|
__namespaces__[0][namespace] = newNamespace;
|
|
} else {
|
|
__namespaces__[0][namespace] = __namespaces__[namespace];
|
|
}
|
|
|
|
__namespaces__.push(__namespaces__[namespace]);
|
|
}
|
|
|
|
//without(); // latest
|
|
//without(#peg); // remove a plate from the middle the pile without smashing everything
|
|
//without(all: 1); // ALL
|
|
|
|
without(namespace, all: nil) {
|
|
|
|
// Remove all
|
|
if (all != nil) {
|
|
for (i in (__namespaces__.length() - 1)) {
|
|
let removedNamespace = __namespaces__.pop().__nsname__;
|
|
//print("--- Without ", removedNamespace, " ---\n\n");
|
|
__namespaces__[0][removedNamespace] = nil;
|
|
}
|
|
__namespaces__.pop();
|
|
return;
|
|
}
|
|
|
|
// Remove last
|
|
if (namespace == nil) {
|
|
let removedNamespace = __namespaces__.pop().__nsname__;
|
|
//print("--- Without ", removedNamespace, " ---\n\n");
|
|
__namespaces__[0][removedNamespace] = nil;
|
|
if (__namespaces__.length() == 1) {
|
|
__namespaces__.pop();
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Remove a given namespace
|
|
// Find its index
|
|
let namespaceIndex = nil;
|
|
for (i from (__namespaces__.length() - 1) to 1) {
|
|
if (__namespaces__[i].__nsname__ == namespace) {
|
|
namespaceIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If it's on top of the stack, just pop
|
|
if (namespaceIndex == __namespaces__.length() - 1) {
|
|
__namespaces__.pop();
|
|
//print("--- Without ", namespace, " ---\n\n");
|
|
__namespaces__[0][namespace] = nil;
|
|
if (__namespaces__.length() == 1) {
|
|
__namespaces__.pop();
|
|
}
|
|
return;
|
|
}
|
|
|
|
// If it's not on top, offset all the namespaces on top of it by one, and then pop
|
|
for (i from namespaceIndex to (__namespaces__.length() - 2)) {
|
|
__namespaces__[i] = __namespaces__[i + 1];
|
|
}
|
|
__namespaces__.pop();
|
|
//print("--- Without ", namespace, " ---\n\n");
|
|
__namespaces__[0][namespace] = nil;
|
|
if (__namespaces__.length() == 1) {
|
|
__namespaces__.pop();
|
|
}
|
|
}
|
|
|
|
get(__identifier) {
|
|
eval(GetVar.new(name: __identifier));
|
|
}
|
|
|
|
set(__identifier, __value) {
|
|
eval(SetVar.new(name: __identifier, value: __value));
|
|
}
|
|
|
|
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)
|
|
// );
|
|
// 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.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, actions) {
|
|
if (stream.match(self.string)) {
|
|
stream.position += len(self.string);
|
|
true;
|
|
} else {
|
|
false;
|
|
}
|
|
}
|
|
|
|
//StringLiteral.match(stream, context, actions) {
|
|
//
|
|
// let n = len(self.string);
|
|
// let i = 0;
|
|
// let success = 1;
|
|
// if (stream.atEnd()) { success = 0; }
|
|
// let 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, 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] == '-') {
|
|
|
|
// [a-z] case
|
|
if (i+1 < classLength) {
|
|
// println("[a-z] case");
|
|
let rangeStart = prevChar;
|
|
let 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() == '-') {
|
|
success = 1;
|
|
}
|
|
}
|
|
|
|
// [ab] case
|
|
} else if (prevChar != nil && self.value[i] != '-') {
|
|
// 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 == 1;
|
|
}
|
|
|
|
// Dot
|
|
|
|
Dot = Object.subtype(#Dot);
|
|
|
|
Dot.match(stream, context, actions) {
|
|
if (!stream.atEnd()) {
|
|
stream.inc();
|
|
true;
|
|
} else {
|
|
false;
|
|
}
|
|
}
|
|
|
|
// Begin
|
|
|
|
Begin = Object.subtype(#Begin);
|
|
|
|
Begin.match(stream, context, actions) {
|
|
stream.setLastBegin();
|
|
true;
|
|
}
|
|
|
|
// End
|
|
|
|
End = Object.subtype(#End);
|
|
|
|
End.match(stream, context, actions) {
|
|
context.variables.yytext = stream.content[stream.lastBegin..stream.position].unescaped();
|
|
true;
|
|
}
|
|
|
|
// Optional (? postfix operator)
|
|
|
|
Optional = Object.subtype(#Optional);
|
|
|
|
Optional.match(stream, context, actions) {
|
|
self.expression.match(stream, context, actions);
|
|
true;
|
|
}
|
|
|
|
// Star
|
|
|
|
Star = Object.subtype(#Star);
|
|
|
|
Star.match(stream, context, actions) {
|
|
while (self.expression.match(stream, context, actions)) {}
|
|
true;
|
|
}
|
|
|
|
// Plus
|
|
|
|
Plus = Object.subtype(#Plus);
|
|
|
|
Plus.match(stream, context, actions) {
|
|
if (self.expression.match(stream, context, actions) == true) {
|
|
while (self.expression.match(stream, context, actions) == true) {}
|
|
true;
|
|
} else {
|
|
false;
|
|
}
|
|
}
|
|
|
|
// And
|
|
|
|
And = Object.subtype(#And);
|
|
|
|
And.match(stream, context, actions) {
|
|
let position = stream.position;
|
|
|
|
if (self.expression.match(stream, context, actions) == true) {
|
|
stream.position = position;
|
|
true;
|
|
} else {
|
|
false;
|
|
}
|
|
}
|
|
|
|
// Not
|
|
|
|
Not = Object.subtype(#Not);
|
|
|
|
Not.match(stream, context, actions) {
|
|
let position = stream.position;
|
|
|
|
if (self.expression.match(stream, context, actions) == true) {
|
|
stream.position = position;
|
|
false;
|
|
} else {
|
|
true;
|
|
}
|
|
}
|
|
|
|
// Sequence
|
|
|
|
Sequence = Object.subtype(#Sequence);
|
|
|
|
Sequence._match(stream, context, actions, index) {
|
|
if (index == self.length() - 1) {
|
|
return self[index].match(stream, context, actions);
|
|
}
|
|
self[index].match(stream, context, actions) && self._match(stream, context, actions, index + 1);
|
|
}
|
|
|
|
Sequence.match(stream, context, actions) {
|
|
let initialActionCount = actions.length();
|
|
let startingPosition = stream.position;
|
|
|
|
success = self._match(stream, context, actions, 0);
|
|
|
|
if (success == false) {
|
|
while (actions.length() > initialActionCount) {
|
|
actions.pop();
|
|
}
|
|
stream.position = startingPosition;
|
|
}
|
|
|
|
success;
|
|
}
|
|
|
|
// Alternation
|
|
|
|
Alternation = Object.subtype(#Alternation);
|
|
|
|
Alternation._match(stream, context, actions, index) {
|
|
if (index == self.length() - 1) {
|
|
return self[index].match(stream, context, actions);
|
|
}
|
|
self[index].match(stream, context, actions) || self._match(stream, context, actions, index + 1);
|
|
}
|
|
|
|
Alternation.match(stream, context, actions) {
|
|
return self._match(stream, context, actions, 0);
|
|
}
|
|
|
|
// Action
|
|
|
|
Action = Object.subtype(#Action);
|
|
|
|
Action.match(stream, context, actions) {
|
|
actions.push([action: self, context: context]);
|
|
true;
|
|
}
|
|
|
|
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
|
|
let returnValue = eval(self.parseTree, env: context.variables);
|
|
if (context.outerContext != nil) {
|
|
context.outerContext.variables[context.returnValueName] = returnValue;
|
|
}
|
|
|
|
returnValue;
|
|
}
|
|
|
|
// Parse-time Action
|
|
|
|
ParseTimeAction = Object.subtype(#ParseTimeAction);
|
|
|
|
ParseTimeAction.match(stream, context, actions) {
|
|
if(self.action.execute(context)) {
|
|
true;
|
|
} else {
|
|
false;
|
|
}
|
|
}
|
|
|
|
// Assignment
|
|
|
|
Assignment = Object.subtype(#Assignment);
|
|
|
|
Assignment.match(stream, context, actions) {
|
|
context.declareVariable(self.name);
|
|
let innerContext = Context.new(outerContext: context, returnValueName: self.name).init();
|
|
self.rule.match(stream, innerContext, actions);
|
|
}
|
|
|
|
// RuleCall
|
|
|
|
RuleCall = Object.subtype(#RuleCall);
|
|
|
|
RuleCall.match(stream, context, actions) {
|
|
//if (rules[self.name] == nil) { print("Trying to call undefined rule: ", self.name, "\n"); exit(); }
|
|
let res = get(self.name).match(stream, context, actions);
|
|
//print("matching rule ", self.name, ": ", res, "\n");
|
|
res;
|
|
}
|
|
|
|
// NamespacedRuleCall
|
|
|
|
NamespacedRuleCall = Object.subtype(#NamespacedRuleCall);
|
|
|
|
NamespacedRuleCall.match(stream, context, actions) {
|
|
with(self.namespace);
|
|
let res = get(self.name).match(stream, context, actions);
|
|
without();
|
|
res;
|
|
}
|
|
|
|
Definition = Object.subtype(#Definition);
|
|
|
|
// ----- Grammar of Meta Language (Minimal) -----
|
|
|
|
with(#HardCodedMeta);
|
|
|
|
metaStatement = Alternation.new()
|
|
.push(Sequence.new()
|
|
.push(Assignment.new(name: #b, rule: RuleCall.new(name: #block)))
|
|
.push(Action.new(parseTree: `{ b; }))
|
|
)
|
|
.push(Sequence.new()
|
|
.push(Assignment.new(name: #e, rule: RuleCall.new(name: #metaExpression)))
|
|
.push(Alternation.new()
|
|
.push(RuleCall.new(name: #semi))
|
|
.push(And.new(expression: RuleCall.new(name: #rbrace)))
|
|
)
|
|
.push(Action.new(parseTree: `{ e; }))
|
|
);
|
|
|
|
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, value: e); }))
|
|
)
|
|
.push(Sequence.new()
|
|
.push(Assignment.new(name: #pf, rule: RuleCall.new(name: #metaPostfix)))
|
|
.push(Action.new(parseTree: `{ pf; }))
|
|
);
|
|
|
|
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 = 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 = Action.new(parseTree: `{ Object.new(); });
|
|
|
|
metaPrimary = Alternation.new()
|
|
.push(RuleCall.new(name: #nil))
|
|
.push(RuleCall.new(name: #number))
|
|
.push(RuleCall.new(name: #metaVar))
|
|
.push(RuleCall.new(name: #metaSubExpr));
|
|
|
|
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; }));
|
|
|
|
block = 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: `{ Block.new(body: b); }));
|
|
|
|
number = Alternation.new()
|
|
.push(Sequence.new()
|
|
.push(StringLiteral.new(string: "-"))
|
|
.push(Assignment.new(name: #n, rule: RuleCall.new(name: #unsign)))
|
|
.push(Action.new(parseTree: `{ Unyop.new(operation: __opNeg).push(n) }))
|
|
)
|
|
.push(Sequence.new()
|
|
.push(StringLiteral.new(string: "+"))
|
|
.push(Assignment.new(name: #n, rule: RuleCall.new(name: #number)))
|
|
.push(Action.new(parseTree: `{ n }))
|
|
)
|
|
.push(Sequence.new()
|
|
.push(Assignment.new(name: #n, rule: RuleCall.new(name: #unsign)))
|
|
.push(Action.new(parseTree: `{ n }))
|
|
);
|
|
|
|
unsign = Sequence.new()
|
|
.push(Begin.new())
|
|
.push(Plus.new(expression: RuleCall.new(name: #digit)))
|
|
.push(End.new())
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Action.new(parseTree: `{ yytext.asInteger(10); }));
|
|
|
|
metaVar = Sequence.new()
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
|
|
.push(Action.new(parseTree: `{ GetVar.new(name: i); }));
|
|
|
|
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); }));
|
|
|
|
digit = CharacterClass.new(value: "0-9");
|
|
letter = CharacterClass.new(value: "A-Za-z_");
|
|
alnum = Alternation.new()
|
|
.push(RuleCall.new(name: #letter))
|
|
.push(RuleCall.new(name: #digit));
|
|
nil = Sequence.new()
|
|
.push(StringLiteral.new(string: "nil"))
|
|
.push(Not.new(expression: RuleCall.new(name: #alnum)))
|
|
.push(RuleCall.new(name: #ws));
|
|
|
|
semi = Sequence.new().push(StringLiteral.new(string: ";" )).push(RuleCall.new(name: #ws));
|
|
comma = Sequence.new().push(StringLiteral.new(string: "," )).push(RuleCall.new(name: #ws));
|
|
lparen = Sequence.new().push(StringLiteral.new(string: "(" )).push(RuleCall.new(name: #ws));
|
|
rparen = Sequence.new().push(StringLiteral.new(string: ")" )).push(RuleCall.new(name: #ws));
|
|
lbrak = Sequence.new().push(StringLiteral.new(string: "[" )).push(RuleCall.new(name: #ws));
|
|
rbrak = Sequence.new().push(StringLiteral.new(string: "]" )).push(RuleCall.new(name: #ws));
|
|
lbrace = Sequence.new().push(StringLiteral.new(string: "{" )).push(RuleCall.new(name: #ws));
|
|
rbrace = Sequence.new().push(StringLiteral.new(string: "}" )).push(RuleCall.new(name: #ws));
|
|
|
|
assign = Sequence.new()
|
|
.push(StringLiteral.new(string: "="))
|
|
.push(Not.new(expression: CharacterClass.new(value: "=")))
|
|
.push(RuleCall.new(name: #ws));
|
|
dot = Sequence.new()
|
|
.push(StringLiteral.new(string: "."))
|
|
.push(Not.new(expression: CharacterClass.new(value: ".")))
|
|
.push(RuleCall.new(name: #ws));
|
|
colon = Sequence.new()
|
|
.push(StringLiteral.new(string: ":"))
|
|
.push(Not.new(expression: CharacterClass.new(value: ":")))
|
|
.push(RuleCall.new(name: #ws));
|
|
|
|
end_of_file = Not.new(expression: Dot.new());
|
|
|
|
end_of_line = Alternation.new()
|
|
.push(StringLiteral.new(string: "\r\n"))
|
|
.push(StringLiteral.new(string: "\n"))
|
|
.push(StringLiteral.new(string: "\r"));
|
|
|
|
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));
|
|
|
|
space = Alternation.new()
|
|
.push(StringLiteral.new(string: " "))
|
|
.push(StringLiteral.new(string: "\t"))
|
|
.push(RuleCall.new(name: #end_of_line));
|
|
|
|
ws = Star.new(expression: Alternation.new()
|
|
.push(RuleCall.new(name: #space))
|
|
.push(RuleCall.new(name: #comment))
|
|
);
|
|
|
|
// ----- Grammar of Grammars -----
|
|
|
|
with(#HardCodedPeg);
|
|
|
|
grammar = Sequence.new()
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Plus.new(expression: Sequence.new()
|
|
.push(Assignment.new(name: #d, rule: RuleCall.new(name: #definition)))
|
|
.push(Action.new(parseTree: `{ set(d.name, d.expression); }))
|
|
))
|
|
.push(RuleCall.new(name: #end_of_file));
|
|
|
|
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 = Alternation.new()
|
|
.push(Sequence.new()
|
|
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #sequence)))
|
|
.push(Not.new(expression: RuleCall.new(name: #bar)))
|
|
.push(Action.new(parseTree: `{ s; }))
|
|
)
|
|
.push(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 = 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 = 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 = 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 = 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: #ruleCall)))
|
|
.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: #ruleCall)))
|
|
.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 = 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: `{ intern(yytext); }));
|
|
|
|
ruleCall = Alternation.new()
|
|
.push(Sequence.new()
|
|
.push(Assignment.new(name: #n, rule: RuleCall.new(name: #identifier)))
|
|
.push(RuleCall.new(name: #ccolon))
|
|
.push(Assignment.new(name: #r, rule: RuleCall.new(name: #identifier)))
|
|
.push(Action.new(parseTree: `{ NamespacedRuleCall.new(namespace: n, name: r); }))
|
|
)
|
|
.push(Sequence.new()
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #identifier)))
|
|
.push(Action.new(parseTree: `{ RuleCall.new(name: i); }))
|
|
);
|
|
|
|
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(string: 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(string: yytext); }))
|
|
);
|
|
|
|
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 = 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 = Alternation.new()
|
|
.push(Sequence.new()
|
|
.push(StringLiteral.new(string: "\\"))
|
|
.push(CharacterClass.new(value: "abefnrtv\'\"[]\\"))
|
|
)
|
|
.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 = Sequence.new()
|
|
.push(Assignment.new(name: #m, rule: NamespacedRuleCall.new(namespace: #HardCodedMeta, name: #block)))
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Action.new(parseTree: `{ Action.new(parseTree: m); }));
|
|
|
|
bar = Sequence.new().push(StringLiteral.new(string: "|")).push(RuleCall.new(name: #ws));
|
|
not = Sequence.new().push(StringLiteral.new(string: "!")).push(RuleCall.new(name: #ws));
|
|
query = Sequence.new().push(StringLiteral.new(string: "?")).push(RuleCall.new(name: #ws));
|
|
begin = Sequence.new().push(StringLiteral.new(string: "<")).push(RuleCall.new(name: #ws));
|
|
end = Sequence.new().push(StringLiteral.new(string: ">")).push(RuleCall.new(name: #ws));
|
|
tilde = Sequence.new().push(StringLiteral.new(string: "~")).push(RuleCall.new(name: #ws));
|
|
rpercent = Sequence.new().push(StringLiteral.new(string: "%}")).push(RuleCall.new(name: #ws));
|
|
|
|
ccolon = Sequence.new().push(StringLiteral.new(string: "::")).push(RuleCall.new(name: #ws));
|
|
|
|
and = Sequence.new()
|
|
.push(StringLiteral.new(string: "&"))
|
|
.push(Not.new(expression: CharacterClass.new(value: "&=")))
|
|
.push(RuleCall.new(name: #ws));
|
|
plus = Sequence.new()
|
|
.push(StringLiteral.new(string: "+"))
|
|
.push(Not.new(expression: CharacterClass.new(value: "+=")))
|
|
.push(RuleCall.new(name: #ws));
|
|
star = Sequence.new()
|
|
.push(StringLiteral.new(string: "*"))
|
|
.push(Not.new(expression: CharacterClass.new(value: "=")))
|
|
.push(RuleCall.new(name: #ws));
|
|
|
|
end_of_file = Not.new(expression: Dot.new());
|
|
|
|
end_of_line = Alternation.new()
|
|
.push(StringLiteral.new(string: "\r\n"))
|
|
.push(StringLiteral.new(string: "\n"))
|
|
.push(StringLiteral.new(string: "\r"));
|
|
|
|
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));
|
|
|
|
space = Alternation.new()
|
|
.push(StringLiteral.new(string: " "))
|
|
.push(StringLiteral.new(string: "\t"))
|
|
.push(RuleCall.new(name: #end_of_line));
|
|
|
|
ws = Star.new(expression: Alternation.new()
|
|
.push(RuleCall.new(name: #space))
|
|
.push(RuleCall.new(name: #comment))
|
|
);
|
|
|
|
// ----- Main -----
|
|
|
|
with(#reading);
|
|
|
|
stream = newStream(readfile("rawminproto.leg"));
|
|
context = Context.new(outerContext: nil).init();
|
|
actions = [];
|
|
|
|
grammar.match(stream, context, actions);
|
|
|
|
with(#metaLanguage);
|
|
for (actionAndContext in actions) {
|
|
actionAndContext.action.execute(actionAndContext.context);
|
|
}
|
|
println("\n--------- META ---------\n\n");
|
|
println(__namespaces__.metaLanguage);
|
|
without(#metaLanguage);
|
|
|
|
//stream = newStream(readfile("rawMetaGrammar.leg"));
|
|
//context = Context.new(outerContext: nil).init();
|
|
//actions = [];
|
|
//
|
|
//print("Matching : ", grammar.match(stream, context, actions), "\n");
|
|
//
|
|
//// Execute all actions after all matching
|
|
//// Open the namespace where rules will be declared
|
|
//with(#metaLanguage);
|
|
//
|
|
//for (actionAndContext in actions) {
|
|
// actionAndContext.action.execute(actionAndContext.context);
|
|
//}
|
|
//
|
|
//println("\n--------- META ---------\n\n");
|
|
//println(__namespaces__.metaLanguage);
|
|
//without(#metaLanguage);
|
|
|
|
without(#reading);
|
|
with(#reading);
|
|
|
|
stream = newStream(readfile("rawgrammar.leg"));
|
|
context = Context.new(outerContext: nil).init();
|
|
actions = [];
|
|
|
|
print("Matching : ", grammar.match(stream, context, actions), "\n");
|
|
|
|
// Execute all actions after all matching
|
|
|
|
with(#peg);
|
|
|
|
for (actionAndContext in actions) {
|
|
actionAndContext.action.execute(actionAndContext.context);
|
|
}
|
|
|
|
println("\n--------- PEG ---------\n\n");
|
|
println(__namespaces__.peg);
|
|
without(#peg);
|
|
|
|
without(#reading);
|
|
|
|
// Circularity test
|
|
without(all: 1);
|
|
|
|
with(#metaLanguage);
|
|
with(#peg);
|
|
with(#reading);
|
|
|
|
stream2 = newStream(readfile("rawminproto.leg"));
|
|
//stream2 = newStream("a = b:c::d { print(a[b].c); }");
|
|
context2 = Context.new(outerContext: nil).init();
|
|
actions2 = [];
|
|
|
|
print("\nMatching : ", grammar.match(stream2, context2, actions2), "\n");
|
|
|
|
with(#metaLanguageCircular);
|
|
|
|
for (actionAndContext in actions2) {
|
|
actionAndContext.action.execute(actionAndContext.context);
|
|
}
|
|
|
|
println("\n--------- CIRCULAR META ---------\n\n");
|
|
println(__namespaces__.metaLanguageCircular);
|
|
without(#metaLanguageCircular);
|
|
|
|
stream2 = newStream(readfile("rawgrammar.leg"));
|
|
context2 = Context.new(outerContext: nil).init();
|
|
actions2 = [];
|
|
|
|
print("\nMatching : ", grammar.match(stream2, context2, actions2), "\n");
|
|
|
|
with(#pegCircular);
|
|
|
|
for (actionAndContext in actions2) {
|
|
actionAndContext.action.execute(actionAndContext.context);
|
|
}
|
|
|
|
println("\n--------- CIRCULAR PEG ---------\n\n");
|
|
println(__namespaces__.pegCircular);
|
|
without(#pegCircular);
|
|
|
|
without(all: 1);
|
|
|
|
compareGrammars(grammar1, grammar2) {
|
|
let success = 1;
|
|
for (key in __namespaces__[grammar1].keys()) {
|
|
if (key == #__nsname__) continue;
|
|
|
|
if (codeString(__namespaces__[grammar1][key]) != codeString(__namespaces__[grammar2][key])) {
|
|
print("Found different objects for rule ", key, ":\n");
|
|
println(__namespaces__[grammar1][key]);
|
|
println(__namespaces__[grammar2][key]);
|
|
success = 0;
|
|
}
|
|
}
|
|
if (success == 1) {
|
|
print("Grammars ", grammar1, " and ", grammar2, " are equal\n");
|
|
}
|
|
}
|
|
|
|
compareGrammars(#peg, #pegCircular);
|
|
compareGrammars(#metaLanguage, #metaLanguageCircular);
|