parameters: (context,string,fmt=None,add=False)
docstring: Returns an Expression from a string.  In auto mode, this reads in constants in klampt.loader JSON-
      compatible format, standard variables in the form "x", user data in the form of strings prepended with $
      (e.g., "$x"), and named expression references in the form of strings prepended with @.
  
      Args:
          context (Context): the context containing possible functions in string
          string (str): the string to parse.
          fmt (str, optional): specifies a format for the string.  Can be None (auto), 'auto', or 'json'
          add (bool, optional): if true, adds all variables referenced in the string to the context. 
              Otherwise, undefined variables are referred to as user data.
  
      An exception is raised on parsing failure.
  
      (Parsing is a little slow, so try not to use it in tight inner loops)
  
      Returns:
          (Expression): the expression represented by str.
docstring_summary: Returns an Expression from a string.  In auto mode, this reads in constants in klampt.loader JSON-
      compatible format, standard variables in the form "x", user data in the form of strings prepended with $
      (e.g., "$x"), and named expression references in the form of strings prepended with @.
docstring_tokens: Returns an Expression from a string . In auto mode this reads in constants in klampt . loader JSON - compatible format standard variables in the form x user data in the form of strings prepended with $ ( e . g . $x ) and named expression references in the form of strings prepended with @ .
function: def exprFromStr(context,string,fmt=None,add=False):
      """Returns an Expression from a string.  In auto mode, this reads in constants in klampt.loader JSON-
      compatible format, standard variables in the form "x", user data in the form of strings prepended with $
      (e.g., "$x"), and named expression references in the form of strings prepended with @.
  
      Args:
          context (Context): the context containing possible functions in string
          string (str): the string to parse.
          fmt (str, optional): specifies a format for the string.  Can be None (auto), 'auto', or 'json'
          add (bool, optional): if true, adds all variables referenced in the string to the context. 
              Otherwise, undefined variables are referred to as user data.
  
      An exception is raised on parsing failure.
  
      (Parsing is a little slow, so try not to use it in tight inner loops)
  
      Returns:
          (Expression): the expression represented by str.
      """
      if len(string) == 0:
          raise ValueError("Empty string provided")
      if fmt == None:
          if string[0] == '{':
              fmt = 'json'
          else:
              fmt = 'auto'
      if fmt == 'auto':
          import re,ast
          USERDATA_MARKER = '___'
          EXPR_MARKER = '____'
          TAGLIST_NAME = '__tagexprlist__'
          taglist = context.expressions.copy()
          def __settag__(self,tagname,taglist):
              assert isinstance(tagname,ConstantExpression) and isinstance(tagname.value,str)
              taglist[tagname.value] = self
              return self
          def __gettag__(tagname,taglist):
              assert isinstance(tagname,ConstantExpression) and isinstance(tagname.value,str)
              return taglist[tagname.value]
          Expression.__settag__ = __settag__
  
          x = re.sub(r"\$(\w+)", r"___\1",string)
          x = re.sub(r"\#(\w+)", r'.__settag__("\1",__tagexprlist__)',x)
          x = re.sub(r"\@(\w+)", r'__gettag__("\1",__tagexprlist__)',x)
          #print "Substituted string",x
          tree = ast.parse(x,mode='eval')
          missing_functions = []
          missing_names = []
          userdata = {}
          #hack to easily access functions with the class.attribute syntax
          allFunctions = _builtin_functions.copy()
          for name,func in context.customFunctions.iteritems():
              path = name.split('.')
              if len(path) == 1:
                  allFunctions[name] = func
              else:
                  if path[0] not in allFunctions:
                      allFunctions[path[0]] = _Object() 
                  root = allFunctions[path[0]]
                  for n in path[1:-1]:
                      if not hasattr(root,n):
                          setattr(root,n,_Object())
                      root = getattr(root,n)
                  setattr(root,path[-1],func)
          allFunctions[TAGLIST_NAME] = taglist
          allFunctions['__gettag__'] = __gettag__
  
          class RewriteVarNames(ast.NodeTransformer):
              def __init__(self):
                  self.infunc = False
              def visit_Call(self,node):
                  self.infunc = True
                  self.generic_visit(node)
                  return node
              def visit_Name(self, node):
                  if self.infunc:
                      self.infunc = False
                      if node.id not in allFunctions:
                          missing_functions.append(node.id)
                      return node
                  if node.id.startswith(USERDATA_MARKER):
                      basename = node.id[len(USERDATA_MARKER):]
                      userdata[node.id] = expr(basename)
                  else:
                      if node.id in context.variableDict:
                          userdata[node.id] = expr(context.variableDict[node.id])
                      elif add:
                          userdata[node.id] = expr(context.addVar(node.id,'N'))
                      elif node.id == TAGLIST_NAME:
                          pass
                      else:
                          missing_names.append(node.id)
                          userdata[node.id] = expr(node.id)
                  return node
              def visit_Num(self, node):
                  return ast.copy_location(ast.Call(func=ast.copy_location(ast.Name(id="_const",ctx=ast.Load()),node),args=[node],keywords=[]),node)
              def visit_Str(self, node):
                  return ast.copy_location(ast.Call(func=ast.copy_location(ast.Name(id="_const",ctx=ast.Load()),node),args=[node],keywords=[]),node)
              def visit_List(self, node):
                  args = []
                  for idx, item in enumerate(node.elts):
                      args.append(self.visit(item))
                  return ast.copy_location(ast.Call(func=ast.copy_location(ast.Name(id="_convert_list",ctx=ast.Load()),node),args=args,keywords=[]),node)
              def visit_Tuple(self, node):
                  args = []
                  for idx, item in enumerate(node.elts):
                      args.append(self.visit(item))
                  return ast.copy_location(ast.Call(func=ast.copy_location(ast.Name(id="_convert_list",ctx=ast.Load()),node),args=args,keywords=[]),node)
  
          #print "old tree:",ast.dump(tree)
          newtree = RewriteVarNames().visit(tree)
          #print "new tree:",ast.dump(newtree)
          if len(missing_functions) > 0:
              raise ValueError("Undefined functions "+','.join(missing_functions))
          if len(missing_names) > 0:
              raise ValueError("Undefined variable "+','.join(missing_names))
          allFunctions['_const'] = const
          allFunctions['_convert_list'] = lambda *args:array(*args)
          ctree = compile(newtree, filename="<ast>", mode="eval")
          res = eval(ctree,allFunctions,userdata)
          delattr(Expression,'__settag__')
          return res
      elif fmt == 'json':
          import json
          obj = json.parse(str)
          return exprFromJson(context,obj)
      else:
          raise ValueError("Invalid format "+fmt)
