rise2es5.py 11.6 KB
Newer Older
Ilya Prokhorov's avatar
Ilya Prokhorov committed
1 2 3
import sys
import os
import re
4
from sets import Set
Ilya Prokhorov's avatar
Ilya Prokhorov committed
5 6 7 8 9

print("Rise to ECMAScript 5 transpiler")

def transpale(line, className):
    
10
    global entityType, classDeclarations, methodDeclarations
11
    
Ilya Prokhorov's avatar
Ilya Prokhorov committed
12 13 14 15
    outputLine = line
    
    classMatch = re.match(r'class ([a-zA-Z]*)', line, re.M|re.I)
    if classMatch != None:
16 17 18
        
        classDeclarations = Set()
        
Ilya Prokhorov's avatar
Ilya Prokhorov committed
19
        className = classMatch.group(1)
20 21 22
        
        entityType = "class"
        
Ilya Prokhorov's avatar
Ilya Prokhorov committed
23
        return "function " + className + "()\n"
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

    protocolMatch = re.match(r'protocol ([a-zA-Z]*)', line, re.M|re.I)
    if protocolMatch != None:
        protocolName = protocolMatch.group(1)
        
        entityType = "protocol"
        
        return "function " + protocolName + "()\n"
    
    builtinPrintMatch = re.match(r'(.*)RiseBuiltInMethods\.print\((.*)\)', line, re.M|re.I)
    if builtinPrintMatch != None:
        prefix = builtinPrintMatch.group(1)
        arguments = builtinPrintMatch.group(2)
        return prefix + "console.log(" + arguments + ");\n"
    
    builtinMapClassMatch = re.match(r'(.*) = RiseBuiltInClasses\.Map.*', line, re.M|re.I)
    if builtinMapClassMatch != None:
        prefix = builtinMapClassMatch.group(1)
        return prefix + " = {};\n"
43 44 45 46 47

    builtinListClassMatch = re.match(r'(.*) = RiseBuiltInClasses\.List.*', line, re.M|re.I)
    if builtinListClassMatch != None:
        prefix = builtinListClassMatch.group(1)
        return prefix + " = [];\n"
Ilya Prokhorov's avatar
Ilya Prokhorov committed
48 49 50
    
    methodMatch = re.match(r'(.*) (method) ([a-zA-Z]*)\((.*)\)', line, re.M|re.I)
    if methodMatch != None:
51 52 53
        
        methodDeclarations = Set()
        
Ilya Prokhorov's avatar
Ilya Prokhorov committed
54 55 56 57 58 59 60 61 62 63 64
        methodName = methodMatch.group(3)
        arguments = methodMatch.group(4)
        print(methodName)
        print(arguments)
        
        parsedArguments = []
        
        argumentsMatches = re.findall(r'([a-zA-Z]*) :', line, re.M|re.I)
        for argumentsMatch in argumentsMatches:
            print(argumentsMatch)
            parsedArguments.append(argumentsMatch)
65
            methodDeclarations.add(argumentsMatch)
Ilya Prokhorov's avatar
Ilya Prokhorov committed
66
        
67 68
        print("parsedArguments:" + str(parsedArguments))
        
Ilya Prokhorov's avatar
Ilya Prokhorov committed
69 70 71 72
        if className == "main":
            prefix = "var "
        else:
            prefix = "\tthis."
73 74
            
        postfix = ""
Ilya Prokhorov's avatar
Ilya Prokhorov committed
75
        
76 77 78
        if entityType == "protocol":
            postfix = " {}"
        
79 80 81 82
        transpiledString = prefix + methodName + " = function("+ ", ".join(parsedArguments) +")" + postfix + "\n"
        print("transpiledString: " + transpiledString)
        
        return transpiledString
Ilya Prokhorov's avatar
Ilya Prokhorov committed
83 84 85 86 87
    
    classVariableDeclarationMatch = re.match(r'(.*) (declare) ([a-zA-Z]*) .*', line, re.M|re.I)
    if classVariableDeclarationMatch != None:
        classVariable = classVariableDeclarationMatch.group(3)
        
88 89
        classDeclarations.add(classVariable)
        
Ilya Prokhorov's avatar
Ilya Prokhorov committed
90 91 92 93 94 95 96 97
        return "\tthis." + classVariable + " = null;\n"
    
    localVariableDeclarationMatch = re.match(r'(.*)(declare) ([a-zA-Z]*)(.*)', line, re.M|re.I)
    if localVariableDeclarationMatch != None:
        space = localVariableDeclarationMatch.group(1)
        localVariable = localVariableDeclarationMatch.group(3)
        value = localVariableDeclarationMatch.group(4)
        
