def direct_env(env: AbstractExpression, or_current: bool = False) -> AbstractExpression: """ Return an ``DesignatedEnv`` struct to mean a direct environment value. :param or_current: If True, return ``current_env()`` when ``env`` evaluates to ``No(T.LexicalEnv)``. Otherwise, return the empty env direct environment instead, which is equivalent to ``no_env()``. """ if or_current: return cast(Any, env).then( lambda non_null_env: T.DesignatedEnv.new( kind=T.DesignatedEnvKind.resolve_value("direct_env"), env_name=No(T.Symbol), direct_env=non_null_env, ), default_val=current_env(), ) else: return T.DesignatedEnv.new( kind=T.DesignatedEnvKind.resolve_value("direct_env"), env_name=No(T.Symbol), direct_env=env, )
def named_env(name: AbstractExpression, or_current: bool = False) -> AbstractExpression: """ Return an ``DesignatedEnv`` struct to mean a named env. :param or_current: If True, return ``current_env()`` when ``name`` evaluates to ``No(T.Symbol)``. Otherwise, return the named env for the null symbol instead, which is equivalent to ``no_env()``. """ if or_current: return cast(Any, name).then( lambda non_null_name: T.DesignatedEnv.new( kind=T.DesignatedEnvKind.resolve_value("named_env"), env_name=non_null_name, direct_env=No(T.LexicalEnv), ), default_val=current_env(), ) else: return T.DesignatedEnv.new( kind=T.DesignatedEnvKind.resolve_value("named_env"), env_name=name, direct_env=No(T.LexicalEnv), )
def current_env() -> AbstractExpression: """ Return an ``DesignatedEnv`` struct to mean the current environment. """ return T.DesignatedEnv.new( kind=T.DesignatedEnvKind.resolve_value("current_env"), env_name=No(T.Symbol), direct_env=No(T.LexicalEnv), )
def no_env() -> AbstractExpression: """ Return a ``DesignatedEnv`` struct to mean no destination environment. """ return T.DesignatedEnv.new( kind=T.DesignatedEnvKind.resolve_value("none"), env_name=No(T.Symbol), direct_env=No(T.LexicalEnv), )
def construct(self): # Accept as a prefix: # # * any pointer, since it can be checked against "null"; # * any StructType, since structs are nullable; # * any LexicalEnvType, which has EmptyEnv as a null value. expr = construct( self.expr, lambda cls: (cls.is_ptr or cls.is_struct_type or cls.is_lexical_env_type), 'Invalid prefix type for .then: {expr_type}') self.var_expr.set_type(expr.type) # Create a then-expr specific scope to restrict the span of the "then" # variable in the debugger. with PropertyDef.get_scope().new_child() as then_scope: then_scope.add(self.var_expr.local_var) then_expr = construct(self.then_expr) var_expr = construct(self.var_expr) then_expr = BindingScope(then_expr, [var_expr], scope=then_scope) # Affect default value to the fallback expression if self.default_val is None: check_source_language( then_expr.type.null_allowed or then_expr.type is T.BoolType, "Then expression should have a default value provided," " in cases where the provided function's return type (here" " {}) does not have a default null value".format( then_expr.type.dsl_name)) default_expr = construct(No(then_expr.type)) else: default_expr = construct(self.default_val, then_expr.type) return Then.Expr(expr, construct(self.var_expr), then_expr, default_expr, then_scope)
def new_env_assoc(key, val, dest_env=None, metadata=None): """ Create a new env assoc, providing basic defaults when fields are not specified. :param AbstractExpression key: The symbol for which to associate a value. :param AbstractExpression val: The node to associate to the key. :param AbstractExpression dest_env: The environment in which to insert the mapping. If this expression evaluates to the empty environment, the mapping will be added to the initial env, e.g. the currently bound env or whatever was specified using the set_initial_env construct. :param AbstractExpression metadata: Additional metadata to associate to the node. """ return T.env_assoc.new( key=key, val=val, dest_env=No(T.LexicalEnv) if dest_env is None else dest_env, metadata=No(T.defer_env_md) if metadata is None else metadata)
def construct(self): # Add var_expr to the scope for this Then expression PropertyDef.get_scope().add(self.var_expr.local_var) # Accept as a prefix: # * any pointer, since it can be checked against "null"; # * any Struct, since its "Is_Null" field can be checked. expr = construct(self.expr, lambda cls: cls.is_ptr or issubclass(cls, Struct)) self.var_expr.set_type(expr.type) then_expr = construct(self.then_expr) # Affect default value to the fallback expression. For the moment, # only booleans and structs are handled. if self.default_val is None: if then_expr.type.matches(BoolType): default_expr = construct(False) elif issubclass(then_expr.type, Struct): default_expr = construct( No( # Because we're doing issubclass instead of isinstance, # PyCharm do not understand that then_exp.type is a Struct, # so the following is necessary not to have warnings. assert_type(then_expr.type, Struct))) elif then_expr.type.matches(LexicalEnvType): default_expr = construct(EmptyEnv) elif then_expr.type.matches(Symbol): default_expr = LiteralExpr(Symbol.nullexpr(), Symbol) else: # The following is not actually used but PyCharm's typer # requires it. default_expr = None check_source_language( False, "Then expression should have a default value provided, " "in cases where the provided function's return type is " "not Bool, here {}".format(then_expr.type.name().camel)) else: default_expr = construct(self.default_val, then_expr.type) return Then.Expr(expr, construct(self.var_expr), then_expr, default_expr)
def new_env_assoc(key, value, dest_env=None, metadata=None): """ Create a new env assoc, providing basic defaults when fields are not specified. :param AbstractExpression key: The symbol for which to associate a value. :param AbstractExpression value: The node to associate to the key. :param AbstractExpression dest_env: The environment in which to insert the mapping (a DesignatedEnv struct value). If left to None, use the current environment. :param AbstractExpression metadata: Additional metadata to associate to the node. """ return T.env_assoc.new( key=key, value=value, dest_env=current_env() if dest_env is None else dest_env, metadata=No(T.defer_env_md) if metadata is None else metadata )
def env_group(self, env_array, with_md=None): """ Return a new lexical environment that logically groups together multiple environments. `env_array` must be an array that contains the environments to be grouped. If it is empty, the empty environment is returned. If provided, `with_md` must be a metadata structure: it will be made the default metadata for this lexical environment. :type env_array: AbstractExpression :type with_md: AbstractExpression """ from langkit.expressions import No if not with_md: with_md = No(T.env_md) return CallExpr('Group_Env', 'Group', T.LexicalEnv, [construct(env_array, T.LexicalEnv.array), construct(with_md, T.env_md)], abstract_expr=self)