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) });