98 99
        methodDeclarations.add(localVariable)
        
100 101 102 103 104 105 106 107 108 109 110 111 112 113
        return space + "var " + localVariable + value + ";\n"
        
    methodCallMatch = re.match(r'(.*)(\(.*\))', line, re.M|re.I)
    if methodCallMatch != None:
        prefix = methodCallMatch.group(1)
        
        formattedString = line.replace("\t", "")
        formattedString = formattedString.replace("\n", "")
        
        if len(formattedString) < 4:
            return line
        
        if formattedString[:3] == "if ":
            return line
Ilya Prokhorov's avatar
Ilya Prokhorov committed
114
        
115 116 117 118 119 120 121 122 123
        if formattedString[:4] == "for":
            return line
        
        arguments = methodCallMatch.group(2)
        print(prefix)
        print(arguments)
        
        parsedArguments = []
        
124
        argumentsMatches = re.findall(r' : ([" a-zA-Z0-9]*)', line, re.M|re.I)
125 126
        for argumentsMatch in argumentsMatches:
            print(argumentsMatch)
127 128 129 130
            
            if argumentsMatch in classDeclarations:
                argumentsMatch = "this." + argumentsMatch
            
131 132 133 134 135
            parsedArguments.append(argumentsMatch)
        
        if len(parsedArguments) < 1:
            return line
        
136 137 138 139
        transpiledString = prefix + "("+ ", ".join(parsedArguments) +");\n"
        print("transpiled method call: " + transpiledString)
        
        return transpiledString
140
                
Ilya Prokhorov's avatar
Ilya Prokhorov committed
141 142 143
    formattedLine = line.replace("\t","")
    formattedLine = formattedLine.replace("\n", "") 
    
144
    if len(formattedLine) > 1 and formattedLine[:4] != "else":
Ilya Prokhorov's avatar
Ilya Prokhorov committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158
        return line[:len(line) - 1] + ";\n"
    
    return line

if len(sys.argv) < 2:
    print("Not enough arguments: " + str(sys.argv))
    print("Command: python rise2es5.py [Sources Directory] [Output ES5 file]")
    print("Example: python rise2es5.py src /usr/user/sources/app/riseLibrary.es5")
    
sourceDirectory = sys.argv[1]
outputFilePath = sys.argv[2]
    
buffer = ""

159
entityType = None
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
classDeclarations = Set()
methodDeclarations = Set()

def addScopeToDeclarations(line):
    
    global classDeclarations, methodDeclarations
    
    allowedList = ["this", "console", "globalTapController", "globalMainController", "window"]
    
    if "framesCounter += 1" in line:
        print("stop")
    
    variableCallMatch = re.match(r'\t*([a-zA-Z]*)\.', line, re.M|re.I)
    if variableCallMatch != None:
        variableCall = variableCallMatch.group(1)
        print("scope for variable: " + variableCall)
        
        if variableCall in allowedList:
            pass
        
        elif variableCall in classDeclarations:
            line = re.sub(r'(\t*)([a-zA-Z]*)\.', r'\1this.\2.', line, 1)
            
            return line
        
        elif variableCall not in methodDeclarations:
