def generateCode(self,gSym,iSym,lSym,cref,blocko,blocki): # set up internal return stuff oldReturn = lSym['_return'] lSym['_return'] = None oldSelf = lSym['@'] # set up new block block = Block(blocko.getName()+"_inner",True) # transfer arguments argNumber = 0 start = blocko.temporaries_count for arg in self.args: # implicit given if arg[0:2] == '@@': lSym['@'] = TemporaryEntry(blocko) # assignment elif arg[0:1] == '@': lSym[arg[1:]] = TemporaryEntry(blocko) # ignore elif arg[0:1] == '_': TemporaryEntry(blocko) argNumber += 1 finish = blocko.temporaries_count - 1 if finish>=start: block.add_instruction("BlockArgs %i %i"%(start,finish)) blocki.add_instruction("Block #%s"%(block.getName())) self.expr.generateCode(gSym,iSym,lSym,cref,blocko,block) if lSym['_return']==True: block.add_instruction('RetValReturn') elif lSym['_return']: lSym['_return'].loadCode(block) block.add_instruction('Return') lSym['_blocks'].append(block) lSym['_return'] = oldReturn lSym['@'] = oldSelf
def generateCode(self,symbolTable): test_global = Global() store_global = Global() test_global.setName('test'+self.name) store_global.setName('store'+self.name) secondary_block = Block(innerBlock = True) secondary_block.add_instruction('Global $store'+self.name) secondary_block.add_instruction('Return') blocks = [] self.block.add_instruction('Block #'+secondary_block.getName()) self.block.add_instruction('Global $test'+self.name) self.block.add_instruction("MCall 1 'and:'") self.block.add_instruction('Pop') self.expr.generateCode(symbolTable, {}, {'_return': None,'@':None,'_blocks':blocks}, None, self.block, self.block) self.block.add_instruction('Dup') self.block.add_instruction('StoreGlobal $store'+self.name) self.block.add_instruction('Global $true') self.block.add_instruction('StoreGlobal $test'+self.name) self.block.add_instruction("Return") return [self.block,secondary_block,store_global,test_global]+blocks
def generateCode(self,gSym,iSym,lSym,cref,blocko,blocki): block = Block(blocko.getName()+"_inner",True) blocki.add_instruction("Block #%s"%(block.getName())) if self.operator: if self.messageName == '?//' or self.messageName == ':[]=': self.argCount = 2 elif self.messageName == '[~~]': self.argCount = 3 elif self.messageName == ':[~~]=': self.argCount = 4 else: self.argCount = 1 for i in range(0,self.argCount): block.add_instruction('BlockArg %i'%(i+1)) block.add_instruction('BlockArg 0') if self.messageName == "+": block.add_instruction("Add 1 '+'") else: block.add_instruction("MCall %i '%s'"%\ (self.argCount,self.messageName)) lSym['_blocks'].append(block)
def generateCode(self,symbolTable): argNumber = 0 blocks = [] selector = Selector(self.selector,False) for value in self.values: block = Block() block.add_instruction('Arg %i'%(argNumber)) block.add_instruction("MCall 0 '()'") block.add_instruction("Return") symbolTable[value].addMethod(symbolTable, selector, PseudoMethod(block.getName(),selector)) blocks += [block] argNumber = argNumber + 1 return blocks
def parseMethodCode(self): if self.tokenizer.check(';'): self.expr = None else: self.tokenizer.require('{') self.expr = parseExpression(self.tokenizer) self.tokenizer.require('}') if self.selector.operator: name = None else: name = self.selector.messageName name = name + "_" + self.cls if self.isClass: name = name + "_class" self.block = Block(name = name,nameSet = False) self.name = self.block.getName() return True
def tryParse(self): publicToken = self.tokenizer.check('public') if not publicToken: publicToken = self.tokenizer.check('private') if not self.tokenizer.check('global'): if publicToken: self.tokenizer.push(publicToken) return False self.tokenizer.require('$') idToken = self.tokenizer.nextToken() if idToken.type() != TokenTypes.identifier: raise SyntaxError("expected identifier: "+idToken.errForm()) self.name = idToken.str self.tokenizer.require('=') self.expr = parseExpressionSimple(self.tokenizer) if not self.expr: raise SyntaxError('expression required for global') self.tokenizer.require(';') self.block = Block(innerBlock = False) return True
def addClassMethod(self,symbolTable): blk = Block() blk.add_instruction('Global $%s' % self.name) blk.add_instruction('Return') if not self.exceptionHandlingBlocks: self.exceptionHandlingBlocks = [] self.exceptionHandlingBlocks += [blk] class FakeSelector: def __init__(self,name): self.messageName = name selector = FakeSelector('class') method = PseudoMethod(blk.getName(),selector) self.addMethod(symbolTable,selector,method) # XXX ??? self.exceptionHandlingBlocks += [blk]
def parseArgsWithSelector(self): self.args = [] while not self.tokenizer.peekCheck('{') and \ not self.tokenizer.peekCheck(';') and \ not self.tokenizer.peekCheck('('): if not self.tokenizer.check('@'): if self.tokenizer.check('#'): class Foo: pass self.block = Foo() name = self.tokenizer.nextToken().str self.block.name = name self.block.getName = lambda: name self.special = True self.name = self.block.name self.tokenizer.check(';') return True else: raise SyntaxError('@ or {: '+ self.tokenizer.nextToken().errForm()) self.args += ['@'+self.tokenizer.nextToken().str] if not self.tokenizer.check(','): break
class MethodDecl(ASTNode): def tryParse(self): self.access = '' publicToken = self.tokenizer.check('public') if publicToken: self.access = 'public' else: publicToken = self.tokenizer.check('private') if publicToken: self.access = 'private' dollarSign = self.tokenizer.check('$') if not dollarSign: if publicToken: self.tokenizer.push(publicToken) return False classToken = self.tokenizer.nextToken() self.cls = classToken.str self.isClass = self.tokenizer.check('class') self.isMixin = False # TODO mixin methods mixinToken = self.tokenizer.check('mixin') self.expr = None if mixinToken: self.tokenizer.push(mixinToken) self.tokenizer.push(classToken) self.tokenizer.push(dollarSign) if publicToken: self.tokenizer.push(publicToken) return False # TODO constructor code generation self.isConstructor = self.tokenizer.check('constructor') self.isAbstract = self.tokenizer.check('abstract') self.isUndefine = self.tokenizer.check('undefine') if not self.isAbstract: self.isAbstract = self.tokenizer.check('optional') self.isFinal = self.tokenizer.check('final') self.isAlias = self.tokenizer.check('alias') self.special = False self.selector = tryParse(SelectorLiteral, self.tokenizer) if self.selector: if self.isAlias: self.aliasTarget = tryParse(SelectorLiteral, self.tokenizer) if not self.aliasTarget: raise SyntaxError('Expected selector; found: ' + \ self.tokenizer.nextToken().errForm()) self.tokenizer.require(';') return True if self.isAbstract: self.tokenizer.require(';') return True else: self.parseArgsWithSelector() else: self.parseInterwoven() if self.special: return True else: self.parseSecureLevelDecl() return self.parseMethodCode() def parseArgument(self): arg = self.tryParseArgument() if not arg: raise SyntaxError("argument expected: "+\ self.tokenizer.nextToken().errForm()) return arg def tryParseArgument(self): if self.tokenizer.check('@'): id = self.tokenizer.nextToken() if id.type() != TokenTypes.identifier: raise SyntaxError("not id: "+id.errForm()) return "@"+id.str elif self.tokenizer.check('_'): return "_" elif self.tokenizer.check('!'): id = self.tokenizer.nextToken() if id.type() != TokenTypes.identifier: raise SyntaxError("not id: "+id.errForm()) return "!"+id.str else: return None def getArgCount(self): return len(self.args) def parseInterwoven(self): nextToken = self.tokenizer.nextToken() if nextToken.type() == TokenTypes.operator: if nextToken.str not in ['?','[',':[', '(']: self.args = [self.parseArgument()] self.selector = Selector(nextToken.str,True) return elif nextToken.str == '?': self.selector = Selector('?//',True) self.args = [self.parseArgument()] self.tokenizer.require('//') self.args += [self.parseArgument()] return elif nextToken.str == ':[': self.args = [self.parseArgument()] if self.tokenizer.check('~'): self.selector = Selector(':[~~]=',True) self.args += [self.parseArgument()] self.tokenizer.require('~') self.args += [self.parseArgument()] else: self.selector = Selector(':[]=',True) self.tokenizer.require(']=') self.args += [self.parseArgument()] return elif nextToken.str == '[': self.args = [self.parseArgument()] if self.tokenizer.check('~'): self.selector = Selector('[~~]',True) self.args += [self.parseArgument()] self.tokenizer.require('~') self.args += [self.parseArgument()] else: self.selector = Selector('[]',True) self.tokenizer.require(']') return elif nextToken.str == '(': self.args = [self.parseArgument()] # TODO (for C3 probably) check if this is a list and match self.selector = Selector('()',True) self.tokenizer.require(')') return elif nextToken.type() == TokenTypes.identifier: #so it's either a unary message-send or a keyworder. colon = self.tokenizer.checkNoWhitespace(':') if colon: self.args = [self.parseArgument()] name = nextToken.str + ':' while True: nextToken = self.tokenizer.nextToken() if nextToken.type() != TokenTypes.identifier: self.tokenizer.push(nextToken) break self.tokenizer.require(':') self.args += [self.parseArgument()] name += nextToken.str + ':' self.selector = Selector(name,False) else: self.args = [] self.selector = Selector(nextToken.str,False) return def parseArgsWithSelector(self): self.args = [] while not self.tokenizer.peekCheck('{') and \ not self.tokenizer.peekCheck(';') and \ not self.tokenizer.peekCheck('('): if not self.tokenizer.check('@'): if self.tokenizer.check('#'): class Foo: pass self.block = Foo() name = self.tokenizer.nextToken().str self.block.name = name self.block.getName = lambda: name self.special = True self.name = self.block.name self.tokenizer.check(';') return True else: raise SyntaxError('@ or {: '+ self.tokenizer.nextToken().errForm()) self.args += ['@'+self.tokenizer.nextToken().str] if not self.tokenizer.check(','): break def parseSecureLevelDecl(self): # TODO check these values and store them in a cleaner way. # TODO Actually use securelevels. if not self.tokenizer.check('('): return # no securelevel decl self.securelevel = self.tokenizer.nextToken() self.tokenizer.require(',') self.writability = self.tokenizer.nextToken() self.tokenizer.require(')') def parseMethodCode(self): if self.tokenizer.check(';'): self.expr = None else: self.tokenizer.require('{') self.expr = parseExpression(self.tokenizer) self.tokenizer.require('}') if self.selector.operator: name = None else: name = self.selector.messageName name = name + "_" + self.cls if self.isClass: name = name + "_class" self.block = Block(name = name,nameSet = False) self.name = self.block.getName() return True def __str__(self): res = '$' res += self.cls if self.isAlias: res += ' alias ' res += str(self.selector) res += ' ' if self.isAlias: res += str(self.aliasTarget) res += ';' else: for arg in self.args: res += '@' res += arg res += ', ' res += "{\n" res += str(self.expr) res += "\n}\n" return res def registerMethod(self,symbolTable): if not self.isAbstract: # TODO addAbstract() and check instead symbolTable[self.cls].addMethod(symbolTable,self.selector,self) def generateCode(self,symbolTable): self.registerMethod(symbolTable) if self.isAlias or self.isAbstract or self.special: return [] cls = symbolTable[self.cls] itable = cls.generateInstanceSymbolTable(symbolTable) table = self.generateLocalSymbolTable(itable) table['_classMethod'] = self.isClass self.block.add_instruction('" '+self.selector.messageName) if self.expr: self.expr.generateCode(symbolTable, itable, table, cls, self.block, self.block) if table['_return'].__class__ == SelfEntry: self.block.add_instruction("SReturn") elif table['_return']==True: self.block.add_instruction("RetValReturn") elif table['_return']: table['_return'].loadCode(self.block) self.block.add_instruction("Return") return [self.block]+table['_blocks'] def generateLocalSymbolTable(self,itable): res = {'@':SelfEntry(), '_return':SelfEntry(), '_blocks':[]} argNum = 0 if self.selector.messageName == '()' and len(self.args) == 1: self.block.add_instruction("AllocFromArgs") self.block.add_instruction("Dup") self.block.add_instruction("ChMTable %PrimitiveArray") realArg = self.args[0] if realArg[0] == '@': arg = realArg[1:] res[arg] = TemporaryEntry(self.block) self.block.add_instruction('StoreTemp %i'%\ (res[arg].getNumber())) elif realArg[0] == '_': self.block.add_instruction("Pop") elif realArg[0] == '!': arg = realArg[1:] ivar = itable[arg] ivar.storeCode(self.block) else: for realArg in self.args: if realArg[0] == '@': arg = realArg[1:] res[arg] = ArgumentEntry(argNum) elif realArg[0] == '_': pass elif realArg[0] == '!': arg = realArg[1:] ivar = itable[arg] self.block.add_instruction('Arg %i'%(argNum)) ivar.storeCode(self.block) argNum += 1 return res
def generateCode(self,stable): self.getMethodTable(stable) #ensure method tables initialized self.addClassMethod(stable) #self.resolveMixins(stable) gvar = Global() # class/singleton object reference gvar.setName(self.name) # our name obj = BytecodeObject(self.name) # class/singleton object gvar.setValue(obj) # which the reference points to if self.singleton: obj.setMTable(self.methodTable) #singletons get object mtable return [self.methodTable,obj,gvar]+self.exceptionHandlingBlocks else: obj.setMTable(self.classMethodTable) #non-singletons get factory one block = Block(name = '_new_' + self.name) # new method block.add_instruction("Int %i"%\ (self.getInstanceVariableCount(stable))) block.add_instruction("Alloc %i"% \ self.getInstanceVariableCount(stable)) block.add_instruction("Dup") block.add_instruction("ChMTable %%%s"%(self.methodTable.name)) block.add_instruction("Return") self.classMethodTable.addMethod('basicNew',block.name) return [self.methodTable,self.classMethodTable,block,obj,gvar]+\ self.exceptionHandlingBlocks
def addMethod(self,symbolTable,selector,method): if self.exception: self.defineExceptionMethod(symbolTable) self.getMethodTable(symbolTable) if method.isClass: mt = self.classMethodTable elif method.isConstructor: self.methodTable.addMethod(selector.messageName, method.block.getName()) classMethodBlock = Block() classMethodBlock.incrementTemporaries() classMethodBlock.add_instruction('Self') classMethodBlock.add_instruction("MCall 0 'basicNew'") classMethodBlock.add_instruction("StoreTemp 0") for i in range(0,method.getArgCount()): classMethodBlock.add_instruction("Arg %i"%(i)) classMethodBlock.add_instruction("Temp 0") classMethodBlock.add_instruction("MCall %i '%s'"%\ (method.getArgCount(),selector.messageName)) classMethodBlock.add_instruction("Temp 0") #classMethodBlock.add_instruction("MCall 0 'secure'") classMethodBlock.add_instruction("Return") self.exceptionHandlingBlocks += [classMethodBlock] self.classMethodTable.addMethod(selector.messageName, classMethodBlock.getName()) return else: mt = self.methodTable if method.isAlias: mt.addAlias(selector.messageName,method.aliasTarget.messageName) else: mt.addMethod(selector.messageName,method.block.getName())
def defineExceptionMethod(self,symbolTable): self.exception = False class FakeSelector: def __init__(self,name): self.messageName = name testerSelector = FakeSelector('internal_is'+self.name) self.addMethod(symbolTable,testerSelector, generateTrueMethod(testerSelector)) symbolTable['Object'].addMethod(symbolTable,testerSelector, generateFalseMethod(testerSelector)) blk1 = Block() blk1.add_instruction('BlockArg 0') blk1.add_instruction("MCall 0 'internal_is%s'"%(self.name)) blk2 = Block() blk2.add_instruction('Block #%s'%(blk1.getName())) blk2.add_instruction('Arg 0') blk2.add_instruction('Self') blk2.add_instruction("MCall 2 'onExceptionMatching:do:'") blk2.add_instruction("Return") self.exceptionHandlingBlocks = [blk1,blk2] symbolTable['Block'].addMethod(symbolTable,self.selector, PseudoMethod(blk2.getName(),self.selector))
class GlobalDecl(ASTNode): def tryParse(self): publicToken = self.tokenizer.check('public') if not publicToken: publicToken = self.tokenizer.check('private') if not self.tokenizer.check('global'): if publicToken: self.tokenizer.push(publicToken) return False self.tokenizer.require('$') idToken = self.tokenizer.nextToken() if idToken.type() != TokenTypes.identifier: raise SyntaxError("expected identifier: "+idToken.errForm()) self.name = idToken.str self.tokenizer.require('=') self.expr = parseExpressionSimple(self.tokenizer) if not self.expr: raise SyntaxError('expression required for global') self.tokenizer.require(';') self.block = Block(innerBlock = False) return True def extractSymbols(self): return {self.name: self} def generateCode(self,symbolTable): test_global = Global() store_global = Global() test_global.setName('test'+self.name) store_global.setName('store'+self.name) secondary_block = Block(innerBlock = True) secondary_block.add_instruction('Global $store'+self.name) secondary_block.add_instruction('Return') blocks = [] self.block.add_instruction('Block #'+secondary_block.getName()) self.block.add_instruction('Global $test'+self.name) self.block.add_instruction("MCall 1 'and:'") self.block.add_instruction('Pop') self.expr.generateCode(symbolTable, {}, {'_return': None,'@':None,'_blocks':blocks}, None, self.block, self.block) self.block.add_instruction('Dup') self.block.add_instruction('StoreGlobal $store'+self.name) self.block.add_instruction('Global $true') self.block.add_instruction('StoreGlobal $test'+self.name) self.block.add_instruction("Return") return [self.block,secondary_block,store_global,test_global]+blocks def loadCode(self,block): block.add_instruction("Self") block.add_instruction("Call 0 #%s"%(self.block.getName())) return [self.block]