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