// ----- 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 = Object.subtype(#Stream); //newStream(string) { // 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) { local 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.getMatchingExpression() { //return `(@stream).match(@self.string) && ((@stream).position += len(@self.string)) && @true; return `{ if (stream.match(@self.string)) { stream.position += len(@self.string); @true; } else { @false; } }; } //StringLiteral.match(stream, context, actions) { // // n = len(self.string); // i = 0; // success = 1; // if (stream.atEnd()) { success = 0; } // startPosition = stream.position; // // while(i < n && success == 1) { // if (self.string[i] != stream.peek()) { // success = 0; // stream.position = startPosition; // // } else { // i = i + 1; // stream.inc(); // } // } // success; //} // Character Class CharacterClass = Object.subtype(#CharacterClass); CharacterClass.match(stream, context, actions) { local classLength = len(self.value); local i = 0; local prevChar = nil; local 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"); local rangeStart = prevChar; local 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; } CharacterClass.staticmatch(stream, context, actions, value) { local classLength = len(value); local i = 0; local prevChar = nil; local success = 0; while (i < classLength && success == 0 && !stream.atEnd()) { // [a] case if (prevChar == nil) { //println("[a] case"); prevChar = value[i]; if (stream.peek() == value[i]) { success = 1; } } else if (prevChar != nil && value[i] == '-') { // [a-z] case if (i+1 < classLength) { // println("[a-z] case"); local rangeStart = prevChar; local rangeEnd = 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 && value[i] != '-') { // println("[ab] case"); prevChar = value[i]; if (stream.peek() == value[i]) { success = 1; } } // print("prevChar: ", prevChar, "\n"); i = i + 1; } if (success == 1) { stream.inc(); } success == 1; } CharacterClass.getMatchingExpression() { //return `CharacterClass.staticmatch(@stream, @context, @actions, @self.value); return `{ CharacterClass.staticmatch(stream, context, actions, @self.value) }; } // Dot Dot = Object.subtype(#Dot); Dot.match(stream, context, actions) { if (!stream.atEnd()) { stream.inc(); true; } else { false; } } Dot.getMatchingExpression() { //return `!(@stream).atEnd() && (@stream).inc() && @true; return `{ !stream.atEnd() && stream.inc() && @true }; } // Begin Begin = Object.subtype(#Begin); Begin.match(stream, context, actions) { stream.setLastBegin(); true; } Begin.getMatchingExpression() { //return `(@stream).setLastBegin() && true; return `{ stream.setLastBegin() && @true }; } // End End = Object.subtype(#End); End.match(stream, context, actions) { context.variables.yytext = stream.content[stream.lastBegin..stream.position].unescaped(); true; } End.getMatchingExpression() { //return `((@context.variables).yytext = (@stream.content)[(@stream).lastBegin..(@stream).position].unescaped()) // && true; return `{ (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; } Optional.getMatchingExpression() { //return `(@self.expression.getMatchingExpression(stream, context, actions)) || @true; return `{ (@self.expression.getMatchingExpression()); @true }; } // Star Star = Object.subtype(#Star); Star.match(stream, context, actions) { while (self.expression.match(stream, context, actions)) {} true; } Star.getMatchingExpression() { return `{ while (@self.expression.getMatchingExpression()) {} @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; } } Plus.getMatchingExpression() { return `{ if (@self.expression.getMatchingExpression()) { while (@self.expression.getMatchingExpression()) {} @true; } else { @false; } }; } // And And = Object.subtype(#And); And.match(stream, context, actions) { local position = stream.position; if (self.expression.match(stream, context, actions) == true) { stream.position = position; true; } else { false; } } And.getMatchingExpression() { return `{ local position = stream.position; if (@self.expression.getMatchingExpression()) { stream.position = position; @true; } else { @false; } }; } // Not Not = Object.subtype(#Not); Not.match(stream, context, actions) { local position = stream.position; if (self.expression.match(stream, context, actions) == true) { stream.position = position; false; } else { true; } } Not.getMatchingExpression() { return `{ local position = stream.position; if (@self.expression.getMatchingExpression()) { 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) { local initialActionCount = actions.length(); local startingPosition = stream.position; local success = self._match(stream, context, actions, 0); if (success == false) { while (actions.length() > initialActionCount) { actions.pop(); } stream.position = startingPosition; } success; } Sequence._getMatchingExpression(index) { if (index == self.length() - 1) { return self[index].getMatchingExpression(); } return `(@self[index].getMatchingExpression()) && @self._getMatchingExpression(index + 1); } Sequence.getMatchingExpression() { return `{ local initialActionCount = actions.length(); local startingPosition = stream.position; ({ (@self._getMatchingExpression(0)); } || { while (actions.length() > initialActionCount) { actions.pop(); } stream.position = startingPosition; @false; }); } } // 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); } Alternation._getMatchingExpression(index) { if (index == self.length() - 1) { return self[index].getMatchingExpression(); } return `(@self[index].getMatchingExpression()) || @self._getMatchingExpression(index + 1); } Alternation.getMatchingExpression() { return `{ @self._getMatchingExpression(0) }; } // Action Action = Object.subtype(#Action); Action.match(stream, context, actions) { actions.push([action: self, context: context]); true; } Action.getMatchingExpression() { return `{ 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 local 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; } } ParseTimeAction.getMatchingExpression() { return `{ (@self.action).execute(context) }; } // Assignment Assignment = Object.subtype(#Assignment); Assignment.match(stream, context, actions) { context.declareVariable(self.name); local innerContext = Context.new(outerContext: context, returnValueName: self.name).init(); self.rule.match(stream, innerContext, actions); } Assignment.getMatchingExpression() { return `{ context.declareVariable(@self.name); local context = Context.new(outerContext: context, returnValueName: @self.name).init(); @self.rule.getMatchingExpression(); } } // 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(); } //print("calling rule ", self.name, " | ", stream.position, "\n"); local res = get(self.name).match(stream, context, actions); //print("matching rule ", self.name, ": ", res, "\n"); res; } RuleCall.getMatchingExpression() { //print("Calling rule ", self.name, "\n"); //local res = `{get(@self.name).getMatchingExpression(@stream, @context, @actions).__eval__()}; //if (innerContext == nil) { `{ Invoke.new(self: self, method: @self.name, arguments: [stream, context, actions]).__eval__() }; //} else { // `{ self.rules[@self.name](stream, @innerContext, actions) }; //} //print("Pos ", stream.position, " | Called rule ", self.name, "\n"); } // NamespacedRuleCall NamespacedRuleCall = Object.subtype(#NamespacedRuleCall); NamespacedRuleCall.match() { with(self.namespace); local res = get(self.name).match(stream, context, actions); without(); res; } NamespacedRuleCall.getMatchingExpression(innerContext) { //return `{ // with(@self.namespace); // local res = get(@self.name).getMatchingExpression(@stream, @context, @actions).__eval__(); // without(); // res; //} //if (innerContext == nil) { `{ Invoke.new(self: @get(self.namespace), method: @self.name, arguments: [stream, context, actions]).__eval__() }; //} else { // `{ (@get(self.namespace)).rules[@self.name](stream, @innerContext, actions) }; //} } Definition = Object.subtype(#Definition); Grammar = Object.subtype(#Grammar); Grammar.addRulesFromNamespace(namespace) { for (key in __namespaces__[namespace].keys()) { if (key == #__nsname__) continue; self[key] = Closure.new( environment: nil, function: Lambda.new( parameters: [#stream, #context, #actions], body: __namespaces__[namespace][key].getMatchingExpression().body ) ) } } // ----- 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: `{ __namespaces__.last()[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 ----- without(all: 1); HardCodedPeg = Grammar.new(); HardCodedMeta = Grammar.new(); HardCodedPeg.addRulesFromNamespace(#HardCodedPeg); HardCodedMeta.addRulesFromNamespace(#HardCodedMeta); HardCodedPeg.__delegate__ = HardCodedMeta; global stream = newStream(readfile("rawminproto.leg")); global context = Context.new(outerContext: nil).init(); global actions = []; print("Matching rawminproto.leg : ", HardCodedPeg.grammar(stream, context, actions), "\n"); with(#metaLanguage); for (actionAndContext in actions) { actionAndContext.action.execute(actionAndContext.context); } without(#metaLanguage); println("\n--------- META ---------\n\n"); println(__namespaces__.metaLanguage); global stream = newStream(readfile("rawgrammar.leg")); global context = Context.new(outerContext: nil).init(); global actions = []; print("Matching rawgrammar.leg : ", HardCodedPeg.grammar(stream, context, actions), "\n"); // Execute all actions after all matching with(#peg); for (actionAndContext in actions) { actionAndContext.action.execute(actionAndContext.context); } without(#peg); println("\n--------- PEG ---------\n\n"); println(__namespaces__.peg); // Circularity test peg = Grammar.new(); metaLanguage = Grammar.new(); peg.addRulesFromNamespace(#peg); metaLanguage.addRulesFromNamespace(#metaLanguage); peg.__delegate__ = metaLanguage; global stream2 = newStream(readfile("rawminproto.leg")); global context2 = Context.new(outerContext: nil).init(); global actions2 = []; print("\nMatching : ", peg.grammar(stream2, context2, actions2), "\n"); with(#metaLanguageCircular); for (actionAndContext in actions2) { actionAndContext.action.execute(actionAndContext.context); } without(#metaLanguageCircular); println("\n--------- CIRCULAR META ---------\n\n"); println(__namespaces__.metaLanguageCircular); global stream2 = newStream(readfile("rawgrammar.leg")); global context2 = Context.new(outerContext: nil).init(); global actions2 = []; print("\nMatching : ", peg.grammar(stream2, context2, actions2), "\n"); with(#pegCircular); for (actionAndContext in actions2) { actionAndContext.action.execute(actionAndContext.context); } without(#pegCircular); println("\n--------- CIRCULAR PEG ---------\n\n"); println(__namespaces__.pegCircular); compareGrammars(grammar1, grammar2) { local 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);