global then = cputime();
|
|
|
|
// ----- 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)) {
|
|
newNamespace = [__nsname__: namespace];
|
|
__namespaces__[namespace] = newNamespace;
|
|
__namespaces__[0][namespace] = newNamespace;
|
|
} else {
|
|
__namespaces__[0][namespace] = __namespaces__[namespace];
|
|
}
|
|
|
|
__namespaces__.push(__namespaces__[namespace]);
|
|
return __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)) {
|
|
removedNamespace = __namespaces__.pop().__nsname__;
|
|
//print("--- Without ", removedNamespace, " ---\n\n");
|
|
__namespaces__[0][removedNamespace] = nil;
|
|
}
|
|
__namespaces__.pop();
|
|
return;
|
|
}
|
|
|
|
// Remove last
|
|
if (namespace == nil) {
|
|
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
|
|
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));
|
|
}
|
|
|
|
setInTopNamespace(__identifier, __value) {
|
|
__namespaces__.last()[__identifier] = __value;
|
|
}
|
|
|
|
println(x) {
|
|
if (!x) {
|
|
if (len(__env__().__delegate__) == 0){
|
|
print("\n");
|
|
} else {
|
|
print(nil, "\n");
|
|
}
|
|
} else {
|
|
print(x, "\n", full: 1);
|
|
}
|
|
}
|
|
|
|
Object.subtype(name) { self.new(__name__: name) }
|
|
|
|
Object.last() { self[self.length() - 1] }
|
|
|
|
// Input stream
|
|
|
|
Stream.peek() { self.content[self.position] }
|
|
|
|
// Context
|
|
|
|
Context = Object.subtype(#Context);
|
|
Context.init() { self.variables = []; self; }
|
|
Context.declareVariable(var) {
|
|
local found = 0;
|
|
for (key in self.variables.keys()) {
|
|
if (key == var) {
|
|
found = 1;
|
|
}
|
|
}
|
|
if (found == 0) {
|
|
self.variables[var] = nil;
|
|
}
|
|
}
|
|
|
|
// ----- Grammar Constructs -----
|
|
|
|
// Parser VM op-codes
|
|
|
|
// opcodes opcode argument arglength next-pc notes
|
|
OpCodes = [
|
|
PUSH: 0, // PUSH nil 0 ok ok both pcs should be set the same
|
|
DROP: 1, // DROP nil 0 ok ok
|
|
POP: 2, // POP nil 0 ok ok
|
|
DOT: 3, // DOT nil 0 ok ko ok/ko next pc are absolute and are
|
|
CLASS: 4, // CLASS bitarray len(bitarray) ok ko instruction indexes (0, 1, 2, ...)
|
|
STRING: 5, // STRING string len(string) ok ko and not array indexes (0, 5, 10, ...)
|
|
TEST: 6,
|
|
RULE2: 7,
|
|
RULE: 8, // RULE symbol 0 ok ko
|
|
CALL: 9, // CALL nil 0 ok ko do not use this; VM internal use only
|
|
CALL2: 10, // CALL nil 0 ok ko do not use this; VM internal use only
|
|
SUCCEED: 11, // SUCCEED nil 0 0 0 next pcs are ignored
|
|
FAIL: 12, // FAIL nil 0 0 0
|
|
ACTION: 13, // ACTION function 0 ok ok both pcs should be the same
|
|
BEGIN: 14, // BEGIN nil 0 ok ok
|
|
END: 15, // END nil 0 ok ok
|
|
UNEND: 16, // UNEND nil 0 ok ok
|
|
SET: 17 // SET symbol 0 ok ok
|
|
];
|
|
|
|
OpCodeNames = [
|
|
"PUSH",
|
|
"DROP",
|
|
"POP",
|
|
"DOT",
|
|
"CLASS",
|
|
"STRING",
|
|
"TEST",
|
|
"RULE2",
|
|
"RULE",
|
|
"CALL",
|
|
"CALL2",
|
|
"SUCCEED",
|
|
"FAIL",
|
|
"ACTION",
|
|
"BEGIN",
|
|
"END",
|
|
"UNEND",
|
|
"SET"
|
|
];
|
|
|
|
Instruction = Object.subtype(#Instruction);
|
|
|
|
Instruction.new(op, arg, arglen, ok, ko) {
|
|
self = super.new();
|
|
self.op = op;
|
|
self.arg = arg;
|
|
self.arglen = arglen;
|
|
self.ok = ok;
|
|
self.ko = ko;
|
|
self;
|
|
}
|
|
|
|
Instruction.printline() {
|
|
print(OpCodeNames[self.op], " ", codeString(self.arg), " ", self.arglen, " ", self.ok, " ", self.ko, "\n");
|
|
}
|
|
|
|
// String Literal
|
|
|
|
StringLiteral = Object.subtype(#StringLiteral);
|
|
|
|
StringLiteral.emitByteCode(instructions, ok, ko) {
|
|
//emit(STRING, (byte *)node->String.string, strlen(node->String.string), ok, ko);
|
|
instructions.push(Instruction.new(OpCodes.STRING, self.string, len(self.string), ok, ko));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
|
|
// Character Class
|
|
|
|
CharacterClass = Object.subtype(#CharacterClass);
|
|
|
|
CharacterClass.emitByteCode(instructions, ok, ko) {
|
|
//emit(CLASS, node->Class.bits, 32, ok, ko);
|
|
instructions.push(Instruction.new(OpCodes.CLASS, self.value.charClass(), 32, ok, ko));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Dot
|
|
|
|
Dot = Object.subtype(#Dot);
|
|
|
|
Dot.emitByteCode(instructions, ok, ko) {
|
|
//emit(DOT, 0, 0, ok, ko);
|
|
instructions.push(Instruction.new(OpCodes.DOT, 0, 0, ok, ko));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Capture
|
|
|
|
Capture = Object.subtype(#Capture);
|
|
|
|
Capture.emitByteCode(instructions, ok, ko) {
|
|
//ok = emit(END, 0, 0, ok, ok);
|
|
//ko = emit(UNEND, 0, 0, ko, ko);
|
|
//ok = generateNode(node->Capture.exp, ok, ko);
|
|
//emit(BEGIN, 0, 0, ok, ok);
|
|
// FAIS CE QUE LE CODE DIT BORDEL
|
|
|
|
instructions.push(Instruction.new(OpCodes.END, 0, 0, ok, ok));
|
|
ok = instructions.length() - 1;
|
|
instructions.push(Instruction.new(OpCodes.UNEND, 0, 0, ko, ko));
|
|
ko = instructions.length() - 1;
|
|
|
|
ok = self.expression.emitByteCode(instructions, ok, ko);
|
|
instructions.push(Instruction.new(OpCodes.BEGIN, 0, 0, ok, ok));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Optional (? postfix operator)
|
|
|
|
Optional = Object.subtype(#Optional);
|
|
|
|
Optional.emitByteCode(instructions, ok, ko) {
|
|
self.expression.emitByteCode(instructions, ok, ok);
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Star
|
|
|
|
Star = Object.subtype(#Star);
|
|
|
|
Star.emitByteCode(instructions, ok, ko) {
|
|
local last = instructions.length();
|
|
self.expression.emitByteCode(instructions, ok, ok);
|
|
instructions[last].ok = instructions.length() - 1;
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Plus
|
|
|
|
Plus = Object.subtype(#Plus);
|
|
|
|
Plus.emitByteCode(instructions, ok, ko) {
|
|
local last = instructions.length();
|
|
local next = self.expression.emitByteCode(instructions, ok, ok);
|
|
instructions[last].ok = instructions.length() - 1;
|
|
self.expression.emitByteCode(instructions, next, ko);
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// And
|
|
|
|
And = Object.subtype(#And);
|
|
|
|
And.emitByteCode(instructions, ok, ko) {
|
|
instructions.push(Instruction.new(OpCodes.POP, 0, 0, ok, ok));
|
|
ok = instructions.length() - 1;
|
|
instructions.push(Instruction.new(OpCodes.DROP, 0, 0, ko, ko));
|
|
ko = instructions.length() - 1;
|
|
local here = self.expression.emitByteCode(instructions, ok, ko);
|
|
instructions.push(Instruction.new(OpCodes.PUSH, 0, 0, here, here));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Not
|
|
|
|
Not = Object.subtype(#Not);
|
|
|
|
Not.emitByteCode(instructions, ok, ko) {
|
|
instructions.push(Instruction.new(OpCodes.POP, 0, 0, ko, ko));
|
|
local nok = instructions.length() - 1;
|
|
instructions.push(Instruction.new(OpCodes.DROP, 0, 0, ok, ok));
|
|
local nko = instructions.length() - 1;
|
|
|
|
local here = self.expression.emitByteCode(instructions, nok, nko);
|
|
instructions.push(Instruction.new(OpCodes.PUSH, 0, 0, here, here));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Sequence
|
|
|
|
Sequence = Object.subtype(#Sequence);
|
|
|
|
Sequence.emitByteCode(instructions, ok, ko) {
|
|
instructions.push(Instruction.new(OpCodes.DROP, 0, 0, ok, ok));
|
|
ok = instructions.length() - 1;
|
|
instructions.push(Instruction.new(OpCodes.POP, 0, 0, ko, ko));
|
|
ko = instructions.length() - 1;
|
|
|
|
for (i from self.length() - 1 to 0) {
|
|
ok = self[i].emitByteCode(instructions, ok, ko);
|
|
}
|
|
|
|
instructions.push(Instruction.new(OpCodes.PUSH, 0, 0, ok, ok));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Alternation
|
|
|
|
Alternation = Object.subtype(#Alternation);
|
|
|
|
Alternation.prepend(sequenceString) {
|
|
alt = self;
|
|
parse(sequenceString, pegGrammar, #startSequence,
|
|
(result) {
|
|
alt.push(alt[len(alt) - 1]);
|
|
for (i from len(alt) - 2 to 0) {
|
|
alt[i + 1] = alt[i];
|
|
}
|
|
alt[0] = result;
|
|
}
|
|
);
|
|
self.parser.__update(self.name, self);
|
|
}
|
|
|
|
parseDefinition(pegString) {
|
|
local definition = nil;
|
|
parse(pegString, pegGrammar, #grammar, (result){ definition = result });
|
|
definition;
|
|
}
|
|
|
|
Alternation.emitByteCode(instructions, ok, ko) {
|
|
instructions.push(Instruction.new(OpCodes.DROP, 0, 0, ok, ok));
|
|
ok = instructions.length() - 1;
|
|
instructions.push(Instruction.new(OpCodes.POP, 0, 0, ko, ko));
|
|
ko = instructions.length() - 1;
|
|
|
|
for (i from self.length() - 1 to 0) {
|
|
ko = self[i].emitByteCode(instructions, ok, ko);
|
|
}
|
|
|
|
instructions.push(Instruction.new(OpCodes.PUSH, 0, 0, ko, ko));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Action
|
|
|
|
Action = Object.subtype(#Action);
|
|
|
|
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
|
|
local returnValue = eval(self.parseTree, env: context.variables);
|
|
if (context.outerContext != nil) {
|
|
context.outerContext.variables[context.returnValueName] = returnValue;
|
|
}
|
|
|
|
returnValue;
|
|
}
|
|
|
|
Action.emitByteCode(instructions, ok, ko) {
|
|
instructions.push(Instruction.new(
|
|
OpCodes.ACTION,
|
|
Closure.new(
|
|
environment: nil,
|
|
function: Lambda.new(
|
|
parameters: [],
|
|
body: self.parseTree.body
|
|
)
|
|
),
|
|
0,
|
|
ok,
|
|
ok
|
|
));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Parse-time Action (&)
|
|
|
|
ParseTimeAction = Object.subtype(#ParseTimeAction);
|
|
|
|
ParseTimeAction.emitByteCode(instructions, ok, ko) {
|
|
instructions.push(Instruction.new(
|
|
OpCodes.TEST,
|
|
Closure.new(
|
|
environment: nil,
|
|
function: Lambda.new(
|
|
parameters: [],
|
|
body: self.action.parseTree.body
|
|
)
|
|
),
|
|
0,
|
|
ok,
|
|
ko
|
|
));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Execute Action (@)
|
|
|
|
ExecuteAction = Object.subtype(#ExecuteAction);
|
|
|
|
ExecuteAction.emitByteCode(instructions, ok, ko) {
|
|
instructions.push(Instruction.new(
|
|
OpCodes.TEST,
|
|
Closure.new(
|
|
environment: nil,
|
|
function: Lambda.new(
|
|
parameters: [],
|
|
body: self.action.parseTree.body
|
|
)
|
|
),
|
|
0,
|
|
ok,
|
|
ok
|
|
));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// Assignment
|
|
|
|
Assignment = Object.subtype(#Assignment);
|
|
|
|
Assignment.emitByteCode(instructions, ok, ko) {
|
|
instructions.push(Instruction.new(OpCodes.SET, self.name, 0, ok, ok));
|
|
ok = instructions.length() - 1;
|
|
self.rule.emitByteCode(instructions, ok, ko);
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// RuleCall
|
|
|
|
RuleCall = Object.subtype(#RuleCall);
|
|
|
|
RuleCall.emitByteCode(instructions, ok, ko) {
|
|
instructions.push(Instruction.new(OpCodes.RULE, self.name, 0, ok, ko));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
// NamespacedRuleCall
|
|
|
|
NamespacedRuleCall = Object.subtype(#NamespacedRuleCall);
|
|
|
|
NamespacedRuleCall.emitByteCode(instructions, ok, ko) {
|
|
instructions.push(Instruction.new(OpCodes.RULE2, self.name, self.namespace, ok, ko));
|
|
instructions.length() - 1;
|
|
}
|
|
|
|
Definition = Object.subtype(#Definition);
|
|
|
|
// Initialize grammar objects
|
|
|
|
Grammar = Object.subtype(#Grammar);
|
|
Parser = Object.subtype(#Parser);
|
|
|
|
Grammar.new() {
|
|
self = super.new();
|
|
self.parser = Parser.new();
|
|
self;
|
|
}
|
|
|
|
minPegGrammar = Grammar.new();
|
|
minMetaGrammar = Grammar.new();
|
|
|
|
// ----- 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()
|
|
.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(Action.new(parseTree: `{ $$ = SetProp.new(object: p, key: i, value: e); }))
|
|
)
|
|
.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(StringLiteral.new(string: "global"))
|
|
.push(RuleCall.new(name: #ws))
|
|
.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: `{ $$ = SetGlobal.new(name: 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: #metaPrefix)))
|
|
.push(Action.new(parseTree: `{ $$ = pf; }))
|
|
);
|
|
|
|
metaPrefix =
|
|
Alternation.new()
|
|
.push(Sequence.new()
|
|
.push(RuleCall.new(name: #pplus))
|
|
.push(Assignment.new(name: #p, rule: RuleCall.new(name: #metaPrefix)))
|
|
.push(Action.new(parseTree: `{ $$ = newBinop(opPreAdd, lvalue(p), newInteger(1)) }))
|
|
)
|
|
.push(RuleCall.new(name: #metaPostfix));
|
|
|
|
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: #lbrak))
|
|
.push(Assignment.new(name: #s, rule: RuleCall.new(name: #metaExpression)))
|
|
.push(RuleCall.new(name: #rbrak))
|
|
.push(Not.new(expression: RuleCall.new(name: #assign)))
|
|
.push(Action.new(parseTree: `{ p = newGetArray(p, s) }))
|
|
)
|
|
.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: #string))
|
|
.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: `{ $$ = b; }));
|
|
|
|
string =
|
|
Sequence.new()
|
|
.push(StringLiteral.new(string: "\""))
|
|
.push(Capture.new(expression: Star.new(expression: Sequence.new()
|
|
.push(Not.new(expression: StringLiteral.new(string: "\"")))
|
|
.push(RuleCall.new(name: #char))
|
|
)))
|
|
.push(StringLiteral.new(string: "\""))
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Action.new(parseTree: `{ $$ = newStringUnescaped(yytext) }));
|
|
|
|
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(StringLiteral.new(string: "\\"))
|
|
.push(CharacterClass.new(value: "xX"))
|
|
.push(Star.new(expression: RuleCall.new(name: #higit)))
|
|
)
|
|
.push(Sequence.new()
|
|
.push(Not.new(expression: StringLiteral.new(string: "\\")))
|
|
.push(Dot.new())
|
|
);
|
|
|
|
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(Capture.new(expression:
|
|
Plus.new(expression: RuleCall.new(name: #digit)))
|
|
)
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Action.new(parseTree: `{ $$ = yytext.asInteger(10); }));
|
|
|
|
metaVar =
|
|
Alternation.new()
|
|
.push(
|
|
Sequence.new()
|
|
.push(StringLiteral.new(string: "global"))
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
|
|
.push(Action.new(parseTree: `{ $$ = GetGlobal.new(name: i); }))
|
|
)
|
|
.push(
|
|
Sequence.new()
|
|
.push(Assignment.new(name: #i, rule: RuleCall.new(name: #metaId)))
|
|
.push(Action.new(parseTree: `{ $$ = GetVar.new(name: i); }))
|
|
);
|
|
|
|
metaId =
|
|
Sequence.new()
|
|
.push(Capture.new(expression: Sequence.new()
|
|
.push(RuleCall.new(name: #letter))
|
|
.push(Star.new(expression: RuleCall.new(name: #alnum)))
|
|
))
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Action.new(parseTree: `{ $$ = intern(yytext); }));
|
|
|
|
digit = CharacterClass.new(value: "0-9");
|
|
higit = CharacterClass.new(value: "0-9A-Fa-f");
|
|
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))
|
|
.push(Action.new(parseTree: `{ $$ = nil }));
|
|
|
|
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));
|
|
pplus = 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(Alternation.new()
|
|
.push(Sequence.new()
|
|
.push(Assignment.new(name: #d, rule: RuleCall.new(name: #definition)))
|
|
.push(Action.new(parseTree: `{ global yysval = d; }))
|
|
)
|
|
.push(Sequence.new()
|
|
.push(RuleCall.new(name: #end_of_file))
|
|
.push(Action.new(parseTree: `{ global yysval = nil; }))
|
|
)
|
|
);
|
|
|
|
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(Optional.new(expression: Sequence.new()
|
|
.push(Assignment.new(name: #q, rule: RuleCall.new(name: #prefix)))
|
|
.push(Action.new(parseTree: `{ $$ = p = Sequence.new().push(p).push(q); }))
|
|
.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(Sequence.new()
|
|
.push(RuleCall.new(name: #at))
|
|
.push(Assignment.new(name: #a, rule: RuleCall.new(name: #action)))
|
|
.push(Action.new(parseTree: `{ $$ = ExecuteAction.new(action: a); }))
|
|
)
|
|
.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(Assignment.new(name: #e, rule: RuleCall.new(name: #expression)))
|
|
.push(RuleCall.new(name: #end))
|
|
.push(Action.new(parseTree: `{ $$ = Capture.new(expression: e); }))
|
|
);
|
|
|
|
identifier =
|
|
Sequence.new()
|
|
.push(Capture.new(expression: Sequence.new()
|
|
.push(CharacterClass.new(value: "-a-zA-Z_"))
|
|
.push(Star.new(expression: CharacterClass.new(value: "-a-zA-Z_0-9")))
|
|
))
|
|
.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: GetProp.new(object: GetVar.new(name: n), key: #parser).__eval__(),
|
|
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(Capture.new(expression:
|
|
Star.new(expression: Sequence.new()
|
|
.push(Not.new(expression: CharacterClass.new(value: "\'")))
|
|
.push(RuleCall.new(name: #char)))
|
|
))
|
|
.push(CharacterClass.new(value: "\'"))
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Action.new(parseTree: `{ $$ = StringLiteral.new(string: yytext.unescaped()); }))
|
|
)
|
|
.push(Sequence.new()
|
|
.push(CharacterClass.new(value: "\""))
|
|
.push(Capture.new(expression:
|
|
Star.new(expression: Sequence.new()
|
|
.push(Not.new(expression: CharacterClass.new(value: "\"")))
|
|
.push(RuleCall.new(name: #char)))
|
|
))
|
|
.push(CharacterClass.new(value: "\""))
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Action.new(parseTree: `{ $$ = StringLiteral.new(string: yytext.unescaped()); }))
|
|
);
|
|
|
|
class =
|
|
Sequence.new()
|
|
.push(StringLiteral.new(string: "["))
|
|
.push(Capture.new(expression:
|
|
Star.new(expression: Sequence.new()
|
|
.push(Not.new(expression: StringLiteral.new(string: "]")))
|
|
.push(RuleCall.new(name: #range)))
|
|
))
|
|
.push(StringLiteral.new(string: "]"))
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Action.new(parseTree: `{ $$ = CharacterClass.new(value: yytext.unescaped()); }));
|
|
|
|
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: minMetaGrammar.parser, name: #block)))
|
|
.push(RuleCall.new(name: #ws))
|
|
.push(Action.new(parseTree: `{ $$ = Action.new(parseTree: Block.new(body: 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));
|
|
at = 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))
|
|
);
|
|
|
|
without(all: 1);
|
|
|
|
// Functions for minproto parser
|
|
|
|
Object_push(o, v) {
|
|
o.push(v);
|
|
o;
|
|
}
|
|
|
|
Object_put(o, k, v) {
|
|
o[k] = v;
|
|
o;
|
|
}
|
|
|
|
global pObject = Object;
|
|
|
|
new(_) {
|
|
[];
|
|
}
|
|
|
|
_get(obj, _, __) {
|
|
obj;
|
|
}
|
|
|
|
expected(what, where)
|
|
{
|
|
error("syntax error: " + what + " expected near: " + where);
|
|
}
|
|
|
|
syntaxError(str) {
|
|
error("syntax error: " + str);
|
|
}
|
|
|
|
newWhile(cond, stmt) {
|
|
While.new(condition: cond, body: stmt);
|
|
}
|
|
|
|
newIf(c, s, t) {
|
|
If.new(condition: c, consequent: s, alternate: t);
|
|
}
|
|
|
|
newContinue() {
|
|
Continue.new();
|
|
}
|
|
|
|
newBreak(e) {
|
|
Break.new(value: e);
|
|
}
|
|
|
|
newReturn(e) {
|
|
Return.new(value: e);
|
|
}
|
|
|
|
newForIn(i, e, s) {
|
|
ForIn.new(identifier: i, expression: e, body: s);
|
|
}
|
|
|
|
newForFromTo(i, a, b, s) {
|
|
ForFromTo.new(identifier: i, first: a, last: b, body: s);
|
|
}
|
|
|
|
newFor(i, c, u, s) {
|
|
For.new(initialise: i, condition: c, update: u, body: s);
|
|
}
|
|
|
|
newTryCatch(t, i, c) {
|
|
TryCatch.new(statement: t, identifier: i, handler: c);
|
|
}
|
|
|
|
newTryEnsure(t, e) {
|
|
TryEnsure.new(statement: t, handler: e);
|
|
}
|
|
|
|
newRaise(e) {
|
|
Raise.new(value: e);
|
|
}
|
|
|
|
newLambda(p, b, par, n) {
|
|
Lambda.new(parameters: p, body: b, parent: par, name: n);
|
|
}
|
|
|
|
newGetLocal(i) {
|
|
GetLocal.new(name: i);
|
|
}
|
|
|
|
newSetLocal(i, v) {
|
|
SetLocal.new(name: i, value: v);
|
|
}
|
|
|
|
newGetGlobal(i) {
|
|
GetGlobal.new(name: i);
|
|
}
|
|
|
|
newSetGlobal(i, v) {
|
|
SetGlobal.new(name: i, value: v);
|
|
}
|
|
|
|
newGetVar(i) {
|
|
GetVar.new(name: i);
|
|
}
|
|
|
|
newSetVar(i, v) {
|
|
SetVar.new(name: i, value: v);
|
|
}
|
|
|
|
newGetProp(v, j) {
|
|
GetProp.new(object: v, key: j);
|
|
}
|
|
|
|
newSetProp(o, k, v) {
|
|
SetProp.new(object: o, key: k, value: v);
|
|
}
|
|
|
|
newBlock(b) {
|
|
Block.new(body: b);
|
|
}
|
|
|
|
newUnyop(o, p) {
|
|
Unyop.new(operation: o).push(p);
|
|
}
|
|
|
|
neg(n) {
|
|
Unyop.new(operation: opNeg).push(n);
|
|
}
|
|
|
|
newSuper(i, a) {
|
|
Super.new(method: i, arguments: a);
|
|
}
|
|
|
|
newGetArray(p, e) {
|
|
GetArray.new(object: p, index: e);
|
|
}
|
|
|
|
newGetSlice(o, s, e) {
|
|
GetSlice.new(object: o, start: s, stop: e);
|
|
}
|
|
|
|
newInvoke(p, i, a) {
|
|
Invoke.new(self: p, method: i, arguments: a);
|
|
}
|
|
|
|
newLiteral(o) {
|
|
Literal.new(object: o);
|
|
}
|
|
|
|
newFloat(f) {
|
|
f;
|
|
}
|
|
|
|
strtod(text, _) {
|
|
text.asFloat();
|
|
}
|
|
|
|
newInteger(i) {
|
|
i;
|
|
}
|
|
|
|
strtol(text, _, base) {
|
|
text.asInteger(base)
|
|
}
|
|
|
|
newStringUnescaped(text) {
|
|
text.unescaped();
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
Parser.__update(ruleName, ruleExpression, v: false) {
|
|
|
|
local instructions = [];
|
|
|
|
instructions.push(Instruction.new(OpCodes.FAIL, nil, 0, 0, 0));
|
|
local ko = instructions.length() - 1;
|
|
|
|
instructions.push(Instruction.new(OpCodes.SUCCEED, nil, 0, 0, 0));
|
|
local ok = instructions.length() - 1;
|
|
|
|
ruleExpression.emitByteCode(instructions, ok, ko);
|
|
|
|
for (n from 0 to (instructions.length() - 1 - ((instructions.length() - 1) % 2)) / 2) {
|
|
local i = instructions[n];
|
|
instructions[n] = instructions[instructions.length() - 1 - n];
|
|
instructions[instructions.length() - 1 - n] = i;
|
|
}
|
|
|
|
if (v) {
|
|
println(ruleName);
|
|
}
|
|
|
|
for (n in instructions.length()) {
|
|
i = instructions[n];
|
|
i.ok = instructions.length() - 1 - i.ok;
|
|
i.ko = instructions.length() - 1 - i.ko;
|
|
if (v) {
|
|
print(" ", { if (n < 100) { "0" } else { "" } }, { if (n < 10) { "0" } else { "" } }, n, " ");
|
|
i.printline();
|
|
}
|
|
}
|
|
|
|
self[ruleName] = [];
|
|
for (instruction in instructions) {
|
|
self[ruleName].push(instruction.op);
|
|
self[ruleName].push(instruction.arg);
|
|
self[ruleName].push(instruction.arglen);
|
|
self[ruleName].push(instruction.ok);
|
|
self[ruleName].push(instruction.ko);
|
|
}
|
|
}
|
|
|
|
Grammar.addRule(ruleName, ruleExpression, v: false) {
|
|
|
|
self[ruleName] = ruleExpression;
|
|
self[ruleName].parser = self.parser;
|
|
self[ruleName].name = ruleName;
|
|
self.parser.__update(ruleName, ruleExpression, v: v);
|
|
|
|
}
|
|
|
|
// Grammar object construction
|
|
for (ruleName in __namespaces__.HardCodedPeg.keys()) {
|
|
if (ruleName == #__nsname__) continue;
|
|
minPegGrammar.addRule(ruleName, __namespaces__.HardCodedPeg[ruleName]);
|
|
}
|
|
|
|
for (ruleName in __namespaces__.HardCodedMeta.keys()) {
|
|
if (ruleName == #__nsname__) continue;
|
|
minMetaGrammar.addRule(ruleName, __namespaces__.HardCodedMeta[ruleName]);
|
|
}
|
|
|
|
minPegGrammar.parser.__delegate__ = minMetaGrammar.parser;
|
|
|
|
// Parsing function
|
|
|
|
parse(input, grammar, startRule, resultCallback){
|
|
|
|
local cursor = 0;
|
|
matchedCharacters = __match__(grammar.parser, startRule, input, cursor);
|
|
cursor += matchedCharacters;
|
|
|
|
while (yysval != 0 && yysval != nil && matchedCharacters >= 0) {
|
|
resultCallback(yysval);
|
|
matchedCharacters = __match__(grammar.parser, startRule, input, cursor);
|
|
cursor += matchedCharacters;
|
|
}
|
|
|
|
}
|
|
|
|
input = readfile("minproto.grammar");
|
|
metaGrammar = Grammar.new();
|
|
global lineno = 0; // This is for the grammar above
|
|
|
|
// How to read the following function call :
|
|
// parse input with minPegGrammar starting with rule grammar applying this function to each result
|
|
parse(input, minPegGrammar, #grammar, (result){ metaGrammar.addRule(result.name, result.expression) });
|
|
|
|
input = readfile("rawgrammar.leg");
|
|
pegGrammar = Grammar.new();
|
|
parse(input, minPegGrammar, #grammar, (result){ pegGrammar.addRule(result.name, result.expression) });
|
|
|
|
circularityTest = false;
|
|
//circularityTest = true;
|
|
if (circularityTest) {
|
|
|
|
compareGrammars(grammar1, grammar2) {
|
|
for (rule in grammar1.parser.keys()) {
|
|
|
|
if (grammar1.parser[rule].length() != grammar2.parser[rule].length()) {
|
|
print("Unmatching lengths for rule ", rule, "\n");
|
|
return false;
|
|
}
|
|
|
|
for (i in grammar1[rule].length()) {
|
|
if (codeString(grammar1.parser[rule][i]) != codeString(grammar2.parser[rule][i])) {
|
|
print("Unmatching contents for rule ", rule, " at index ", i, ":\n",
|
|
grammar1.parser[rule][i], "\n", grammar2.parser[rule][i], "\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
input = readfile("rawgrammar.leg");
|
|
pegGrammarCircular = Grammar.new();
|
|
parse(input, pegGrammar, #grammar, (result){ pegGrammarCircular.addRule(result.name, result.expression) });
|
|
|
|
input = readfile("minproto.grammar");
|
|
metaGrammarCircular = Grammar.new();
|
|
parse(input, pegGrammar, #grammar, (result){ metaGrammarCircular.addRule(result.name, result.expression) });
|
|
|
|
if (compareGrammars(pegGrammar, pegGrammarCircular))
|
|
print("Grammars pegGrammar and pegGrammarCircular are equal\n");
|
|
if (compareGrammars(metaGrammar, metaGrammarCircular))
|
|
print("Grammars metaGrammar and metaGrammarCircular are equal\n");
|
|
|
|
}
|
|
|
|
input = readfile("dowhile.meta");
|
|
parse(input, metaGrammar, #start, (result){ eval(result, env: nil) });
|
|
|
|
input = readfile("fstring.meta");
|
|
parse(input, metaGrammar, #start, (result){ eval(result, env: nil) });
|