def assign(self, node, cur, end=None): """ Variable left side of an assignment Args: self (Builder): Code constructor node (Node): Parent node cur (int): Current position in code Kwargs: end (int, optional): End of variable Returns: int : End of variable Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "a = 4") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Assign assign.single 'a = 4' 0 Var variables.assign 'a' 4 Expression expression.create '4' 4 Int misc.number '4' >>> builder.configure(suggest=False) >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Assign int int 1 1| | Var unknown (int) a 1 5| | Int int int """ if self.code[cur] not in c.letters: self.syntaxerror(cur, "assign variable name") k = cur + 1 while self.code[k] in c.letters + c.digits + "_": k += 1 name = self.code[cur:k] last = k while self.code[k] in " \t": k += 1 # Get value of cell if self.code[k] == "{": end = findend.cell(self, k) end = end + 1 while self.code[end] in " \t": end += 1 if self.code[end] == "(": end = findend.paren(self, end) node = mc.collection.Cset(node, name, cur=cur, code=self.code[cur:end + 1]) if self.disp: print "%4d Cset " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end + 1]) n_fields = 0 while self.code[k] == "{": cur = self.iterate_cell(node, k) k = cur + 1 while self.code[k] in " \t": k += 1 n_fields += 1 while self.code[k] in " \t": k += 1 if self.code[k] != "(": self.syntaxerror(k, "parenthesis start") cur = self.create_list(node, k) node["n_fields"] = n_fields node["n_args"] = len(node) - n_fields else: end = findend.cell(self, k) node = mc.collection.Cvar(node, name, cur=cur, code=self.code[cur:end + 1]) if self.disp: print "%4d Cvar " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end + 1]) num = 0 while self.code[k] == "{": cur = self.iterate_cell(node, k) k = cur + 1 while self.code[k] in " \t": k += 1 num += 1 # Set value of array elif self.code[k] == "(": end = findend.paren(self, k) if self.code[end + 1] == "." and self.code[end + 2] in c.letters: start = end + 2 end += 2 while self.code[end] in c.letters + c.digits + "_": end += 1 value = self.code[start:end] if self.disp: print "%4d Sset " %\ cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end]) node = mc.collection.Sset(node, name, value, cur=cur, code=self.code[cur:end], pointer=1) last = self.create_list(node, k) cur = end - 1 else: if self.disp: print "%4d Set " %\ cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end + 1]) node = mc.collection.Set(node, name, cur=cur, code=self.code[cur:end + 1]) last = self.create_list(node, k) cur = last elif self.code[k] == ".": k += 1 # Fieldname of type "a.() = ..." if self.code[k] == "(": end = findend.paren(self, k) k += 1 while self.code[k] in " \t": k += 1 if self.disp: print "%4d Nset " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end + 1]) node = mc.collection.Nset(node, name) node.cur = cur node.code = self.code[cur:end + 1] cur = self.create_expression(node, cur) elif self.code[k] in c.letters: j = k + 1 while self.code[j] in c.letters + c.digits + "_.": j += 1 value = self.code[k:j] last = j - 1 while self.code[j] in " \t": j += 1 # Fieldname of type "a.b(...) = ..." if self.code[j] == "(": end = findend.paren(self, j) if self.disp: print "%4d Fset " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end + 1]) node = mc.collection.Fset(node, name, value=value, cur=cur, code=self.code[cur:end + 1]) cur = self.create_list(node, j) # Fieldname of type "a.b = ..." else: if self.disp: print "%4d Fvar " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:last + 1]) node = mc.collection.Fvar(node, name, value=value, cur=cur, code=self.code[cur:last + 1]) cur = last # Simple variable assignment else: if self.disp: print "%4d Var " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:last]) node = mc.collection.Var(node, name, cur=cur, code=self.code[cur:last]) cur = last - 1 node.create_declare() return cur
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 variable(self, parent, cur): """ Variable not on the left side of an assignment Args: self (Builder): Code constructor node (Node): Parent node cur (int): Current position in code Kwargs: end (int, optional): End of variable Returns: int : End of variable Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "a") 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' >>> 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 """ k = cur if self.code[k] == "@": k += 1 if self.code[k] not in c.letters: self.syntaxerror(k, "variable name") k += 1 while self.code[k] in c.letters + c.digits + "_": k += 1 name = self.code[cur:k] last = k while self.code[k] in " \t": k += 1 # Get value of cell if self.code[k] == "{": end = findend.cell(self, k) end = end + 1 while self.code[end] in " \t": end += 1 if self.code[end] == "(": end = findend.paren(self, end) node = mc.collection.Cget(parent, name, cur=cur, code=self.code[cur:end + 1]) if self.disp: print "%4d Cget " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end + 1]) n_fields = 0 while self.code[k] == "{": cur = self.iterate_cell(node, k) k = cur + 1 while self.code[k] in " \t": k += 1 n_fields += 1 while self.code[k] in " \t": k += 1 if self.code[k] != "(": self.syntaxerror(k, "argument parenthesis") cur = self.create_list(node, k) node["n_fields"] = n_fields node["n_args"] = len(node) - n_fields else: end = findend.cell(self, k) node = mc.collection.Cvar(parent, name, cur=cur, code=self.code[cur:end + 1]) if self.disp: print "%4d Cvar " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end + 1]) num = 0 while self.code[k] == "{": cur = cell_arg(self, node, k) k = cur + 1 while self.code[k] in " \t": k += 1 num += 1 # Get value of array elif self.code[k] == "(": end = findend.paren(self, k) if self.code[end + 1] == "." and self.code[end + 2] in c.letters: start = end + 2 end += 2 while self.code[end] in c.letters + c.digits + "_": end += 1 value = self.code[start:end] if self.disp: print "%4d Sget " %\ cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end]) node = mc.collection.Sget(parent, name, value, cur=cur, code=self.code[cur:end], pointer=1) last = self.create_list(node, k) cur = end else: if self.disp: print "%4d Get " %\ cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end + 1]) node = mc.collection.Get(parent, name, cur=cur, code=self.code[cur:end + 1]) last = self.create_list(node, k) cur = last elif self.code[k] == "." and self.code[k + 1] not in "*/\\^'": k += 1 # Fieldname of type "a.(..)" if self.code[k] == "(": end = findend.paren(self, k) if self.disp: print "%4d Nget " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end + 1]) k += 1 while self.code[k] in " \t": k += 1 node = mc.collection.Nget(parent, name, cur=cur, code=self.code[cur:end + 1]) cur = self.create_expression(node, k) elif self.code[k] in c.letters: j = k + 1 while self.code[j] in c.letters + c.digits + "_": j += 1 value = self.code[k:j] last = j while self.code[j] in " \t": j += 1 # Fieldname of type "a.b(...)" if self.code[j] == "(": end = findend.paren(self, j) if self.disp: print "%4d Fget " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end + 1]) node = mc.collection.Fget(parent, name, cur=cur, value=value, code=self.code[cur:end + 1]) j += 1 while self.code[j] in " \t": j += 1 cur = self.create_expression(node, j) node.create_declare() # Fieldname of type "a.b" else: if self.disp: print "%4d Fvar " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:last]) node = mc.collection.Fvar(parent, name, value=value, cur=cur, code=self.code[cur:last]) cur = last - 1 node.create_declare() # Simple variable else: if self.disp: print "%4d Var " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:last]) node = mc.collection.Var(parent, name, cur=cur, code=self.code[cur:last]) cur = last - 1 while self.code[cur] in " \t": 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 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 space_delimited(self, start): """ Check if list is space-delimited Args: self (Builder): Code constructor start (int): Current position in code Returns: bool: True if list consists of whitespace delimiters """ 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 c.l_end: return False if self.code[k] not in c.e_start: self.syntaxerror(k, "expression start") if self.code[k] == "'": k = findend.string(self, k) + 1 while self.code[k] in " \t": k += 1 while True: if self.code[k] == "(": k = findend.paren(self, k) elif self.code[k] == "[": k = findend.matrix(self, k) elif self.code[k] == "{": k = findend.cell(self, k) elif self.code[k] == "'": # if self.code[k-1] in c.s_start: return True elif self.code[k : k + 3] == "...": k = findend.dots(self, k) elif self.code[k] in " \t": if space_delimiter(self, k): return True while self.code[k + 1] in " \t": k += 1 elif self.code[k] in c.e_end: if self.code[k] == ",": return False elif self.code[k] in c.l_end: return False elif self.code[k] != ";": return True while self.code[k + 1] in " \t": k += 1 elif self.code[k + 1] in c.letters + c.digits + "_@": while self.code[k + 1] in c.letters + c.digits + "_@": k += 1 k += 1
def assign(self, node, cur, end=None): """ Variable left side of an assignment Args: self (Builder): Code constructor node (Node): Parent node cur (int): Current position in code Kwargs: end (int, optional): End of variable Returns: int : End of variable Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "a = 4") loading unnamed Program functions.program 0 Main functions.main 0 Codeblock codeblock.codeblock 0 Assign assign.single 'a = 4' 0 Var variables.assign 'a' 4 Expression expression.create '4' 4 Int misc.number '4' >>> builder.configure(suggest=False) >>> print mc.qtree(builder, core=True) # doctest: +NORMALIZE_WHITESPACE 1 1Block code_block TYPE 1 1| Assign int int 1 1| | Var unknown (int) a 1 5| | Int int int """ if self.code[cur] not in c.letters: self.syntaxerror(cur, "assign variable name") k = cur+1 while self.code[k] in c.letters+c.digits+"_": k += 1 name = self.code[cur:k] last = k while self.code[k] in " \t": k += 1 # Get value of cell if self.code[k] == "{": end = findend.cell(self, k) end = end+1 while self.code[end] in " \t": end += 1 if self.code[end] == "(": end = findend.paren(self, end) node = mc.collection.Cset(node, name, cur=cur, code=self.code[cur:end+1]) if self.disp: print "%4d Cset " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end+1]) n_fields = 0 while self.code[k] == "{": cur = self.iterate_cell(node, k) k = cur+1 while self.code[k] in " \t": k += 1 n_fields += 1 while self.code[k] in " \t": k += 1 if self.code[k] != "(": self.syntaxerror(k, "parenthesis start") cur = self.create_list(node, k) node["n_fields"] = n_fields node["n_args"] = len(node) - n_fields else: end = findend.cell(self, k) node = mc.collection.Cvar(node, name, cur=cur, code=self.code[cur:end+1]) if self.disp: print "%4d Cvar " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end+1]) num = 0 while self.code[k] == "{": cur = self.iterate_cell(node, k) k = cur+1 while self.code[k] in " \t": k += 1 num += 1 # Set value of array elif self.code[k] == "(": end = findend.paren(self, k) if self.code[end+1] == "." and self.code[end+2] in c.letters: start = end+2 end += 2 while self.code[end] in c.letters+c.digits+"_": end += 1 value = self.code[start:end] if self.disp: print "%4d Sset " %\ cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end]) node = mc.collection.Sset(node, name, value, cur=cur, code=self.code[cur:end], pointer=1) last = self.create_list(node, k) cur = end-1 else: if self.disp: print "%4d Set " %\ cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end+1]) node = mc.collection.Set(node, name, cur=cur, code=self.code[cur:end+1]) last = self.create_list(node, k) cur = last elif self.code[k] == ".": k += 1 # Fieldname of type "a.() = ..." if self.code[k] == "(": end = findend.paren(self, k) k += 1 while self.code[k] in " \t": k += 1 if self.disp: print "%4d Nset " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end+1]) node = mc.collection.Nset(node, name) node.cur = cur node.code = self.code[cur:end+1] cur = self.create_expression(node, cur) elif self.code[k] in c.letters: j = k+1 while self.code[j] in c.letters+c.digits+"_.": j += 1 value = self.code[k:j] last = j-1 while self.code[j] in " \t": j += 1 # Fieldname of type "a.b(...) = ..." if self.code[j] == "(": end = findend.paren(self, j) if self.disp: print "%4d Fset " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:end+1]) node = mc.collection.Fset(node, name, value=value, cur=cur, code=self.code[cur:end+1]) cur = self.create_list(node, j) # Fieldname of type "a.b = ..." else: if self.disp: print "%4d Fvar " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:last+1]) node = mc.collection.Fvar(node, name, value=value, cur=cur, code=self.code[cur:last+1]) cur = last # Simple variable assignment else: if self.disp: print "%4d Var " % cur, print "%-20s" % "variables.assign", print repr(self.code[cur:last]) node = mc.collection.Var(node, name, cur=cur, code=self.code[cur:last]) cur = last-1 node.create_declare() return cur
def variable(self, parent, cur): """ Variable not on the left side of an assignment Args: self (Builder): Code constructor node (Node): Parent node cur (int): Current position in code Kwargs: end (int, optional): End of variable Returns: int : End of variable Example: >>> builder = mc.Builder(True) >>> builder.load("unnamed", "a") 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' >>> 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 """ k = cur if self.code[k] == "@": k += 1 if self.code[k] not in c.letters: self.syntaxerror(k, "variable name") k += 1 while self.code[k] in c.letters+c.digits+"_": k += 1 name = self.code[cur:k] last = k while self.code[k] in " \t": k += 1 # Get value of cell if self.code[k] == "{": end = findend.cell(self, k) end = end+1 while self.code[end] in " \t": end += 1 if self.code[end] == "(": end = findend.paren(self, end) node = mc.collection.Cget(parent, name, cur=cur, code=self.code[cur:end+1]) if self.disp: print "%4d Cget " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end+1]) n_fields = 0 while self.code[k] == "{": cur = self.iterate_cell(node, k) k = cur+1 while self.code[k] in " \t": k += 1 n_fields += 1 while self.code[k] in " \t": k += 1 if self.code[k] != "(": self.syntaxerror(k, "argument parenthesis") cur = self.create_list(node, k) node["n_fields"] = n_fields node["n_args"] = len(node) - n_fields else: end = findend.cell(self, k) node = mc.collection.Cvar(parent, name, cur=cur, code=self.code[cur:end+1]) if self.disp: print "%4d Cvar " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end+1]) num = 0 while self.code[k] == "{": cur = cell_arg(self, node, k) k = cur+1 while self.code[k] in " \t": k += 1 num += 1 # Get value of array elif self.code[k] == "(": end = findend.paren(self, k) if self.code[end+1] == "." and self.code[end+2] in c.letters: start = end+2 end += 2 while self.code[end] in c.letters+c.digits+"_": end += 1 value = self.code[start:end] if self.disp: print "%4d Sget " %\ cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end]) node = mc.collection.Sget(parent, name, value, cur=cur, code=self.code[cur:end], pointer=1) last = self.create_list(node, k) cur = end else: if self.disp: print "%4d Get " %\ cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end+1]) node = mc.collection.Get(parent, name, cur=cur, code=self.code[cur:end+1]) last = self.create_list(node, k) cur = last elif self.code[k] == "." and self.code[k+1] not in "*/\\^'": k += 1 # Fieldname of type "a.(..)" if self.code[k] == "(": end = findend.paren(self, k) if self.disp: print "%4d Nget " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end+1]) k += 1 while self.code[k] in " \t": k += 1 node = mc.collection.Nget(parent, name, cur=cur, code=self.code[cur:end+1]) cur = self.create_expression(node, k) elif self.code[k] in c.letters: j = k+1 while self.code[j] in c.letters+c.digits+"_": j += 1 value = self.code[k:j] last = j while self.code[j] in " \t": j += 1 # Fieldname of type "a.b(...)" if self.code[j] == "(": end = findend.paren(self, j) if self.disp: print "%4d Fget " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:end+1]) node = mc.collection.Fget(parent, name, cur=cur, value=value, code=self.code[cur:end+1]) j += 1 while self.code[j] in " \t": j += 1 cur = self.create_expression(node, j) node.create_declare() # Fieldname of type "a.b" else: if self.disp: print "%4d Fvar " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:last]) node = mc.collection.Fvar(parent, name, value=value, cur=cur, code=self.code[cur:last]) cur = last-1 node.create_declare() # Simple variable else: if self.disp: print "%4d Var " % cur, print "%-20s" % "variables.variable", print repr(self.code[cur:last]) node = mc.collection.Var(parent, name, cur=cur, code=self.code[cur:last]) cur = last-1 while self.code[cur] in " \t": cur += 1 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 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 space_delimited(self, start): """ Check if list is space-delimited Args: self (Builder): Code constructor start (int): Current position in code Returns: bool: True if list consists of whitespace delimiters """ 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 c.l_end: return False if self.code[k] not in c.e_start: self.syntaxerror(k, "expression start") if self.code[k] == "'": k = findend.string(self, k) + 1 while self.code[k] in " \t": k += 1 while True: if self.code[k] == "(": k = findend.paren(self, k) elif self.code[k] == "[": k = findend.matrix(self, k) elif self.code[k] == "{": k = findend.cell(self, k) elif self.code[k] == "'" and string(self, k): #k = findend.string(self, k) #if self.code[k-1] in c.s_start: return True elif self.code[k:k + 3] == "...": k = findend.dots(self, k) elif self.code[k] in " \t": if space_delimiter(self, k): return True while self.code[k + 1] in " \t": k += 1 elif self.code[k] in c.e_end: if self.code[k] == ",": return False elif self.code[k] in c.l_end: return False elif self.code[k] != ";": return True while self.code[k + 1] in " \t": k += 1 elif self.code[k + 1] in c.letters + c.digits + "_@": while self.code[k + 1] in c.letters + c.digits + "_@": k += 1 k += 1