def parse_expr(self, k, v, context): if isinstance(v, (bool, int, float)): return Assignment(k, self, v) elif isinstance(v, basestring): return Assignment(k, self, parse(v, context)) else: # lets be explicit about it return None
def all_symbols(self, global_context): from links import PrefixingLink symbols = WarnOverrideDict(self.variables.copy()) local_context = global_context.copy() local_context[self.name] = symbols local_context['__entity__'] = self.name macros = dict((k, parse(v, local_context)) for k, v in self.macro_strings.iteritems()) symbols.update(macros) symbols['other'] = PrefixingLink(self, macros, self.links, '__other_') symbols.update(self.methods) return symbols
def execute(self, s): entity = self.entity if entity is None: raise Exception(entity_required) period = self.period if period is None: raise Exception(period_required) entity_name = self.entity.name parse_ctx = self.parse_ctx.copy() local_parse_ctx = parse_ctx[entity_name].copy() # add all currently defined temp_variables because otherwise # local variables (defined within a function) wouldn't be available local_parse_ctx.update((name, Variable(entity, name)) for name in entity.temp_variables.keys()) parse_ctx[entity_name] = local_parse_ctx expr = parse(s, parse_ctx, interactive=True) result = expr_eval(expr, self.eval_ctx) if result is None: print("done.") return result
def evaluate(s, parse_ctx, eval_ctx): expr = parse(s, parse_ctx) return expr.evaluate(eval_ctx)
def parse_expressions(self, items, context): """ items -- a list of tuples (name, process_string) context -- parsing context a dict of all symbols available for all entities """ processes = [] for k, v in items: if k == 'while': if not isinstance(v, dict): raise ValueError("while is a reserved keyword") cond = parse(v['cond'], context) assert isinstance(cond, Expr) code = self.parse_process_group("while:code", v['code'], context, purge=False) process = While(k, self, cond, code) else: process = self.parse_expr(k, v, context) if process is None: if self.ismethod(v): if isinstance(v, list): # v should be a list of dicts (assignments) or # strings (actions) argnames, code_def, result_def = [], v, None else: assert isinstance(v, dict) args_def = v.get('args', '') argnames = [a.strip() for a in args_def.split(',') if a != ''] code_def = v.get('code', []) result_def = v.get('return') method_context = self.get_group_context(context, argnames) code = self.parse_process_group("func:code", code_def, method_context, purge=False) #TODO: use code.predictors instead (but it currently # fails for some reason) or at least factor this out # with the code in parse_process_group group_expressions = [elem.items()[0] if isinstance(elem, dict) else (None, elem) for elem in code_def] group_predictors = \ self.collect_predictors(group_expressions) method_context = self.get_group_context( method_context, group_predictors) result = parse(result_def, method_context) assert result is None or isinstance(result, Expr) process = Function(k, self, argnames, code, result) elif isinstance(v, dict) and 'predictor' in v: raise ValueError("Using the 'predictor' keyword is " "not supported anymore. " "If you need several processes to " "write to the same variable, you " "should rather use procedures.") else: raise Exception("unknown expression type for %s: %s" % (k, type(v))) processes.append((k, process)) return processes
def parse_expressions(self, items, context, functions_only=False): """ items -- a list of tuples (name, process_string) context -- parsing context a dict of all symbols available for all entities functions_only -- whether non-functions processes are allowed """ processes = [] for k, v in items: if k == 'while': if isinstance(v, dict): raise SyntaxError(""" This syntax for while is not supported anymore: - while: cond: {cond_expr} code: - ... Please use this instead: - while {cond_expr}: - ... """.format(cond_expr=v['cond'])) else: raise ValueError("while is a reserved keyword") elif k is not None and k.startswith('while '): if not isinstance(v, list): raise SyntaxError("while is a reserved keyword") cond = parse(k[6:].strip(), context) assert isinstance(cond, Expr) code = self.parse_process_group("while_code", v, context, purge=False) process = While(k, self, cond, code) elif k == 'return': e = SyntaxError("return is a reserved keyword. To return " "from a function, use 'return expr' " "instead of 'return: expr'") e.liam2context = "while parsing: return: {}".format(v) raise e elif k is None and isinstance(v, str) and v.startswith('return'): assert len(v) == 6 or v[6] == ' ' if len(v) > 6: result_def = v[7:].strip() else: result_def = None result_expr = parse(result_def, context) process = Return(None, self, result_expr) else: process = self.parse_expr(k, v, context) if process is not None and functions_only: if k in self.fields.names: msg = """defining a process outside of a function is deprecated because it is ambiguous. You should: * wrap the '{name}: {expr}' assignment inside a function like this: compute_{name}: # you can name it any way you like but simply \ '{name}' is not recommended ! - {name}: {expr} * update the simulation.processes list to use 'compute_{name}' (the function \ name) instead of '{name}'. """ else: msg = """defining a process outside of a function is \ deprecated because it is ambiguous. 1) If '{name}: {expr}' is an assignment ('{name}' stores the result of \ '{expr}'), you should: * wrap the assignment inside a function, for example, like this: compute_{name}: # you can name it any way you like but simply \ '{name}' is not recommended ! - {name}: {expr} * update the simulation.processes list to use 'compute_{name}' (the function \ name) instead of '{name}'. * add '{name}' in the entities fields with 'output: False' 2) otherwise if '{expr}' is an expression which does not return any value, you \ can simply transform it into a function, like this: {name}: - {expr} """ warnings.warn(msg.format(name=k, expr=v), UserDeprecationWarning) if process is None: if self.ismethod(v): if isinstance(v, dict): args = v.get('args', '') code = v.get('code', '') result = v.get('return', '') oldargs = "\n args: {}".format(args) \ if args else '' oldcode = "\n code:\n - ..." \ if code else '' newcode = "\n - ..." if code else '' oldresult = "\n return: " + result \ if result else '' newresult = "\n - return " + result \ if result else '' template = """ This syntax for defining functions with arguments or a return value is not supported anymore: {funcname}:{oldargs}{oldcode}{oldresult} Please use this instead: {funcname}({newargs}):{newcode}{newresult}""" msg = template.format(funcname=k, oldargs=oldargs, oldcode=oldcode, oldresult=oldresult, newargs=args, newcode=newcode, newresult=newresult) raise SyntaxError(msg) assert isinstance(v, list) # v should be a list of dicts (assignments) or # strings (actions) if "(" in k: k, args = split_signature(k) argnames = argspec(args).args code_def, result_def = v, None else: argnames, code_def, result_def = [], v, None method_context = self.get_group_context( context, argnames) code = self.parse_process_group(k + "_code", code_def, method_context, purge=False) # TODO: use code.predictors instead (but it currently # fails for some reason) or at least factor this out # with the code in parse_process_group group_expressions = [ elem.items()[0] if isinstance(elem, dict) else (None, elem) for elem in code_def ] group_predictors = \ self.collect_predictors(group_expressions) method_context = self.get_group_context( method_context, group_predictors) result_expr = parse(result_def, method_context) assert result_expr is None or \ isinstance(result_expr, Expr) process = Function(k, self, argnames, code, result_expr) elif isinstance(v, dict) and 'predictor' in v: raise ValueError("Using the 'predictor' keyword is " "not supported anymore. " "If you need several processes to " "write to the same variable, you " "should rather use functions.") elif k is None and v is None: raise ValueError("empty process found ('-')") else: raise Exception("unknown expression type for " "%s: %s (%s)" % (k, v, type(v))) processes.append((k, process)) return processes
def parse_expressions(self, items, context, functions_only=False): """ items -- a list of tuples (name, process_string) context -- parsing context a dict of all symbols available for all entities functions_only -- whether non-functions processes are allowed """ processes = [] for k, v in items: if k == 'while': if isinstance(v, dict): raise SyntaxError(""" This syntax for while is not supported anymore: - while: cond: {cond_expr} code: - ... Please use this instead: - while {cond_expr}: - ... """.format(cond_expr=v['cond'])) else: raise ValueError("while is a reserved keyword") elif k is not None and k.startswith('while '): if not isinstance(v, list): raise SyntaxError("while is a reserved keyword") cond = parse(k[6:].strip(), context) assert isinstance(cond, Expr) code = self.parse_process_group("while_code", v, context, purge=False) process = While(k, self, cond, code) elif k == 'return': e = SyntaxError("return is a reserved keyword. To return " "from a function, use 'return expr' " "instead of 'return: expr'") e.liam2context = "while parsing: return: {}".format(v) raise e elif k is None and isinstance(v, str) and v.startswith('return'): assert len(v) == 6 or v[6] == ' ' if len(v) > 6: result_def = v[7:].strip() else: result_def = None result_expr = parse(result_def, context) process = Return(None, self, result_expr) else: process = self.parse_expr(k, v, context) if process is not None and functions_only: if k in self.fields.names: msg = """defining a process outside of a function is deprecated because it is ambiguous. You should: * wrap the '{name}: {expr}' assignment inside a function like this: compute_{name}: # you can name it any way you like but simply \ '{name}' is not recommended ! - {name}: {expr} * update the simulation.processes list to use 'compute_{name}' (the function \ name) instead of '{name}'. """ else: msg = """defining a process outside of a function is \ deprecated because it is ambiguous. 1) If '{name}: {expr}' is an assignment ('{name}' stores the result of \ '{expr}'), you should: * wrap the assignment inside a function, for example, like this: compute_{name}: # you can name it any way you like but simply \ '{name}' is not recommended ! - {name}: {expr} * update the simulation.processes list to use 'compute_{name}' (the function \ name) instead of '{name}'. * add '{name}' in the entities fields with 'output: False' 2) otherwise if '{expr}' is an expression which does not return any value, you \ can simply transform it into a function, like this: {name}: - {expr} """ warnings.warn(msg.format(name=k, expr=v), UserDeprecationWarning) if process is None: if self.ismethod(v): if isinstance(v, dict): args = v.get('args', '') code = v.get('code', '') result = v.get('return', '') oldargs = "\n args: {}".format(args) \ if args else '' oldcode = "\n code:\n - ..." \ if code else '' newcode = "\n - ..." if code else '' oldresult = "\n return: " + result \ if result else '' newresult = "\n - return " + result \ if result else '' template = """ This syntax for defining functions with arguments or a return value is not supported anymore: {funcname}:{oldargs}{oldcode}{oldresult} Please use this instead: {funcname}({newargs}):{newcode}{newresult}""" msg = template.format(funcname=k, oldargs=oldargs, oldcode=oldcode, oldresult=oldresult, newargs=args, newcode=newcode, newresult=newresult) raise SyntaxError(msg) assert isinstance(v, list) # v should be a list of dicts (assignments) or # strings (actions) if "(" in k: k, args = split_signature(k) argnames = argspec(args).args code_def, result_def = v, None else: argnames, code_def, result_def = [], v, None method_context = self.get_group_context(context, argnames) code = self.parse_process_group(k + "_code", code_def, method_context, purge=False) # TODO: use code.predictors instead (but it currently # fails for some reason) or at least factor this out # with the code in parse_process_group group_expressions = [elem.items()[0] if isinstance(elem, dict) else (None, elem) for elem in code_def] group_predictors = \ self.collect_predictors(group_expressions) method_context = self.get_group_context( method_context, group_predictors) result_expr = parse(result_def, method_context) assert result_expr is None or \ isinstance(result_expr, Expr) process = Function(k, self, argnames, code, result_expr) elif isinstance(v, dict) and 'predictor' in v: raise ValueError("Using the 'predictor' keyword is " "not supported anymore. " "If you need several processes to " "write to the same variable, you " "should rather use functions.") elif k is None and v is None: raise ValueError("empty process found ('-')") else: raise Exception("unknown expression type for " "%s: %s (%s)" % (k, v, type(v))) processes.append((k, process)) return processes