diff options
author | romangraef <roman.graef@gmail.com> | 2018-05-15 20:02:18 +0200 |
---|---|---|
committer | romangraef <roman.graef@gmail.com> | 2018-05-15 20:02:18 +0200 |
commit | 9187528a1e4d96aee5381138547c62ed7e281aa8 (patch) | |
tree | 5aaea27d46ba55d54866cacb130425cbcd560896 /query | |
parent | 50787a7a3c14b8cbe1890cfdc62bc1d27171209c (diff) | |
download | fuckingselfbot-master.tar.gz fuckingselfbot-master.tar.bz2 fuckingselfbot-master.zip |
Diffstat (limited to 'query')
-rw-r--r-- | query/Query.g4 | 33 | ||||
-rw-r--r-- | query/__init__.py | 1 | ||||
-rw-r--r-- | query/parse.py | 113 |
3 files changed, 147 insertions, 0 deletions
diff --git a/query/Query.g4 b/query/Query.g4 new file mode 100644 index 0000000..a13a80f --- /dev/null +++ b/query/Query.g4 @@ -0,0 +1,33 @@ + +grammar Query; + +prog: stat+ EOF? ; + +stat: expr # rawExpr + | ID '=' expr # assign + ; + +expr: expr '.' ID # access + | expr '(' (args=expr*) ')' # call + | expr op=('*'|'/') expr # MulDiv + | expr op=('+'|'-') expr # AddSub + | INT # int + | STRINGLITERAL # string + | ID # id + | '(' expr ')' # parens + | '{' (args=arguments)? prog '}' # func + ; + +arguments: ID (',' ID)* '->'; + +STRINGLITERAL : '"' ( StringEscapeSeq | ~( '\\' | '"' | '\r' | '\n' ) )* '"' ; +StringEscapeSeq : '\\' ( 't' | 'n' | 'r' | '"' | '\\' | '$' | ('0'..'9')) ; + +MUL : '*' ; // assigns token name to '*' used above in grammar +DIV : '/' ; +ADD : '+' ; +SUB : '-' ; +ID : [a-zA-Z]+ ; // match identifiers +INT : [0-9]+ ; // match integers +NEWLINE:'\r'? '\n' -> skip ; // return newlines to parser (is end-statement signal) +WS : [ \t]+ -> skip ; // toss out whitespace
\ No newline at end of file diff --git a/query/__init__.py b/query/__init__.py new file mode 100644 index 0000000..1b51639 --- /dev/null +++ b/query/__init__.py @@ -0,0 +1 @@ +from .parse import parse diff --git a/query/parse.py b/query/parse.py new file mode 100644 index 0000000..b509044 --- /dev/null +++ b/query/parse.py @@ -0,0 +1,113 @@ +from typing import List + +from antlr4 import * + +from query.QueryLexer import QueryLexer +from query.QueryParser import QueryParser +from query.QueryVisitor import QueryVisitor + + +def make_function(outer_scope, argument_names: List[str], parser: QueryParser, prog: QueryParser.ProgContext): + def function(*args): + visitor = MyQueryVisitor(parser) + visitor.memory = outer_scope.copy() + for i in range(len(args)): + visitor.memory[argument_names[i]] = args[i] + return visitor.for_result(prog) + + return function + + +class Return(Exception): + def __init__(self, thing): + self.ret = thing + + +class MyQueryVisitor(QueryVisitor): + def __init__(self, parser: QueryParser): + self.memory = { + } + self.parser: QueryParser = parser + self.last_expr = None + + def for_result(self, ctx): + try: + self.visit(ctx) + except Return as ret: + return ret.ret + return self.last_expr + + def visitProg(self, ctx: QueryParser.ProgContext): + for stat in ctx.getChildren(lambda child: isinstance(child, QueryParser.StatContext)): + self.visit(stat) + + def visitFunc(self, ctx: QueryParser.FuncContext): + args = ctx.arguments().getText()[:-2].split(',') + return make_function(self.memory, args, self.parser, ctx.prog()) + + def visitAssign(self, ctx): + name = ctx.ID().getText() + value = self.visit(ctx.expr()) + self.memory[name] = value + return value + + def visitRawExpr(self, ctx: QueryParser.RawExprContext): + value = self.visit(ctx.expr()) + self.last_expr = value + return value + + def visitInt(self, ctx): + return int(ctx.INT().getText()) + + def visitId(self, ctx): + name = ctx.ID().getText() + if name in self.memory: + return self.memory[name] + return 0 + + def visitAccess(self, ctx: QueryParser.AccessContext): + thing = self.visit(ctx.expr()) + return getattr(thing, ctx.ID(), 0) + + def visitMulDiv(self, ctx): + left = (self.visit(ctx.expr(0))) + right = (self.visit(ctx.expr(1))) + if ctx.op.type == QueryParser.MUL: + return left * right + return left / right + + def visitString(self, ctx: QueryParser.StringContext): + return eval(ctx.getText()) + + def visitAddSub(self, ctx): + left = int(self.visit(ctx.expr(0))) + right = int(self.visit(ctx.expr(1))) + if ctx.op.type == QueryParser.ADD: + return left + right + return left - right + + def visitParens(self, ctx): + return self.visit(ctx.expr()) + + def visitCall(self, ctx: QueryParser.CallContext): + to_call = self.visit(ctx.expr(0)) + args = [self.visit(arg) for arg in ctx.getChildren(lambda x: isinstance(x, QueryParser.ExprContext))][1:] + return to_call(*args) + + def visit(self, tree): + return super(MyQueryVisitor, self).visit(tree) + + +def parse(text, **kwargs): + parser = QueryParser(CommonTokenStream(QueryLexer(InputStream(text)))) + tree = parser.prog() + visitor = MyQueryVisitor(parser) + for key, value in kwargs.items(): + visitor.memory[key] = value + return visitor.for_result(tree) + + +if __name__ == '__main__': + with open('debug.txt') as handle: + content = handle.read() + print(parse(content)) |