Commits

Ahmed Youssef  committed 1297a66

ast, codevisitor

  • Participants
  • Parent commits 9935fbf

Comments (0)

Files changed (3)

File pykid/kidast.py

 class Program(Node):
     def __init__(self, stmtlist):
         self.stmtlist=stmtlist
+        
+    def visit(self, visitor):
+        return visitor.visitProgram(self)
+        
+    def printme(self, level=0):
+        print " "*level+"program node"
+        print " " *level + "stmts: ", self.stmtlist
+    
+    
+class Innerblock(Node):
+    def __init__(self, stmtlist):
+        self.stmtlist=stmtlist
+        
+    def printme(self, level=0):
+        print " "*level + "innerblock node"
+        print " " *level + "stmts: ", self.stmtlist
+        
+    def visit(self, visitor):
+        return visitor.visitInnerblock(self)
+        
+        
+class Stmt(Node):
+    pass
 
-class Funccall(Node):
-    def __init__(self, name, args):
-        self.name=name
-        self.args=args
+class IfStmt(Node):
+    def __init__(self, cond, block):
+        self.cond=cond
+        self.block=block
         
-class Funcdef(Node):
+    def printme(self, level=0):
+        print " " * level + "If Stmt"
+        print " " * (level+1) + "Condition: "
+        self.cond.printme(level+1)
+        print " " * (level+1) + "Innerblock: "
+        self.block.printme(level+1)
+        
+    def visit(self, visitor):
+        return visitor.visitIfStmt(self)
+        
+class IfElseStmt(Node):
+    def __init__(self, cond, ifblock, elseblock):
+        self.cond=cond
+        self.ifblock=ifblock
+        self.elseblock=elseblock
+        
+    def printme(self, level=0):
+        print " " * level + "IfElse Stmt"
+        self.cond.printme(level+1)
+        self.ifblock.printme(level+1)
+        self.elseblock.printme(level+1)
+        
+    def visit(self, visitor):
+        return visitor.visitIfElseStmt(self)
+        
+class WhileStmt(Node):
+    def __init__(self, cond, block):
+        self.cond=cond
+        self.block=block
+        
+        
+    def printme(self, level=0):
+        print " " * level + "While Stmt"
+        self.cond.printme(level+1)
+        self.block.printme(level+1)
+
+    def visit(self, visitor):
+        return visitor.visitWhileStmt(self)
+        
+class ForeachStmt(Node):
+    def __init__(self, var, container, block):
+        self.var=var
+        self.container=container
+        self.block=block
+        
+    def printme(self, level=0):
+        print " " * level + "Foreach Stmt"
+        #self.var.printme(level+1)
+        #self.container.printme(level+1)
+        self.block.printme(level+1)
+
+    def visit(self, visitor):
+        return visitor.visitForeachStmt(self)
+        
+class FuncDefStmt(Node):
     def __init__(self, name, args, body):
         self.name=name
         self.args=args
         self.body=body
         
+    def printme(self, level=0):
+        print " "*level + "Funcdef stmt"
+        self.name.printme(level+1)
+        self.body.printme(level+1)
+        
+    def visit(self, visitor):
+        return visitor.visitFuncDefStmt(self)
+        
+class VarDefStmt(Node):
+    def __init__(self, varname, value):
+        self.varname=varname
+        self.value=value
+        
+    def printme(self, level):
+        print " "*level + "Vardef "
+        self.varname.printme(level+1)
+        self.value.printme(level+1)
+      
+    def visit(self, visitor):
+        return visitor.visitVarDefStmt(self)
+        
+class FuncCallExpression(Node):
+    def __init__(self, name, args):
+        self.name=name
+        self.args=args
+    
+    def printme(self, level=0):
+        print " "*level + "FuncCall"
+        self.name.printme(level+1)
+        print self.args.printme(level+1)
+        
+    def visit(self, visitor):
+        return visitor.visitFuncCallExpression(self)
+        
+class ArgumentsList(Node):
+    def __init__(self, args):
+        self.args=args
+        
+    def printme(self, level=0):
+        print " "*level + "arguments: "
+        for el in self.args:
+            el.printme(level+1)
 
