def comma_list(self, start): """ Iterate over a comma separated list Args: self (Builder): Code constructor start (int): Current position in code Returns: list : A list of 2-tuples that represents index start and end for each expression in list """ if self.code[start] not in c.l_start: self.syntaxerror(start, "list start") k = start+1 while self.code[k] in " \t": k += 1 if self.code[k] in "]}": return [[]] out = [[]] count = False while True: if self.code[k:k+3] == "...": k = findend.dots(self, k) elif self.code[k] in c.e_start: if count: self.syntaxerror(k, "comma list indicator") count = True end = findend.expression(self, k) out[-1].append((k, end)) k = end elif self.code[k] == ",": if not count: self.syntaxerror(k, "comma list indicator") count = False elif self.code[k] == ";": if not count: self.syntaxerror(k, "comma list indicator") count = False out.append([]) elif self.code[k] in c.l_end: return out k += 1
def whileloop(self, parent, cur): ''' While loop Args: self (Builder): Code constructor. parent (Node): Parent node cur (int): Current position in code Returns: int: Index to end of code block Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", ... """while a ... b ... end""") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 While branches.whileloop 'while a' 6 Expression expression.create 'a' 6 Var variables.variable 'a' 10 Codeblock codeblock.codeblock 10 Statement codeblock.codeblock 'b' 10 Expression expression.create 'b' 10 Var variables.variable 'b' >>> builder.configure() >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| While code_block TYPE 1 7| | Var unknown TYPE a 2 11| | Block code_block TYPE 2 11| | | Statement code_block TYPE 2 11| | | | Var unknown TYPE b ''' if self.code[cur:cur+5] != "while" and self.code[cur+5] not in c.k_end: self.syntaxerror(cur, "start of while-loop") start = cur k = cur+5 while self.code[k] in " \t": k += 1 end = findend.expression(self, k) if self.disp: print "%4d While " % cur, print "%-20s" % "branches.whileloop", print repr(self.code[cur:end+1]) whileloop = mc.collection.While(parent, cur=cur) if self.code[k] == "(": k += 1 while self.code[k] in " \t": k += 1 cur = self.create_expression(whileloop, k) cur += 1 cur += 1 while self.code[cur] in " \t": cur += 1 end = self.create_codeblock(whileloop, cur) whileloop.code = self.code[start:end+1] return end
def ifbranch(self, parent, start): ''' If-ifelse-else branch Args: self (Builder): Code constructor. parent (Node): Parent node cur (int): Current position in code Returns: int: Index to end of code block Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", ... """if a ... b ... elseif c ... d ... end""") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 If branches.ifbranch 'if a' 3 Expression expression.create 'a' 3 Var variables.variable 'a' 4 Codeblock codeblock.codeblock 7 Statement codeblock.codeblock 'b' 7 Expression expression.create 'b' 7 Var variables.variable 'b' 9 Else if branches.ifbranch 'elseif c' 16 Expression expression.create 'c' 16 Var variables.variable 'c' 17 Codeblock codeblock.codeblock 20 Statement codeblock.codeblock 'd' 20 Expression expression.create 'd' 20 Var variables.variable 'd' >>> builder.configure() >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Branch code_block TYPE 1 4| | If code_block TYPE 1 4| | | Var unknown TYPE a 1 5| | | Block code_block TYPE 2 8| | | | Statement code_block TYPE 2 8| | | | | Var unknown TYPE b 3 10| | Elif code_block TYPE 3 17| | | Var unknown TYPE c 3 18| | | Block code_block TYPE 4 21| | | | Statement code_block TYPE 4 21| | | | | Var unknown TYPE d ''' if self.code[start:start+2] != "if" or self.code[start+2] not in c.k_end: self.syntaxerror(start, "if branch start") branch = mc.collection.Branch(parent, cur=start) cur = start cur += 2 while self.code[cur] in " \t": cur += 1 if self.code[cur] not in c.e_start: self.syntaxerror(cur, "expression start") end = findend.expression(self, cur) if self.disp: print "%4d If " % (start), print "%-20s" % "branches.ifbranch", print repr(self.code[start:end+1]) node = mc.collection.If(branch, cur=cur) if self.code[cur] == "(": cur += 1 while self.code[cur] in " \t": cur += 1 self.create_expression(node, cur) cur = end+1 end = self.create_codeblock(node, cur) node.code = self.code[cur:end] cur = end while self.code[cur:cur+6] == "elseif" and self.code[cur+6] in c.k_end: node.code = self.code[start:cur] start = cur cur += 6 while self.code[cur] in " \t": cur += 1 end = findend.expression(self, cur) if self.disp: print "%4d Else if " % (start), print "%-20s" % "branches.ifbranch", print repr(self.code[start:end+1]) node = mc.collection.Elif(branch, cur=start) if self.code[cur] == "(": cur += 1 while self.code[cur] in " \t": cur += 1 self.create_expression(node, cur) cur = end+1 cur = end = self.create_codeblock(node, cur) cur = end node.code = self.code[start:cur] if self.code[cur:cur+4] == "else" and self.code[cur+4] in c.k_end: start = cur cur += 4 if self.disp: print "%4d Else " % (start), print "%-20s" % "branches.ifbranch", print repr(self.code[start:start+5]) node = mc.collection.Else(branch, cur=start) end = self.create_codeblock(node, cur) node.code = self.code[start:end+1] branch.code = self.code[start:end+1] return end
def create(self, node, start, end=None, start_opr=None): """ Create expression in three steps: 1) In order, split into sub-expressions for each dividing operator 2) Address prefixes, postfixes, parenthesises, etc. 3) Identify the remaining singleton Args: self (Builder): Code constructor. node (Node): Reference to the parent node start (int): current possition in code end (int, optional): end of expression. Required for space-delimited expression. start_opr (str, optional): At which operator the recursive process is. (For internal use) Returns: int : index to end of the expression Examples:: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "a*b+c/d") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Statement codeblock.codeblock 'a*b+c/d' 0 Expression expression.create 'a*b+c/d' 0 Expression expression.create 'a*b' 0 Expression expression.create 'a' 0 Var variables.variable 'a' 2 Expression expression.create 'b' 2 Var variables.variable 'b' 4 Expression expression.create 'c/d' 4 Expression expression.create 'c' 4 Var variables.variable 'c' 6 Expression expression.create 'd' 6 Var variables.variable 'd' >>> builder.configure(suggest=False) >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Statement code_block TYPE 1 1| | Plus expression TYPE 1 1| | | Mul expression TYPE 1 1| | | | Var unknown TYPE a 1 3| | | | Var unknown TYPE b 1 5| | | Matrixdivisionexpression TYPE 1 5| | | | Var unknown TYPE c 1 7| | | | Var unknown TYPE d """ if self.code[start:start + 3] == "...": start = findend.dots(self, start) start += 1 while self.code[start] in " \t": start += 1 if self.code[start] == ":": if self.disp: print "%4d Expression " % (start), print "%-20s" % "expression.create", print repr(self.code[start:start + 1]) print "%4d All " % (start), print "%-20s" % "expression.create", print repr(self.code[start:start + 1]) mc.collection.All(node, cur=start, code=self.code[start]) return start if end is None: end = findend.expression(self, start) if self.disp: print "%4d Expression " % (start), print "%-20s" % "expression.create", print repr(self.code[start:end + 1]) if self.code[start] not in c.e_start: self.syntaxerror(start, "expression start") operators = [ "||", "&&", "|", "&", "~=", "==", ">=", ">", "<=", "<", ":", "+", "-", ".*", "*", "./", "/", ".\\", "\\", ".^", "^" ] if not (start_opr is None): operators = operators[operators.index(start_opr) + 1:] for opr in operators: # Pre-screen if opr not in self.code[start:end + 1]: continue starts = [start] last = start ends = [] k = start while True: if self.code[k] == "(": k = last = findend.paren(self, k) elif self.code[k] == "[": k = last = findend.matrix(self, k) elif self.code[k] == "{": k = last = findend.cell(self, k) elif self.code[k] == "'": if identify.string(self, k): k = last = findend.string(self, k) else: last = k elif opr == self.code[k:k + len(opr)]: if opr in "+-": # no prefixes and no (scientific) numbers if self.code[last] not in c.letters+c.digits+")]}" or\ self.code[k-1] in "dDeE" and self.code[k-2] in\ c.digits+"." and self.code[k+1] in c.digits: k += 1 continue k += len(opr) - 1 while self.code[k + 1] in " \t": k += 1 # no all-operator if opr == ":" and self.code[k + 1] in ",;\n)]}": k += 1 continue starts.append(k + 1) ends.append(last) elif self.code[k] in c.letters + c.digits + "_": last = k k += 1 if k >= end: ends.append(end) break if len(ends) > 1: node = retrieve_operator(self, opr)(node) node.cur = start node.code = self.code[starts[0]:ends[-1] + 1] for s, e in zip(starts, ends): create(self, node, s, e, opr) return end # All operators removed at this point! END = end # Prefixes while self.code[start] in "-~": if self.code[start] == "-": node = mc.collection.Neg(node, cur=start, code=self.code[start:end + 1]) start += 1 if self.code[start] == "~": node = mc.collection.Not(node, cur=start, code=self.code[start:end + 1]) start += 1 while self.code[start] in " \t": start += 1 # Postfixes if self.code[end] == "'" and not self.code[start] == "'": if self.code[end - 1] == ".": node = mc.collection.Transpose(node, cur=start, code=self.code[start:end + 1]) end -= 2 else: node = mc.collection.Ctranspose(node, cur=start, code=self.code[start:end + 1]) node.cur = start node.code = self.code[start:end + 1] end -= 1 while self.code[end] in " \t": end -= 1 # Parenthesis if self.code[start] == "(": if self.code[end] != ")": self.syntaxerror(end, "parenthesis end") node = mc.collection.Paren(node, cur=start, code=self.code[start:end + 1]) start += 1 while self.code[start] in " \t": start += 1 end -= 1 while self.code[end] in " \t": end -= 1 return create(self, node, start, end) # Reserved keywords elif self.code[start:start + 3] == "end" and self.code[start + 3] in " +-:\t" + c.e_end: node = mc.collection.End(node, cur=start, code=self.code[start:start + 3]) elif self.code[start:start + 6] == "return" and self.code[start + 6] in " ,;\n": node = mc.collection.Return(node, cur=start, code=self.code[start:start + 6]) elif self.code[start:start + 5] == "break" and self.code[start + 5] in " ,;\n": node = mc.collection.Break(node, cur=start, code=self.code[start:start + 5]) # Rest elif self.code[start] == "'": if self.code[end] != "'": self.syntaxerror(end, "string end") if "\n" in self.code[start:end]: self.syntaxerror(end, "non line-feed characters in string") mc.collection.String(node, self.code[start + 1:end], cur=start, code=self.code[start:end + 1]) elif self.code[start] in c.digits or\ self.code[start] == "." and self.code[start+1] in c.digits: cur = self.create_number(node, start) elif self.code[start] == "[": cur = self.create_matrix(node, start) elif self.code[start] == "{": cur = self.create_cell(node, start) else: if self.code[start] not in c.letters + "@": self.syntaxerror(start, "variable name") cur = self.create_variable(node, start) return END
def switch(self, parent, cur): ''' Switch-case branch Args: self (Builder): Code constructor. parent (Node): Parent node cur (int): Current position in code Returns: int: Index to end of codeblock Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", ... """switch a ... case b ... c ... case d ... d ... end""") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Switch branches.switch 'switch a' 7 Expression expression.create 'a' 7 Var variables.variable 'a' 9 Case branches.switch 'case b' 14 Expression expression.create 'b' 14 Var variables.variable 'b' 18 Codeblock codeblock.codeblock 18 Statement codeblock.codeblock 'c' 18 Expression expression.create 'c' 18 Var variables.variable 'c' 20 Case branches.switch 'case d' 25 Expression expression.create 'd' 25 Var variables.variable 'd' 29 Codeblock codeblock.codeblock 29 Statement codeblock.codeblock 'd' 29 Expression expression.create 'd' 29 Var variables.variable 'd' >>> builder.configure() >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Switch code_block TYPE 1 8| | Var unknown TYPE a 2 10| | Case code_block TYPE 2 15| | | Var unknown TYPE b 3 19| | | Block code_block TYPE 3 19| | | | Statement code_block TYPE 3 19| | | | | Var unknown TYPE c 4 21| | Case code_block TYPE 4 26| | | Var unknown TYPE d 5 30| | | Block code_block TYPE 5 30| | | | Statement code_block TYPE 5 30| | | | | Var unknown TYPE d ''' if not (self.code[cur:cur+6] == "switch" and\ self.code[cur+6] in " \t("): self.syntaxerror(cur, "start of switch branch") k = cur+6 while self.code[k] in " \t": k += 1 end = findend.expression(self, k) if self.disp: print "%4d Switch " % cur, print "%-20s" % "branches.switch", print repr(self.code[cur:end+1]) switch = mc.collection.Switch(parent, cur=cur) self.create_expression(switch, k, end) k = end+1 while self.code[k] in " \t\n;,": k += 1 while self.code[k:k+4] == "case" and self.code[k+4] in " \t(": cur = k k += 4 while self.code[k] in " \t": k += 1 end = findend.expression(self, k) if self.disp: print "%4d Case " % cur, print "%-20s" % "branches.switch", print repr(self.code[cur:end+1]) case = mc.collection.Case(switch, cur=cur) cur = self.create_expression(case, k, end) k = cur+1 while self.code[k] in " \t;,\n": k += 1 k = self.create_codeblock(case, k) if self.code[k:k+9] == "otherwise" and self.code[k+9] in " \t(,;\n": cur = k if self.disp: print "%4d Otherwise " % cur, print "%-20s" % "branches.switch", print repr(self.code[cur:cur+10]) otherwise = mc.collection.Otherwise(switch, cur=cur) k += 9 while self.code[k] in " \t\n;,": k += 1 k = self.create_codeblock(otherwise, k) return k
def codeblock(self, parent, start): ''' If-ifelse-else branch Args: self (Builder): Code constructor parent (Node): Parent node cur (int): Current position in code Returns: int: Index to end of codeblock Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "a; 'b'; 3") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Statement codeblock.codeblock 'a' 0 Expression expression.create 'a' 0 Var variables.variable 'a' 3 Statement codeblock.codeblock "'b'" 3 String misc.string "'b'" 8 Statement codeblock.codeblock '3' 8 Expression expression.create '3' 8 Int misc.number '3' >>> builder.configure() >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Statement code_block TYPE 1 1| | Var unknown TYPE a 1 4| Statement code_block TYPE 1 4| | String string string 1 9| Statement code_block TYPE 1 9| | Int int int ''' cur = start block = mc.collection.Block(parent, cur=cur) if self.disp: print "%4d Codeblock " % cur, print "%-20s" % "codeblock.codeblock" is_end_terminated = False while True: #print self.code[cur:cur+5] if self.code[cur] in " \t;": pass elif self.code[cur] == "\n": if len(self.code) - cur < 3: break #%#PARFOR token elif self.code[cur:cur + 8] == "%#PARFOR": cur = self.create_pragma_parfor(block, cur) elif self.code[cur] == "%": cur = self.create_comment(block, cur) elif self.code[cur:cur + 3] == "___": cur = self.create_verbatim(block, cur) elif self.code[cur] == "[": # Divide between statement and assignment eq_loc = findend.matrix(self, cur) + 1 while self.code[eq_loc] in " \t": eq_loc += 1 if self.code[eq_loc] == "=" and self.code[eq_loc + 1] != "=": cur = self.create_assigns(block, cur, eq_loc) else: statement = mc.collection.Statement(block, cur=cur) end = findend.expression(self, cur) if self.disp: print "%4d Statement " % cur, print "%-20s" % "codeblock.codeblock", print repr(self.code[cur:end + 1]) statement.code = self.code[cur:end + 1] cur = self.create_expression(statement, cur, end=end) elif self.code[cur] == "'": end = findend.string(self, cur) if self.disp: print "%4d Statement " % cur, print "%-20s" % "codeblock.codeblock", print repr(self.code[cur:end + 1]) statement = mc.collection.Statement(block, cur=cur, code=self.code[cur:end + 1]) cur = self.create_string(statement, cur) elif self.code[cur:cur + 4] == "case" and self.code[cur + 4] in c.k_end: break elif self.code[cur:cur + 5] == "catch" and self.code[cur + 5] in c.k_end: break elif self.code[cur:cur + 3] == "end" and self.code[cur + 3] in c.k_end: cur += 3 is_end_terminated = True break elif self.code[cur:cur + 4] == "else" and self.code[cur + 4] in c.k_end: break elif self.code[cur:cur + 6] == "elseif" and self.code[cur + 6] in c.k_end: break elif self.code[cur:cur + 6] == "parfor" and self.code[cur + 6] in c.k_end: cur = self.create_parfor(block, cur) elif self.code[cur:cur + 3] == "for" and self.code[cur + 3] in c.k_end: cur = self.create_for(block, cur) elif self.code[cur:cur+8] == "function" and\ self.code[cur+8] in c.k_end + "[": cur -= 1 break elif self.code[cur:cur + 2] == "if" and self.code[cur + 2] in c.k_end: cur = self.create_if(block, cur) elif self.code[cur:cur + 9] == "otherwise" and self.code[cur + 9] in c.k_end: break elif self.code[cur:cur + 6] == "switch" and self.code[cur + 6] in c.k_end: cur = self.create_switch(block, cur) elif self.code[cur:cur + 3] == "try" and self.code[cur + 3] in c.k_end: cur = self.create_try(block, cur) elif self.code[cur:cur + 5] == "while" and self.code[cur + 5] in c.k_end: cur = self.create_while(block, cur) elif self.code[cur:cur+4] == "hold" and \ self.code[cur+4] not in c.letters+c.digits+"_": cur = self.create_reserved(block, cur) elif self.code[cur:cur+4] == "load" and \ self.code[cur+4] not in c.letters+c.digits+"_": cur = self.create_reserved(block, cur) elif self.code[cur:cur+4] == "disp" and \ self.code[cur+4] not in c.letters+c.digits+"_": cur = self.create_reserved(block, cur) elif self.code[cur:cur+4] == "grid" and \ self.code[cur+4] not in c.letters+c.digits+"_": cur = self.create_reserved(block, cur) elif self.code[cur] in c.e_start: j = findend.expression(self, cur) j += 1 while self.code[j] in " \t": j += 1 eq_loc = j if self.code[eq_loc] == "=": # and self.code[eq_loc+1] != "=": j = eq_loc + 1 while self.code[j] in " \t": j += 1 if self.code[j] == "@": cur = self.create_lambda_assign(block, cur, eq_loc) else: cur = self.create_assign(block, cur, eq_loc) else: end = findend.expression(self, cur) if self.disp: print "%4d Statement " % cur, print "%-20s" % "codeblock.codeblock", print repr(self.code[cur:end + 1]) statement = mc.collection.Statement(block, cur=cur, code=self.code[cur:end + 1]) cur = self.create_expression(statement, cur, end=end) cur += 1 if len(self.code) - cur < 3: break block.is_end_terminated = is_end_terminated block.code = self.code[start:cur + 1] return cur
def codeblock(self, parent, start): ''' If-ifelse-else branch Args: self (Builder): Code constructor parent (Node): Parent node cur (int): Current position in code Returns: int: Index to end of codeblock Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "a; 'b'; 3") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Statement codeblock.codeblock 'a' 0 Expression expression.create 'a' 0 Var variables.variable 'a' 3 Statement codeblock.codeblock "'b'" 3 String misc.string "'b'" 8 Statement codeblock.codeblock '3' 8 Expression expression.create '3' 8 Int misc.number '3' >>> builder.configure() >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Statement code_block TYPE 1 1| | Var unknown TYPE a 1 4| Statement code_block TYPE 1 4| | String string string 1 9| Statement code_block TYPE 1 9| | Int int int ''' cur = start block = mc.collection.Block(parent, cur=cur) if self.disp: print "%4d Codeblock " % cur, print "%-20s" % "codeblock.codeblock" while True: if self.code[cur] in " \t;": pass elif self.code[cur] == "\n": if len(self.code)-cur < 3: break #%%PARFOR token elif self.code[cur:cur+8] == "%%PARFOR": cur = self.create_pragma_parfor(block, cur) elif self.code[cur] == "%": cur = self.create_comment(block, cur) elif self.code[cur:cur+3] == "___": cur = self.create_verbatim(block, cur) elif self.code[cur] == "[": # Divide between statement and assignment eq_loc = findend.matrix(self, cur)+1 while self.code[eq_loc] in " \t": eq_loc += 1 if self.code[eq_loc] == "=" and self.code[eq_loc+1] != "=": cur = self.create_assigns(block, cur, eq_loc) else: statement = mc.collection.Statement(block, cur=cur) end = findend.expression(self, cur) if self.disp: print "%4d Statement " % cur, print "%-20s" % "codeblock.codeblock", print repr(self.code[cur:end+1]) statement.code = self.code[cur:end+1] cur = self.create_expression( statement, cur, end=end) elif self.code[cur] == "'": end = findend.string(self, cur) if self.disp: print "%4d Statement " % cur, print "%-20s" % "codeblock.codeblock", print repr(self.code[cur:end+1]) statement = mc.collection.Statement(block, cur=cur, code=self.code[cur:end+1]) cur = self.create_string(statement, cur) elif self.code[cur:cur+4] == "case" and self.code[cur+4] in c.k_end: break elif self.code[cur:cur+5] == "catch" and self.code[cur+5] in c.k_end: break elif self.code[cur:cur+3] == "end" and self.code[cur+3] in c.k_end: cur += 3 break elif self.code[cur:cur+4] == "else" and self.code[cur+4] in c.k_end: break elif self.code[cur:cur+6] == "elseif" and self.code[cur+6] in c.k_end: break elif self.code[cur:cur+6] == "parfor" and self.code[cur+6] in c.k_end: cur = self.create_parfor(block, cur) elif self.code[cur:cur+3] == "for" and self.code[cur+3] in c.k_end: cur = self.create_for(block, cur) elif self.code[cur:cur+8] == "function" and\ self.code[cur+8] in c.k_end + "[": cur -= 1 break elif self.code[cur:cur+2] == "if" and self.code[cur+2] in c.k_end: cur = self.create_if(block, cur) elif self.code[cur:cur+9] == "otherwise" and self.code[cur+9] in c.k_end: break elif self.code[cur:cur+6] == "switch" and self.code[cur+6] in c.k_end: cur = self.create_switch(block, cur) elif self.code[cur:cur+3] == "try" and self.code[cur+3] in c.k_end: cur = self.create_try(block, cur) elif self.code[cur:cur+5] == "while" and self.code[cur+5] in c.k_end: cur = self.create_while(block, cur) elif self.code[cur:cur+4] == "hold" and \ self.code[cur+4] not in c.letters+c.digits+"_": cur = self.create_reserved(block, cur) elif self.code[cur:cur+4] == "grid" and \ self.code[cur+4] not in c.letters+c.digits+"_": cur = self.create_reserved(block, cur) elif self.code[cur] in c.e_start: j = findend.expression(self, cur) j += 1 while self.code[j] in " \t": j += 1 eq_loc = j if self.code[eq_loc] == "=": # and self.code[eq_loc+1] != "=": j = eq_loc +1 while self.code[j] in " \t": j += 1 if self.code[j] == "@": cur = self.create_lambda_assign(block, cur, eq_loc) else: cur = self.create_assign(block, cur, eq_loc) else: end = findend.expression(self, cur) if self.disp: print "%4d Statement " % cur, print "%-20s" % "codeblock.codeblock", print repr(self.code[cur:end+1]) statement = mc.collection.Statement(block, cur=cur, code=self.code[cur:end+1]) cur = self.create_expression(statement, cur, end=end) cur += 1 if len(self.code)-cur<3: break block.code = self.code[start:cur+1] return cur
def function(self, parent, cur): """ Explicit functions Args: self (Builder): Code constructor parent (Node): Parent node cur (int): Current position in code Returns: int : Index to end of function Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "function f(); end") loading unnamed Program functions.program 0 Function functions.function 'function f()' 12 Codeblock codeblock.codeblock >>> builder.configure(suggest=False) >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Funcs program TYPE unnamed 1 1| Func func_returns TYPE f 1 1| | Declares func_returns TYPE 1 1| | Returns func_returns TYPE 1 11| | Params func_returns TYPE 1 13| | Block code_block TYPE """ if self.code[cur:cur+8] != "function": self.syntaxerror(cur, "function start") if self.code[cur+8] not in c.k_end+"[": self.syntaxerror(cur, "function name or return values") START = cur k = cur + 8 while self.code[k] in " \t": k += 1 if self.code[k] not in c.letters+"[": self.syntaxerror(k, "function name or return values") start = k k = findend.expression(self, k) end = k k += 1 while self.code[k] in " \t": k += 1 # with return values if self.code[k] == "=": k += 1 while self.code[k] in " \t.": if self.code[k:k+3] == "...": k = findend.dots(self, k)+1 else: k += 1 l = k if self.code[l] not in c.letters: self.syntaxerror(l, "function name") while self.code[l+1] in c.letters+c.digits+"_": l += 1 m = l+1 while self.code[m] in " \t": m += 1 if self.code[m] == "(": m = findend.paren(self, m) else: m = l if self.disp: print "%4d Function " % cur, print "%-20s" % "functions.function", print repr(self.code[START:m+1]) name = self.code[k:l+1] func = mc.collection.Func(parent, name, cur=cur) mc.collection.Declares(func, code="") returns = mc.collection.Returns(func, code=self.code[start:end+1]) # multi-return if self.code[start] == "[": if identify.space_delimited(self, start): L = iterate.space_list(self, start) else: L = iterate.comma_list(self, start) end = START for array in L: for s,e in array: end = s if self.disp: print "%4d Return " % cur, print "%-20s" % "functions.function", print repr(self.code[s:e+1]) if not any([a in c.letters+c.digits+"_@" \ for a in self.code[s:e+1]]): self.syntaxerror(s, "return value") mc.collection.Var(returns, self.code[s:e+1], cur=s, code=self.code[s:e+1]) # single return else: end = findend.expression(self, start) if self.disp: print "%4d Return " % cur, print repr(self.code[start:end+1]) mc.collection.Var(returns, self.code[start:end+1], cur=start, code=self.code[start:end+1]) cur = l+1 while self.code[cur] in " \t": cur += 1 # No returns else: m = k if self.code[m] == "(": m = findend.paren(self, m) else: m = end if self.disp: print "%4d Function " % cur, print "%-20s" % "functions.function", print repr(self.code[START:m+1]) end = start+1 while self.code[end] in c.letters+"_": end += 1 name = self.code[start:end] func = mc.collection.Func(parent, name, cur=cur) mc.collection.Declares(func) returns = mc.collection.Returns(func) cur = end # Parameters params = mc.collection.Params(func, cur=cur) if self.code[cur] == "(": end = findend.paren(self, cur) params.code = self.code[cur+1:end] L = iterate.comma_list(self, cur) for array in L: for s,e in array: if self.disp: print "%4d Param " % cur, print "%-20s" % "functions.function", print repr(self.code[s:e+1]) var = mc.collection.Var(params, self.code[s:e+1], cur=s, code=self.code[s:e+1]) cur = end cur += 1 cur = self.create_codeblock(func, cur) # Postfix for var in returns: var.create_declare() end = cur func.code = self.code[START:end+1] mc.collection.Header(func.program[4], func.name) return cur
def lambda_func(self, node, cur): """ Anonymous function content. Support function of `lambda_assign`. Args: self (Builder): Code constructor parent (Node): Parent node cur (int): Current position in code Returns: int : Index to end of function line """ if self.code[cur] != "@": self.syntaxerror(cur, "anonymous function indicator (@)") end = cur +1 while self.code[end] in " \t": end += 1 if self.code[end] != "(": self.syntaxerror(end, "anonymous function argument list") end = findend.paren(self, end) end += 1 while self.code[end] in " \t": end += 1 end = findend.expression(self, end) if self.disp: print "%4d Lambda " % cur, print "%-20s" % "functions.lambda_func", print repr(self.code[cur:end+1]) if node.cls == "Assign": name = node[0].name else: name = "lambda" funcs = node.program[1] name = "_%s" % (name) if name in funcs.names: i = 0 while name+"%d" % i in funcs.names: i += 1 name = name + "%d" % i func = mc.collection.Func(funcs, name, cur=cur, code=self.code[cur:end+1]) declares = mc.collection.Declares(func) returns = mc.collection.Returns(func) params = mc.collection.Params(func) k = cur+1 while self.code[k] in " \t": k += 1 if self.code[k] != "(": self.syntaxerror(k, "anonymous function argument list") cur = self.create_list(params, k) cur += 1 while self.code[cur] in " \t": cur += 1 block = mc.collection.Block(func) assign = mc.collection.Assign(block) var = mc.collection.Var(assign, "_retval") cur = self.create_expression(assign, cur, end=end) for n in assign[1].flatten(): if (n.cls in ("Get", "Cget", "Var", "Fvar", "Fget", "Sget")) and n.name in node.func[0].names + node.func[2].names: n.create_declare() var = mc.collection.Var(returns, "_retval") var.create_declare() lamb = mc.collection.Lambda(node, name) lamb.reference = func return cur
def multi(self, parent, cur, eq_loc): """ Assignment with multiple return Args: self (Builder): Code constructor. parent (Node): Parent node cur (int): Current position in code eq_loc (int): position of the assignment marker ('='-sign) Returns: int: Index to end of assignment Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "[a,b] = c") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Assigns assign.multi '[a,b] = c' 1 Var variables.assign 'a' 3 Var variables.assign 'b' 8 Expression expression.create 'c' 8 Var variables.variable 'c' >>> builder.configure() >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Assigns unknown TYPE c 1 2| | Var unknown TYPE a 1 4| | Var unknown TYPE b 1 9| | Var unknown TYPE c """ if self.code[cur] != "[": self.syntaxerror(cur, "multi-assign start") if self.code[eq_loc] != "=": self.syntaxerror(cur, "assignment sign (=)") j = eq_loc + 1 while self.code[j] in " \t.": if self.code[j] == ".": j = findend.dots(self, j) + 1 else: j += 1 end = findend.expression(self, j) if self.disp: print "%4d Assigns " %\ cur, print "%-20s" % "assign.multi", print repr(self.code[cur:end + 1]) if identify.space_delimited(self, cur): l = iterate.space_list(self, cur) else: l = iterate.comma_list(self, cur) if len(l[0]) == 1: return self.create_assign(parent, l[0][0][0], eq_loc) assigns = mc.collection.Assigns(parent, cur=cur, code=self.code[cur:end + 1]) for vector in l: for start, stop in vector: self.create_assign_variable(assigns, start, end=stop) cur = eq_loc + 1 while self.code[cur] in " \t": cur += 1 cur_ = self.create_expression(assigns, cur) assigns.name = assigns[-1].name return cur_
def single(self, parent, cur, eq_loc): """ Assignment with single return. Args: self (Builder): Code constructor parent (Node): Parent node cur (int): Current position in code eq_loc (int): position of the assignment marker ('='-sign) Returns: int: Index to end of assignment Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "a=b") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Assign assign.single 'a=b' 0 Var variables.assign 'a' 2 Expression expression.create 'b' 2 Var variables.variable 'b' >>> builder.configure() >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Assign unknown TYPE b 1 1| | Var unknown TYPE a 1 3| | Var unknown TYPE b """ if self.code[cur] not in c.letters: self.syntaxerror(cur, "assignment start") if self.code[eq_loc] != "=": self.syntaxerror(cur, "assignment indicator (=)") j = eq_loc + 1 while self.code[j] in " \t": j += 1 end = findend.expression(self, j) if self.disp: print "%4d Assign " %\ cur, print "%-20s" % "assign.single", print repr(self.code[cur:end + 1]) assign = mc.collection.Assign(parent, cur=cur, code=self.code[cur:end + 1]) cur = self.create_assign_variable(assign, cur, eq_loc) cur += 1 while self.code[cur] in " \t": cur += 1 if self.code[cur] == "]": cur += 1 while self.code[cur] in " \t": cur += 1 if self.code[cur] != "=": self.syntaxerror(cur, "assignment indicator (=)") k = cur + 1 while self.code[k] in " \t": k += 1 self.create_expression(assign, k, end) assign.name = assign[-1].name if len(assign) != 2: self.syntaxerror(k, "single assign when multi-assign") return end
def create(self, node, start, end=None, start_opr=None): """ Create expression in three steps: 1) In order, split into sub-expressions for each dividing operator 2) Address prefixes, postfixes, parenthesises, etc. 3) Identify the remaining singleton Args: self (Builder): Code constructor. node (Node): Reference to the parent node start (int): current possition in code end (int, optional): end of expression. Required for space-delimited expression. start_opr (str, optional): At which operator the recursive process is. (For internal use) Returns: int : index to end of the expression Examples:: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "a*b+c/d") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Statement codeblock.codeblock 'a*b+c/d' 0 Expression expression.create 'a*b+c/d' 0 Expression expression.create 'a*b' 0 Expression expression.create 'a' 0 Var variables.variable 'a' 2 Expression expression.create 'b' 2 Var variables.variable 'b' 4 Expression expression.create 'c/d' 4 Expression expression.create 'c' 4 Var variables.variable 'c' 6 Expression expression.create 'd' 6 Var variables.variable 'd' >>> builder.configure(suggest=False) >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Statement code_block TYPE 1 1| | Plus expression TYPE 1 1| | | Mul expression TYPE 1 1| | | | Var unknown TYPE a 1 3| | | | Var unknown TYPE b 1 5| | | Matrixdivisionexpression TYPE 1 5| | | | Var unknown TYPE c 1 7| | | | Var unknown TYPE d """ if self.code[start:start+3] == "...": start = findend.dots(self, start) start += 1 while self.code[start] in " \t": start += 1 if self.code[start] == ":": if self.disp: print "%4d Expression " % (start), print "%-20s" % "expression.create", print repr(self.code[start:start+1]) print "%4d All " % (start), print "%-20s" % "expression.create", print repr(self.code[start:start+1]) mc.collection.All(node, cur=start, code=self.code[start]) return start if end is None: end = findend.expression(self, start) if self.disp: print "%4d Expression " % (start), print "%-20s" % "expression.create", print repr(self.code[start:end+1]) if self.code[start] not in c.e_start: self.syntaxerror(start, "expression start") operators = [ "||", "&&", "|", "&", "~=", "==", ">=", ">", "<=", "<", ":", "+", "-", ".*", "*", "./", "/", ".\\", "\\", ".^", "^"] if not (start_opr is None): operators = operators[operators.index(start_opr)+1:] for opr in operators: # Pre-screen if opr not in self.code[start:end+1]: continue starts = [start] last = start ends = [] k = start while True: if self.code[k] == "(": k = last = findend.paren(self, k) elif self.code[k] == "[": k = last = findend.matrix(self, k) elif self.code[k] == "{": k = last = findend.cell(self, k) elif self.code[k] == "'": if identify.string(self, k): k = last = findend.string(self, k) else: last = k elif opr == self.code[k:k+len(opr)]: if opr in "+-": # no prefixes and no (scientific) numbers if self.code[last] not in c.letters+c.digits+")]}" or\ self.code[k-1] in "dDeE" and self.code[k-2] in\ c.digits+"." and self.code[k+1] in c.digits: k += 1 continue k += len(opr)-1 while self.code[k+1] in " \t": k += 1 # no all-operator if opr == ":" and self.code[k+1] in ",;\n)]}": k += 1 continue starts.append(k+1) ends.append(last) elif self.code[k] in c.letters+c.digits+"_": last = k k += 1 if k >= end: ends.append(end) break if len(ends)>1: node = retrieve_operator(self, opr)(node) node.cur = start node.code = self.code[starts[0]:ends[-1]+1] for s,e in zip(starts, ends): create(self, node, s, e, opr) return end # All operators removed at this point! END = end # Prefixes while self.code[start] in "-~": if self.code[start] == "-": node = mc.collection.Neg(node, cur=start, code=self.code[start:end+1]) start += 1 if self.code[start] == "~": node = mc.collection.Not(node, cur=start, code=self.code[start:end+1]) start += 1 while self.code[start] in " \t": start += 1 # Postfixes if self.code[end] == "'" and not self.code[start] == "'": if self.code[end-1] == ".": node = mc.collection.Transpose(node, cur=start, code=self.code[start:end+1]) end -= 2 else: node = mc.collection.Ctranspose(node, cur=start, code=self.code[start:end+1]) node.cur = start node.code = self.code[start:end+1] end -= 1 while self.code[end] in " \t": end -= 1 # Parenthesis if self.code[start] == "(": if self.code[end] != ")": self.syntaxerror(end, "parenthesis end") node = mc.collection.Paren(node, cur=start, code=self.code[start:end+1]) start += 1 while self.code[start] in " \t": start += 1 end -= 1 while self.code[end] in " \t": end -= 1 return create(self, node, start, end) # Reserved keywords elif self.code[start:start+3] == "end": # and self.code[start+3] in " \t" + c.e_end: node = mc.collection.End(node, cur=start, code=self.code[start:start+3]) elif self.code[start:start+6] == "return" and self.code[start+6] in " ,;\n": node = mc.collection.Return(node, cur=start, code=self.code[start:start+6]) elif self.code[start:start+5] == "break" and self.code[start+5] in " ,;\n": node = mc.collection.Break(node, cur=start, code=self.code[start:start+5]) # Rest elif self.code[start] == "'": if self.code[end] != "'": self.syntaxerror(end, "string end") if "\n" in self.code[start:end]: self.syntaxerror(end, "non line-feed characters in string") mc.collection.String(node, self.code[start+1:end], cur=start, code=self.code[start:end+1]) elif self.code[start] in c.digits or\ self.code[start] == "." and self.code[start+1] in c.digits: cur = self.create_number(node, start) elif self.code[start] == "[": cur = self.create_matrix(node, start) elif self.code[start] == "{": cur = self.create_cell(node, start) else: if self.code[start] not in c.letters+"@": self.syntaxerror(start, "variable name") cur = self.create_variable(node, start) return END
def lambda_func(self, node, cur): """ Anonymous function content. Support function of `lambda_assign`. Args: self (Builder): Code constructor parent (Node): Parent node cur (int): Current position in code Returns: int : Index to end of function line """ if self.code[cur] != "@": self.syntaxerror(cur, "anonymous function indicator (@)") end = cur + 1 while self.code[end] in " \t": end += 1 if self.code[end] != "(": self.syntaxerror(end, "anonymous function argument list") end = findend.paren(self, end) end += 1 while self.code[end] in " \t": end += 1 end = findend.expression(self, end) if self.disp: print "%4d Lambda " % cur, print "%-20s" % "functions.lambda_func", print repr(self.code[cur:end + 1]) if node.cls == "Assign": name = node[0].name else: name = "lambda" funcs = node.program[1] name = "_%s" % (name) if name in funcs.names: i = 0 while name + "%d" % i in funcs.names: i += 1 name = name + "%d" % i func = mc.collection.Func(funcs, name, cur=cur, code=self.code[cur:end + 1]) declares = mc.collection.Declares(func) returns = mc.collection.Returns(func) params = mc.collection.Params(func) k = cur + 1 while self.code[k] in " \t": k += 1 if self.code[k] != "(": self.syntaxerror(k, "anonymous function argument list") cur = self.create_list(params, k) cur += 1 while self.code[cur] in " \t": cur += 1 block = mc.collection.Block(func) assign = mc.collection.Assign(block) var = mc.collection.Var(assign, "_retval") cur = self.create_expression(assign, cur, end=end) for n in assign[1].flatten(): if (n.cls in ("Get", "Cget", "Var", "Fvar", "Fget", "Sget") ) and n.name in node.func[0].names + node.func[2].names: n.create_declare() var = mc.collection.Var(returns, "_retval") var.create_declare() lamb = mc.collection.Lambda(node, name) lamb.reference = func return cur
def function(self, parent, cur): """ Explicit functions Args: self (Builder): Code constructor parent (Node): Parent node cur (int): Current position in code Returns: int : Index to end of function Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "function f(); end") loading unnamed Program functions.program 0 Function functions.function 'function f()' 12 Codeblock codeblock.codeblock >>> builder.configure(suggest=False) >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Funcs program TYPE unnamed 1 1| Func func_returns TYPE f 1 1| | Declares func_returns TYPE 1 1| | Returns func_returns TYPE 1 11| | Params func_returns TYPE 1 13| | Block code_block TYPE """ if self.code[cur:cur + 8] != "function": self.syntaxerror(cur, "function start") if self.code[cur + 8] not in c.k_end + "[": self.syntaxerror(cur, "function name or return values") START = cur k = cur + 8 while self.code[k] in " \t": k += 1 if self.code[k] not in c.letters + "[": self.syntaxerror(k, "function name or return values") start = k k = findend.expression(self, k) end = k k += 1 while self.code[k] in " \t": k += 1 # with return values if self.code[k] == "=": k += 1 while self.code[k] in " \t.": if self.code[k:k + 3] == "...": k = findend.dots(self, k) + 1 else: k += 1 l = k if self.code[l] not in c.letters: self.syntaxerror(l, "function name") while self.code[l + 1] in c.letters + c.digits + "_": l += 1 m = l + 1 while self.code[m] in " \t": m += 1 if self.code[m] == "(": m = findend.paren(self, m) else: m = l if self.disp: print "%4d Function " % cur, print "%-20s" % "functions.function", print repr(self.code[START:m + 1]) name = self.code[k:l + 1] func = mc.collection.Func(parent, name, cur=cur) mc.collection.Declares(func, code="") returns = mc.collection.Returns(func, code=self.code[start:end + 1]) # multi-return if self.code[start] == "[": if identify.space_delimited(self, start): L = iterate.space_list(self, start) else: L = iterate.comma_list(self, start) end = START for array in L: for s, e in array: end = s if self.disp: print "%4d Return " % cur, print "%-20s" % "functions.function", print repr(self.code[s:e + 1]) if not any([a in c.letters+c.digits+"_@" \ for a in self.code[s:e+1]]): self.syntaxerror(s, "return value") mc.collection.Var(returns, self.code[s:e + 1], cur=s, code=self.code[s:e + 1]) # single return else: end = findend.expression(self, start) if self.disp: print "%4d Return " % cur, print repr(self.code[start:end + 1]) mc.collection.Var(returns, self.code[start:end + 1], cur=start, code=self.code[start:end + 1]) cur = l + 1 while self.code[cur] in " \t": cur += 1 # No returns else: m = k if self.code[m] == "(": m = findend.paren(self, m) else: m = end if self.disp: print "%4d Function " % cur, print "%-20s" % "functions.function", print repr(self.code[START:m + 1]) end = start + 1 while self.code[end] in c.letters + "_": end += 1 name = self.code[start:end] func = mc.collection.Func(parent, name, cur=cur) mc.collection.Declares(func) returns = mc.collection.Returns(func) cur = end # Parameters params = mc.collection.Params(func, cur=cur) if self.code[cur] == "(": end = findend.paren(self, cur) params.code = self.code[cur + 1:end] L = iterate.comma_list(self, cur) for array in L: for s, e in array: if self.disp: print "%4d Param " % cur, print "%-20s" % "functions.function", print repr(self.code[s:e + 1]) var = mc.collection.Var(params, self.code[s:e + 1], cur=s, code=self.code[s:e + 1]) cur = end cur += 1 cur = self.create_codeblock(func, cur) # Postfix for var in returns: var.create_declare() end = cur func.code = self.code[START:end + 1] mc.collection.Header(func.program[4], func.name) return cur
def single(self, parent, cur, eq_loc): """ Assignment with single return. Args: self (Builder): Code constructor parent (Node): Parent node cur (int): Current position in code eq_loc (int): position of the assignment marker ('='-sign) Returns: int: Index to end of assignment Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "a=b") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Assign assign.single 'a=b' 0 Var variables.assign 'a' 2 Expression expression.create 'b' 2 Var variables.variable 'b' >>> builder.configure() >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Assign unknown TYPE b 1 1| | Var unknown TYPE a 1 3| | Var unknown TYPE b """ if self.code[cur] not in c.letters: self.syntaxerror(cur, "assignment start") if self.code[eq_loc] != "=": self.syntaxerror(cur, "assignment indicator (=)") j = eq_loc + 1 while self.code[j] in " \t": j += 1 end = findend.expression(self, j) if self.disp: print "%4d Assign " % cur, print "%-20s" % "assign.single", print repr(self.code[cur : end + 1]) assign = mc.collection.Assign(parent, cur=cur, code=self.code[cur : end + 1]) cur = self.create_assign_variable(assign, cur, eq_loc) cur += 1 while self.code[cur] in " \t": cur += 1 if self.code[cur] == "]": cur += 1 while self.code[cur] in " \t": cur += 1 if self.code[cur] != "=": self.syntaxerror(cur, "assignment indicator (=)") k = cur + 1 while self.code[k] in " \t": k += 1 self.create_expression(assign, k, end) assign.name = assign[-1].name if len(assign) != 2: self.syntaxerror(k, "single assign when multi-assign") return end
def multi(self, parent, cur, eq_loc): """ Assignment with multiple return Args: self (Builder): Code constructor. parent (Node): Parent node cur (int): Current position in code eq_loc (int): position of the assignment marker ('='-sign) Returns: int: Index to end of assignment Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "[a,b] = c") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Assigns assign.multi '[a,b] = c' 1 Var variables.assign 'a' 3 Var variables.assign 'b' 8 Expression expression.create 'c' 8 Var variables.variable 'c' >>> builder.configure() >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Assigns unknown TYPE c 1 2| | Var unknown TYPE a 1 4| | Var unknown TYPE b 1 9| | Var unknown TYPE c """ if self.code[cur] != "[": self.syntaxerror(cur, "multi-assign start") if self.code[eq_loc] != "=": self.syntaxerror(cur, "assignment sign (=)") j = eq_loc + 1 while self.code[j] in " \t.": if self.code[j] == ".": j = findend.dots(self, j) + 1 else: j += 1 end = findend.expression(self, j) if self.disp: print "%4d Assigns " % cur, print "%-20s" % "assign.multi", print repr(self.code[cur : end + 1]) if identify.space_delimited(self, cur): l = iterate.space_list(self, cur) else: l = iterate.comma_list(self, cur) if len(l[0]) == 1: return self.create_assign(parent, l[0][0][0], eq_loc) assigns = mc.collection.Assigns(parent, cur=cur, code=self.code[cur : end + 1]) for vector in l: for start, stop in vector: self.create_assign_variable(assigns, start, end=stop) cur = eq_loc + 1 while self.code[cur] in " \t": cur += 1 cur_ = self.create_expression(assigns, cur) assigns.name = assigns[-1].name return cur_