function_tokens: def exprFromStr ( context , string , fmt = None , add = False ) : if len ( string ) == 0 : raise ValueError ( "Empty string provided" ) if fmt == None : if string [ 0 ] == '{' : fmt = 'json' else : fmt = 'auto' if fmt == 'auto' : import re , ast USERDATA_MARKER = '___' EXPR_MARKER = '____' TAGLIST_NAME = '__tagexprlist__' taglist = context . expressions . copy ( ) def __settag__ ( self , tagname , taglist ) : assert isinstance ( tagname , ConstantExpression ) and isinstance ( tagname . value , str ) taglist [ tagname . value ] = self return self def __gettag__ ( tagname , taglist ) : assert isinstance ( tagname , ConstantExpression ) and isinstance ( tagname . value , str ) return taglist [ tagname . value ] Expression . __settag__ = __settag__ x = re . sub ( r"\$(\w+)" , r"___\1" , string ) x = re . sub ( r"\#(\w+)" , r'.__settag__("\1",__tagexprlist__)' , x ) x = re . sub ( r"\@(\w+)" , r'__gettag__("\1",__tagexprlist__)' , x ) #print "Substituted string",x tree = ast . parse ( x , mode = 'eval' ) missing_functions = [ ] missing_names = [ ] userdata = { } #hack to easily access functions with the class.attribute syntax allFunctions = _builtin_functions . copy ( ) for name , func in context . customFunctions . iteritems ( ) : path = name . split ( '.' ) if len ( path ) == 1 : allFunctions [ name ] = func else : if path [ 0 ] not in allFunctions : allFunctions [ path [ 0 ] ] = _Object ( ) root = allFunctions [ path [ 0 ] ] for n in path [ 1 : - 1 ] : if not hasattr ( root , n ) : setattr ( root , n , _Object ( ) ) root = getattr ( root , n ) setattr ( root , path [ - 1 ] , func ) allFunctions [ TAGLIST_NAME ] = taglist allFunctions [ '__gettag__' ] = __gettag__ class RewriteVarNames ( ast . NodeTransformer ) : def __init__ ( self ) : self . infunc = False def visit_Call ( self , node ) : self . infunc = True self . generic_visit ( node ) return node def visit_Name ( self , node ) : if self . infunc : self . infunc = False if node . id not in allFunctions : missing_functions . append ( node . id ) return node if node . id . startswith ( USERDATA_MARKER ) : basename = node . id [ len ( USERDATA_MARKER ) : ] userdata [ node . id ] = expr ( basename ) else : if node . id in context . variableDict : userdata [ node . id ] = expr ( context . variableDict [ node . id ] ) elif add : userdata [ node . id ] = expr ( context . addVar ( node . id , 'N' ) ) elif node . id == TAGLIST_NAME : pass else : missing_names . append ( node . id ) userdata [ node . id ] = expr ( node . id ) return node def visit_Num ( self , node ) : return ast . copy_location ( ast . Call ( func = ast . copy_location ( ast . Name ( id = "_const" , ctx = ast . Load ( ) ) , node ) , args = [ node ] , keywords = [ ] ) , node ) def visit_Str ( self , node ) : return ast . copy_location ( ast . Call ( func = ast . copy_location ( ast . Name ( id = "_const" , ctx = ast . Load ( ) ) , node ) , args = [ node ] , keywords = [ ] ) , node ) def visit_List ( self , node ) : args = [ ] for idx , item in enumerate ( node . elts ) : args . append ( self . visit ( item ) ) return ast . copy_location ( ast . Call ( func = ast . copy_location ( ast . Name ( id = "_convert_list" , ctx = ast . Load ( ) ) , node ) , args = args , keywords = [ ] ) , node ) def visit_Tuple ( self , node ) : args = [ ] for idx , item in enumerate ( node . elts ) : args . append ( self . visit ( item ) ) return ast . copy_location ( ast . Call ( func = ast . copy_location ( ast . Name ( id = "_convert_list" , ctx = ast . Load ( ) ) , node ) , args = args , keywords = [ ] ) , node ) #print "old tree:",ast.dump(tree) newtree = RewriteVarNames ( ) . visit ( tree ) #print "new tree:",ast.dump(newtree) if len ( missing_functions ) > 0 : raise ValueError ( "Undefined functions " + ',' . join ( missing_functions ) ) if len ( missing_names ) > 0 : raise ValueError ( "Undefined variable " + ',' . join ( missing_names ) ) allFunctions [ '_const' ] = const allFunctions [ '_convert_list' ] = lambda * args : array ( * args ) ctree = compile ( newtree , filename = "<ast>" , mode = "eval" ) res = eval ( ctree , allFunctions , userdata ) delattr ( Expression , '__settag__' ) return res elif fmt == 'json' : import json obj = json . parse ( str ) return exprFromJson ( context , obj ) else : raise ValueError ( "Invalid format " + fmt )