-class BinaryNode(Node):
+class Expression(Node):
+    def __init__(self, expr):
+        self.expr=expr
+        
+    def visit(self, visitor):
+        return self.visitExpression(self)
+
+class BinaryExpression(Node):
     def __init__(self, l, op, r):
         self.left=l
         self.op=op
-        self.r=op
+        self.right=r
         
+    def printme(self, level=0):
+        print " "*level + "BinaryExpression on OP"+self.op
+        self.left.printme(level+1)
+        self.right.printme(level+1)
+
+    def visit(self, visitor):
+        return visitor.visitBinaryExpression(self)
         
-class VardefNode(Node):
-    def __init__(self, varname, value):
-        self.varname=varname
-        self.value=value
-      
+class Number(Node):
+    def __init__(self, num):
+        self.value=num
 
+    def printme(self, level=0):
+        print " " * level + "Number: ", self.value
+        
+    def visit(self, visitor):
+        return visitor.visitNumber(self)
+        
+class String(Node):
+    def __init__(self, string):
+        self.value=string
+
+    def printme(self, level=0):
+        print " " * level + "String: ", self.value
+        
+    def visit(self, visitor):
+        return visitor.visitString(self)
+        
+class Identifier(Node):
+    def __init__(self, identifier):
+        self.value=identifier
+        
+    def printme(self, level=0):
+        print " " * level + "IDENTIFIER: ", self.identifier
+
+    def visit(self, visitor):
+        return visitor.visitIdentifier(self)
+        
 if __name__=="__main__":
-    pass
+    pass

