def __init__(self): self.grammarParser = GrammarParser() self.loader = Loader() self.lexer = Lexer() self.parser = Parser() self.checker = Checker() self.genFactory = GenFactory() # compile grammar rules self.grammarParser.compileGrammar() self.compiledModules = {}
def setUp(self): self.lexer = Lexer() self.lines_re = re.compile('\n')
class LexerTest(unittest.TestCase): def setUp(self): self.lexer = Lexer() self.lines_re = re.compile('\n') def tokensToWords(self, tokens): return [token.word for token in tokens] def tokensToWordtypes(self, tokens): return [token.wordtype for token in tokens] def checkWordsWordtypes(self, code, expectedWords, expectedWordtypes): lines = self.lines_re.split(code) source = Source('test.mut', lines, []) self.assertEqual(source.tokens, None) self.lexer.parseSource(source) actualWords = self.tokensToWords(source.tokens) actualWordtypes = self.tokensToWordtypes(source.tokens) self.assertListEqual(actualWords, expectedWords) self.assertListEqual(actualWordtypes, expectedWordtypes) def testParseSource(self): data = [ # Variable [ """ bool flag = true; """, ['bool', 'flag', '=', 'true', ';'], ['bool', 'name', '=', 'litbool', ';'], ], [ """ int num = 32; """, ['int', 'num', '=', '32', ';'], ['int', 'name', '=', 'litint', ';'], ], [ """ float num = 32.54; """, ['float', 'num', '=', '32.54', ';'], ['float', 'name', '=', 'litfloat', ';'], ], [ """ string label = 'User label'; """, ['string', 'label', '=', "'User label'", ';'], ['string', 'name', '=', 'litstring', ';'], ], [ """ App app = App(); """, ['App', 'app', '=', 'App', '(', ')', ';'], ['name', 'name', '=', 'name', '(', ')', ';'], ], [ """ tasker.App app = App(); """, ['tasker.App', 'app', '=', 'App', '(', ')', ';'], ['name', 'name', '=', 'name', '(', ')', ';'], ], # Select from [ """ var openMessages = select from messages where status is TaskStatus.OPEN; """, ['var', 'openMessages', '=', 'select', 'from', 'messages', 'where', 'status', 'is', 'TaskStatus.OPEN', ';'], ['var', 'name', '=', 'select', 'from', 'name', 'where', 'name', 'is', 'name', ';'], ], # Select concat [ """ var messages = select concat newMessages, openMessages; """, ['var', 'messages', '=', 'select', 'concat', 'newMessages', ',', 'openMessages', ';'], ['var', 'name', '=', 'select', 'concat', 'name', ',', 'name', ';'], ], # Tag [ """ tag content = <div class=['item', 'foo']></div>; """, ['tag', 'content', '=', '<', 'div', 'class', '=', '[', "'item'", ',', "'foo'", ']', '>', '</', 'div', '>', ';'], ['tag', 'name', '=', '<', 'name', 'class', '=', '[', 'litstring', ',', 'litstring', ']', '>', '</', 'name', '>', ';'], ], # Function [ """ int main() { return 0; } """, ['int', 'main', '(', ')', '{', 'return', '0', ';', '}'], ['int', 'name', '(', ')', '{', 'return', 'litint', ';', '}'], ], [ """ (string[] messages) { map(messages, renderMessage); } """, ['(', 'string', '[', ']', 'messages', ')', '{', 'map', '(', 'messages', ',', 'renderMessage', ')', ';', '}'], ['(', 'string', '[', ']', 'name', ')', '{', 'map', '(', 'name', ',', 'name', ')', ';', '}'], ], # Enum [ """ enum TaskStatus { NEW = 1; OPEN = 2; } """, ['enum', 'TaskStatus', '{', 'NEW', '=', '1', ';', 'OPEN', '=', '2', ';', '}'], ['enum', 'name', '{', 'name', '=', 'litint', ';', 'name', '=', 'litint', ';', '}'], ], # Struct [ """ struct Task { string id; string name; } """, ['struct', 'Task', '{', 'string', 'id', ';', 'string', 'name', ';', '}'], ['struct', 'name', '{', 'string', 'name', ';', 'string', 'name', ';', '}'], ], # Class [ """ class App { () { } } """, ['class', 'App', '{', '(', ')', '{', '}', '}'], ['class', 'name', '{', '(', ')', '{', '}', '}'], ], ] for code, expectedWords, expectedWordtypes in data: self.checkWordsWordtypes(code, expectedWords, expectedWordtypes)
class Compiler(object): def __init__(self): self.grammarParser = GrammarParser() self.loader = Loader() self.lexer = Lexer() self.parser = Parser() self.checker = Checker() self.genFactory = GenFactory() # compile grammar rules self.grammarParser.compileGrammar() self.compiledModules = {} def compile(self, srcPaths, moduleName): """ Create mutant lang source code tree. Load module and all referenced modules. Tokenize and parse source code. Always cache modules by moduleName (import name). output: module - common.Module instance. """ # check if moduleName already compiled if moduleName in self.compiledModules: return self.compiledModules[moduleName] self.loader.setPaths(srcPaths) # loader, lexer and parser all change module object mainModule = self.loader.loadModule(moduleName) # parse each module in lexer.modules cache for name, module in self.loader.modules.items(): # check cache if name in self.compiledModules: continue self.lexer.parse(module) self.parser.parse(module) # check and set functioncall as constructor for name, module in self.loader.modules.items(): self.markConstructors(module) # check and add module to cache for name, module in self.loader.modules.items(): self.checker.check(module) self.compiledModules[name] = module return mainModule def mutate(self, module, destPath, genName): """ Translate module and referenced modules to genName language modules. Create generated module sources formatted. Save generated sources to disk. """ gen = self.genFactory.createGen(genName) def save(self, filename, lines): with open(filename, 'w') as f: f.writelines(lines) def markConstructors(self, module): """ Find and mark constructor among functioncall nodes """ # find in variables body for name, va in module.variables.items(): self.markConstructorInVariable(module, va) # find in functions for name, fn in module.functions.items(): self.markConstructorInNodes(module, fn.bodyNodes) for cn, cl in module.classes.items(): # find in class variables body for name, va in cl.variables.items(): self.markConstructorInVariable(module, va) # find in class functions variables body for name, fn in cl.functions.items(): self.markConstructorInNodes(module, fn.bodyNodes) def markConstructorInVariable(self, module, va): if va.body and (va.body.nodetype == 'functioncall'): self.markConstructorFunctioncall(module, va.body) def markConstructorFunctioncall(self, module, fc): if common.isClassName(module, fc.name): fc.isConstructorCall = True # mark constructor in params for node in fc.params: if node.nodetype == 'functioncall': self.markConstructorFunctioncall(module, node) def markConstructorInNodes(self, module, nodes): for node in nodes: if (node.nodetype == 'variable') and node.body: if node.body.nodetype == 'functioncall': self.markConstructorFunctioncall(module, node.body) elif (node.nodetype == 'value') and node.body and (node.body.nodetype == 'functioncall'): self.markConstructorFunctioncall(module, node.body) elif node.nodetype == 'return': if node.body.nodetype == 'functioncall': self.markConstructorFunctioncall(module, node.body) elif node.nodetype == 'if': if node.body: self.markConstructorInNodes(module, node.body) if node.elseBody: self.markConstructorInNodes(module, node.elseBody)