186 187
            print("warning for line: " + line + "; no declaration '" + variableCall + "' in class or method")
            #exit(1)
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204

    variableCallMatch = re.match(r'\t*([a-zA-Z]*)\[', line, re.M|re.I)
    if variableCallMatch != None:
        variableCall = variableCallMatch.group(1)
        print("scope for variable: " + variableCall)
        
        if variableCall in allowedList:
            pass
        
        elif variableCall in classDeclarations:
            line = re.sub(r'(\t*)([a-zA-Z]*)\[', r'\1this.\2[', line, 1)
            
            return line
        
        elif variableCall not in methodDeclarations:
            print("error for line: " + line + "; no declaration '" + variableCall + "' in class or method")
            exit(1)
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
        
    variableCallMatch = re.match(r'\t*([a-zA-Z]*) =', line, re.M|re.I)
    if variableCallMatch != None:
        variableCall = variableCallMatch.group(1)
        print("scope for variable: " + variableCall)
        
        if variableCall in allowedList:
            pass
        
        elif variableCall in classDeclarations:
            line = re.sub(r'(\t*)([a-zA-Z]*) =', r'\1this.\2 = ', line, 1)
            
            return line
        
        elif variableCall not in methodDeclarations:
            print("error for line: " + line + "; no declaration '" + variableCall + "' in class or method")
            exit(1)
    
    variableCallMatch = re.match(r'\t*if \(([a-zA-Z]*)\.', line, re.M|re.I)
    if variableCallMatch != None:
        variableCall = variableCallMatch.group(1)
        print("scope for variable: " + variableCall)
        
        if variableCall in allowedList:
            pass
        
        elif variableCall in classDeclarations:
            line = re.sub(r'(\t*if \()([a-zA-Z]*)\.', r'\1this.\2.', line, 1)
            
            return line
        
        elif variableCall not in methodDeclarations:
            print("error for line: " + line + "; no declaration '" + variableCall + "' in class or method")
            exit(1)     

    variableCallMatch = re.match(r'\t*if \(([a-zA-Z]*) ', line, re.M|re.I)
    if variableCallMatch != None:
        variableCall = variableCallMatch.group(1)
        print("scope for variable: " + variableCall)
        
        if variableCall in allowedList:
            pass
        
        elif variableCall in classDeclarations:
            line = re.sub(r'(\t*if \()([a-zA-Z]*) ', r'\1this.\2 ', line, 1)
            
            return line
        
        elif variableCall not in methodDeclarations:
            print("error for line: " + line + "; no declaration '" + variableCall + "' in class or method")
            exit(1)     
        
    variableCallMatch = re.match(r'\t*return ([a-zA-Z]*)\.', line, re.M|re.I)
    if variableCallMatch != None:
        variableCall = variableCallMatch.group(1)
        print("scope for variable: " + variableCall)
        
        if variableCall in allowedList:
            pass
        
        elif variableCall in classDeclarations:
            line = re.sub(r'(\t*return )([a-zA-Z]*)\.', r'\1this.\2.', line, 1)
            
            return line
        
        elif variableCall not in methodDeclarations:
            print("error for line: " + line + "; no declaration '" + variableCall + "' in class or method")
            exit(1)          

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
    variableCallMatch = re.match(r'\t*return ([a-zA-Z]*)\[', line, re.M|re.I)
    if variableCallMatch != None:
        variableCall = variableCallMatch.group(1)
        print("scope for variable: " + variableCall)
        
        if variableCall in allowedList:
            pass
        
        elif variableCall in classDeclarations:
            line = re.sub(r'(\t*return )([a-zA-Z]*)\[', r'\1this.\2[', line, 1)
            
            return line
        
        elif variableCall not in methodDeclarations:
            print("error for line: " + line + "; no declaration '" + variableCall + "' in class or method")
            exit(1)

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
    variableCallMatch = re.match(r'\t*return ([a-zA-Z]*)\;', line, re.M|re.I)
    if variableCallMatch != None:
        variableCall = variableCallMatch.group(1)
        print("scope for variable: " + variableCall)
        
        if variableCall in allowedList:
            pass
        
        elif variableCall in classDeclarations:
            line = re.sub(r'(\t*return )([a-zA-Z]*)\;', r'\1this.\2;', line, 1)
            
            return line
        
        elif variableCall not in methodDeclarations:
            print("error for line: " + line + "; no declaration '" + variableCall + "' in class or method")
            exit(1)          

    variableCallMatch = re.match(r'\t*([a-zA-Z]*)\ ', line, re.M|re.I)
    if variableCallMatch != None:
        variableCall = variableCallMatch.group(1)
        print("scope for variable: " + variableCall)
        
        if len(variableCall) < 1:
            pass
        
        elif variableCall in allowedList:
            pass
        
        elif variableCall in classDeclarations:
            line = re.sub(r'(\t*)([a-zA-Z]*)\ ', r'\1this.\2 ', line, 1)
            
            return line        
        
    return line
325

326
for root, dirs, files in os.walk(sourceDirectory, followlinks=True):
Ilya Prokhorov's avatar
Ilya Prokhorov committed
327 328 329
    for file in files:
        if file.endswith(".rise"):
            
330 331
            entityType = None
            
Ilya Prokhorov's avatar
Ilya Prokhorov committed
332 333 334 335 336 337 338 339
            filePath = os.path.join(root, file) 
            
            className = file[:len(file) - len(".rise")]
            
            print(filePath)
            
            file = open(filePath, 'r')
            for line in file:
340
                buffer = buffer + addScopeToDeclarations(transpale(line, className))
Ilya Prokhorov's avatar
Ilya Prokhorov committed
341 342 343 344 345 346 347 348
                
            buffer = buffer + "\n\n"
            
print(buffer)

file = open(outputFilePath, 'w')
file.write(buffer)