File pykid/parser.py

 '''
 from ply import yacc
 from lexer import *
-#program : blocks
-#blocks: block*
-#block: statements
-#statements: statement*
-#statement: expr | funccall | funcdef
-#funccall: ID(argslist)(.funcall(argslist)*)
-#argslist
-#expr: term + expr
-#    |  term - expr
-#term: factor * term
-#    | factor / term
-#factor: NUMBER
-#      | ID
+from pythoncodegen import *
+from kidast import *
 
-
-    
 precedence = (
     ('left','PLUS','MINUS'),
     ('left','TIMES','DIVIDE'),
-    ('right','UMINUS'),
+   # ('right','UMINUS'),
 )
 
-def p_block(p):
-    """block : stmtlist
-             | innerblock
+def p_program(p):
+    """program : stmtlist
     """
-    print p[1]
-    p[0]=None
+    p[0]=Program(p[1])
+    #p[0]=('PROGRAM', p[1])
     
 def p_innerblock(p):
     """innerblock : LBRACE stmtlist RBRACE
-                 | LBRACE RBRACE
+                  | 
     """
-    p[0]=('INNERBLOCK', p[2])
+    p[0]=Innerblock(p[2])
     
 def p_stmtlist(p):
-    """stmtlist : stmtlist SEMICOLON stmt
-                | stmt
+    """stmtlist : stmt stmtlist
+                | 
     """
     #print type(p)
     stmtlist=[]
     if len(p)==2:
         stmtlist.append(p[1])
-    else:
-        for el in [p[1], p[3]]:
+    elif len(p)>2:
+        for el in [p[1], p[2]]:
             if isinstance(el, list):
                 stmtlist.extend(el)
             else:
     #for s in stmtlist: 
     #    print s, type(s)
     
-    stmts = [ x for x in stmtlist] #if x is not None]
-    print "stmtslist", stmts
-    #print "codeblock"
-    p[0]=stmts
+    #stmts = [ x for x in stmtlist] #if x is not None]
+    p[0]=stmtlist
     
 
-def p_stmt_funccall(p):
+
+def p_stmt(p):
+    """stmt : funcdef    
+            | whilestmt
+            | foreachstmt
+            | ifelsestmt 
+            | ifstmt     
+            | vardef  
+            | qexpr     
+            | 
     """
-        stmt : ID LPAREN argslist RPAREN
+    if len(p)>1:
+        p[0]=p[1]
+    else:
+        p[0]=None
+        
+def p_while(p):
     """
-    funcname=p[1]
-    argslist=p[3]
-    print "calling func: ", funcname
-    print "with args: ", argslist
-    p[0]=('FUNCCALL', funcname, argslist)
+        whilestmt : WHILE LPAREN qexpr RPAREN innerblock
     
+    """
+    p[0]=WhileStmt(p[3], p[5])
+    
+def p_foreach(p):
+    """
+        foreachstmt : FOREACH LPAREN qexpr COLON qexpr RPAREN innerblock
+    """
+    p[0]=ForeachStmt(p[3], p[5], p[7])
+def p_ifelse(p):
+    """
+        ifelsestmt : IF LPAREN qexpr RPAREN innerblock ELSE innerblock
+    
+    """
+    p[0]=IfElseStmt(p[3], p[5], p[7])
+    
+def p_if(p):
+    """
+        ifstmt : IF LPAREN qexpr RPAREN innerblock
+    
+    """
+    p[0] = IfStmt(p[3], p[5])
+    
+def p_funcdef(p):
+    """funcdef : ID LPAREN argslist RPAREN EQUALS FUNCTION innerblock
+    """
+    fname=p[1]
+    args=p[3]
+    innerblock=p[7]
+    p[0]=FuncDefStmt(Identifier(fname), ArgumentsList(args), innerblock)
 
+def p_vardef(p):
+    """
+        vardef : DEF ID EQUALS qexpr
+    """
+    p[0]=VarDefStmt(Identifier(p[2]), p[4])
+    
+def p_expr_funccall(p):
+    """
+        qexpr : ID LPAREN argslist RPAREN
+    """
+    funcname=Identifier(p[1])
+    argslist=ArgumentsList(p[3])
+    p[0]=FuncCallExpression(funcname, argslist)
+    
+    
 def p_argslist(p):
+    #FIXME first rule argslist COMMA 
     """
-        argslist : argslist COMMA expr
-                | expr
+        argslist : qexpr COMMA argslist
+                | innerblock COMMA argslist
+                | qexpr
+                | innerblock
                 |
     """ 
     args=[]
     if len(p)==1:
         p[0]=args
-        return
 
-    if len(p)==2:
+
+    elif len(p)==2:
         args.append(p[1])
     else:
         for el in [p[1], p[3]]:
                 args.append(el)
     p[0]=args
 
-def p_funcdef(p):
-    """funcdef : ID LPAREN argslist RPAREN EQUALS FUNCTION innerblock
+
+def p_qexpr(p):
     """
-    print "lenp:", len(p)
-    fname=p[1]
-    print "fname: ", fname
-    args=p[3]
-    print "with params:", args
-    innerblock=p[7]
-    p[0]=('FUNC', innerblock)
+        qexpr : qexpr PLUS qexpr
+              | qexpr MINUS qexpr
+              | qexpr TIMES qexpr
+              | qexpr DIVIDE qexpr
+              | qexpr EQ qexpr
+              | qexpr NE qexpr
+              | qexpr GT qexpr
+              | qexpr LT qexpr
+              | qexpr GE qexpr
+              | qexpr LE qexpr
+ 
 
-def p_stmt_funcdef(p):
-    """stmt : funcdef"""
-    p[0]=p[1]
-def p_stmt_expr(p):
-    'stmt : expr'
-    p[0] = p[1]
+    """
+    p[0]= BinaryExpression(p[1], p[2], p[3])
+    
+def p_qexpr_paren(p):
+    """
+        qexpr : LPAREN qexpr RPAREN
+              |
+    """
+    p[0]=Expression(p[2])
+    
+def p_qexpr_id(p):
+    "qexpr : ID"
+    p[0]=Identifier(p[1])
+    
+def p_qexpr_val(p):
+    """qexpr : STRING"""
+             
+    p[0]=String("'"+str(p[1])+"'") #quote strings
 
-def p_stmt(p):
-    'stmt : '
+def p_qexpr_num(p):
+    """qexpr : NUMBER"""
+    p[0]=Number(int(p[1]))
 
-def p_expression_uminus(p):
-    "expr : '-' expr %prec UMINUS"
-    p[0] = -p[2]
-    
-def p_expression_plus(p):
-    'expr : expr PLUS term'
-    p[0] = p[1] + p[3]
-
-def p_expression_minus(p):
-    'expr : expr MINUS term'
-    p[0] = p[1] + p[3]
-    
-def p_expression_term(p):
-    'expr : term'
-    p[0] = p[1]
-#
-def p_factor_variable(p):
-    'factor : ID'
-    p[0]=p[1]
-def p_term_times(p):
-    'term : term TIMES factor'
-    p[0] = p[1] * p[3]
-    
-def p_term_div(p):
-    'term : term DIVIDE factor'
-    p[0] = p[1] / p[3]
-    
-def p_term_factor(p):
-    'term : factor'
-    p[0] = p[1]
-    
-def p_factor_number(p):
-    'factor : NUMBER'
-    p[0] = p[1]
-
-def p_factor_expr(p):
-    'factor : LPAREN expr RPAREN'
-    p[0] = p[2]
     
 def p_error(p):
     print "Syntax error"
 
+
 if __name__=="__main__":
-    #line="{1+20 + (3+2)*5 ;  3+5; 6+1;}"
-    #line="{ print(5,3,6+6) ; 1+2; 5+2}"
-    line="f(x,y)=function{print(3)}"
+
+    script="""
+    def name='ahmed'
+    if(name=='ahmed'){
+        print('you can comin')
+    } 
+    
+    if(1==0){
+        print('you dont know math?')
+    }else{
+        print('you know math...')
+    }
+    
+    def x=0
+    while(x<10){
+        def y=0
+        while(y<5){
+            print('less than 5')
+            def y=y+1
+        }
+        print('okay')
+        def x = x+1
+    }
+    
+    sum(x,y)=function{
+    
+        logme()=function{
+            print('summing x,y',x,y)
+        
+        }
+        
+        return(x+y)
+    
+    }
+    def xs='helloworld'
+    foreach(x : xs){
+        print(x)
+    }
+    
+"""
     p=yacc.yacc()
-    p.parse(line, debug=False)
-    
+    #p=p.parse(script, debug=False)
+    s="""
+    print(1+2)
+    def x=3
+    def y=4
+    callme(3)
+    sum(x,y)=function{ return(x+y) }
+    foreach(x : xs){
+        print('x', x)
+    }
+    
+    if('name'=='ahmed'){
+        print('welcome ahmed')
+    }
+    """
+    l="""
+    
+    def x = 1
+    def y = 2
+    if(x==1){
+        print('true')
+        if(y<2){
+            print('y less than 2')
+        }
+        if(x==1){
+        print('one')
+		}else{
+			print('not one')
+		}
+    }
+	while(x<10){
+		print('less than 10')
+		def x = x+1
+	
+	}
+    def xs='helloworld'
+    foreach(x : xs){
+        print(x)
+    }
+    def j=3
+    def x=(55+23)*(4+3)
+    """
+    p=p.parse(l, debug=False)
+    v=Visitor()
+    pycode=v.visitProgram(p)
+    print "PYCODE: >>>\n", pycode, "<<<"
+    exec(pycode)
+

File pykid/pythoncodegen.py

+from kidast import *
+class Visitor(object):
+    
+    def __init__(self):
+        self.code=""
+        self.level=0
+        
+    def visitProgram(self, node):
+        stmts=node.stmtlist
+        self.code=self.visitStmtlist(stmts)
+        return self.code
+  
+    def visitInnerblock(self, node):
+        self.start_block()
+        code=self.visitStmtlist(node.stmtlist)
+        self.end_block()
+        return code
+    
+    def visitStmtlist(self, stmts):
+
+        mycode=""
+        for s in stmts:
+            code =self.visitStmt(s)
+            if code is not None:
+                mycode +=code 
+                
+        return mycode
+    
+    def visitStmt(self, s):
+        res=None
+        mycode=""
+        if isinstance(s, IfStmt):
+            res=self.visitIfStmt(s)
+        elif isinstance(s, IfElseStmt):
+            res=self.visitIfElseStmt(s)
+        elif isinstance(s, WhileStmt):
+            res=self.visitWhileStmt(s)
+        elif isinstance(s, ForeachStmt):
+            res=self.visitForeachStmt(s)
+        elif isinstance(s, VarDefStmt):
+            res=self.visitVarDefStmt(s)
+        elif isinstance(s, FuncDefStmt):
+            res=self.visitFuncDefStmt(s)
+        #FUNCTION CALL ARE STATEMENTS AS WELL
+        elif isinstance(s, FuncCallExpression):
+            res=self.visitFuncCallExpression(s)
+        if res is not None:
+            mycode +=res + "\n"
+        
+        return res
+        
+    def start_block(self):
+        self.level +=4
+        
+    def end_block(self):
+        self.level -=4
+        
+    def visitIfStmt(self, node):
+        code=""
+        cond=self.visitExpression(node.cond)
+        
+        ifblock=self.visitInnerblock(node.block)  
+        #node.block.printme()
+        #print "IFBLOCK: ==>", node.block.stmtlist.stmts, "<<<<"
+        code += " "*self.level + "if "+ cond + " : \n"
+        code +=ifblock
+        #self.level -=1
+        
+        return code
+    
+    def visitIfElseStmt(self, node):
+        code=""
+        cond=self.visitExpression(node.cond)
+        
+        ifblock=self.visitInnerblock(node.ifblock)  
+        elseblock=self.visitInnerblock(node.elseblock)
+        code += " "*self.level + "if "+ cond + " : \n"
+        code +=ifblock
+        code +=" "*self.level + "else :\n" +elseblock
+        
+        return code
+    
+    def visitWhileStmt(self, node):
+        code=""
+        cond=self.visitExpression(node.cond)
+        
+        whileblock=self.visitInnerblock(node.block)  
+        code += " "*self.level + "while "+ cond + " : \n"
+        code +=whileblock
+        
+        return code
+    
+    def visitForeachStmt(self, node):
+        code=""
+        var=self.visitExpression(node.var)
+        container=self.visitExpression(node.container)
+        block=self.visitInnerblock(node.block)  
+        code += " "*self.level + "for "+ var + " in "+container+ " : \n"
+        code +=block
+        
+        return code
+    
+        
+    def visitFuncDefStmt(self, node):
+        lvl=self.level
+        funcname = self.visitIdentifier(node.name)
+        args = node.args.args #argslist.args
+        fblock = self.visitInnerblock(node.body)
+        code=""
+        code +="\n"+" "*lvl +"def "+funcname+"(" + ",".join(args) + ")"+ ":\n"
+        code +=fblock
+        
+        return code
+    def visitVarDefStmt(self, node):
+        lvl=self.level
+        var=self.visitIdentifier(node.varname)
+        val=self.visitExpression(node.value)
+        code = " "*lvl + var + " = " + str(val) + "\n"
+        return code
+    
+    def visitFuncCallExpression(self, node):
+        lvl=self.level
+        name=self.visitIdentifier(node.name)
+        args=node.args.args
+        args = ",".join(str(self.visitExpression(x)) for x in args)
+        code =""
+        code += " "*lvl + name + "(" + args + ")" +"\n"
+        return code 
+    
+    def visitExpression(self, node):
+        if isinstance(node, Expression):
+            return self.visitExpression(node.expr)
+        if isinstance(node, Number):
+            return self.visitNumber(node)
+        elif isinstance(node, String):
+            return self.visitString(node)
+        elif isinstance(node, Identifier):
+            return self.visitIdentifier(node)
+        elif isinstance(node, FuncCallExpression):
+            return self.visitFuncCallExpression(node)
+        elif isinstance(node, BinaryExpression):
+            return self.visitBinaryExpression(node)
+    
+    def visitBinaryExpression(self, node):
+        
+        l=self.visitExpression(node.left)
+        r=self.visitExpression(node.right) #recursive
+        op=node.op
+        code=""
+        code += "(" + str(l) + op + str(r) + ")"
+        return code 
+    
+    def visitNumber(self, node):
+        return node.value
+    
+    def visitString(self, node):
+        return node.value
+    
+    def visitIdentifier(self, node):
+        return node.value
+    
+