class FooNode(ASTNode): pred = Property(True) foo_1 = Property( If(Self.pred, No(T.BarNode), No(T.Literal)).as_bare_entity, public=True )
def name_parent(): """ Assuming this node can define a named environment, return the syntactic parent node that defines the parent scope for Self. If there is no such node (because Self is in the root list), return null. """ return If( Self.parent.is_null | Not(Self.parent.is_a(T.FooNode.list)) | Self.parent.parent.is_null | Not(Self.parent.parent.is_a(T.DeclarativePart)) | Self.parent.parent.parent.is_null, No(T.FooNode), # All nodes that can define a named environment are supposed to # live in lists (Self.parent is a list), so Self.parent.parent is # supposed to be a declarative part, and finally Self.parent.parent # gets the node that owns that declarative part. Let( lambda owner=Self.parent.parent.parent: If( owner.is_a( T.PackageDecl, T.PackageBody, T.SubpDecl, T.SubpBody, T.SubpBodyDecls, T.PublicPart, T.PrivatePart ), owner.match( lambda pp=T.PublicPart: pp.parent, lambda pp=T.PrivatePart: pp.parent, lambda n: n, ), No(T.FooNode), ) ) )
def rebind(from_node=T.FooNode.entity, to_node=T.FooNode.entity): # Build non-null rebindings rbdng = Var(No(T.EnvRebindings).append_rebinding( from_node.children_env, to_node.children_env )) # Call rebind_env on them (this is the important part, the rest is # cosmetic). return No(T.LexicalEnv).rebind_env(rbdng).get("foo")
class FunDecl(FooNode): name = Field(type=T.Identifier) args = Field(type=T.ArgSpec.list) env_spec = EnvSpec( add_to_env( T.env_assoc.new( key=Self.name.symbol, val=Self, dest_env=No(T.LexicalEnv), metadata=No(T.Metadata), )))
class ConsDecl(FooNode): name = Field(type=T.Identifier) cons_expr = Field(type=T.Expr) env_spec = EnvSpec( add_to_env( T.env_assoc.new( key=Self.name.symbol, val=Self, dest_env=No(T.LexicalEnv), metadata=No(T.Metadata), )))
class FooNode(ASTNode): null_unit = Property(No(AnalysisUnit), public=True) null_node = Property(No(T.Expression.entity), public=True) deref_null_unit = Property(Self.null_unit.root.as_bare_entity, public=True) deref_null_node = Property(Self.null_node.null_node, public=True) null_node_unit = Property(Self.null_node.unit, public=True) cast_null_node = Property(Self.null_node.cast(T.Name), public=True) match_null_node = Property( Self.null_node.node.match(lambda l=T.Literal: l, lambda n=T.Name: n, lambda others: others).as_bare_entity, public=True)
def arg_exprs_assocs_getter(): """ For each argument, associate its name to its default expression. """ decl = Var(Self.node_env.get_first(Self.name).cast(T.FunDecl)) return decl.args.map(lambda a: T.inner_env_assoc.new( key=a.name.symbol, value=a.arg_expr.node, metadata=No(T.env_md)))
class Example(FooNode): name = Field(type=T.Id) dest_scope = Field(type=T.Id) content = Field(type=T.Id.list) @langkit_property() def has_kw(kw=T.Symbol): """ Return whether "content" contains the ``kw`` keyword. """ return Self.content.map(lambda c: c.symbol).contains(kw) env_spec = EnvSpec( add_env(names=[Self.name.symbol]), add_to_env_kv( key=Self.name.symbol, value=Self, # Check correct behavior when the env argument is null or not (when # it's not, add to the parents' env), and when or_current=True is # passed or not (current = Self's env). dest_env=Let(lambda name=If( Self.has_kw("null_name"), No(T.Symbol), Self.dest_scope.symbol, ): If( Self.has_kw("or_current"), named_env(name, or_current=True), named_env(name), ))), )
def test_arrays(): empty = Var(No(T.Example.array)) single = Var(ArrayLiteral([Self.cast(Example)])) complete = Var(Self.parent.cast(T.Example.list).as_array) arr = Var(empty.concat(single).concat(complete)) return arr.length # BREAK:test_arrays
def get_entity(md=Metadata): return New(Couple.entity, node=Self, info=New(T.entity_info, md=md, rebindings=No(EnvRebindings), from_rebound=False))
def get_rebindings(inverse=T.Bool): example_nodes = Var(Self.parent.cast(T.Example.list).as_array) n1 = Var(example_nodes.at(If(inverse, 1, 2))) n2 = Var(example_nodes.at(If(inverse, 2, 1))) return No(T.EnvRebindings).append_rebinding( n1.children_env, n2.children_env, )
def find_atoms(): return Entity.match( # This should match Lit .. Ref lambda a=T.Atom: a.singleton, # This should match Def | Plus .. FooNode.list lambda _: No(T.Atom.entity.array), ).concat(Entity.children.mapcat(lambda c: c.find_atoms))
def args_assocs_getter(): """ For each argument, associate its name to the expression passed in this call. """ decl = Var(Self.node_env.get_first(Self.name).cast(T.FunDecl)) return decl.args.map(lambda i, a: T.inner_env_assoc.new( key=a.name.symbol, value=Self.args.at(i), metadata=No(T.env_md)))
class RegularBlock(FooNode): id = Field(type=T.Identifier) env_spec = EnvSpec( set_initial_env_by_name(Self.id.symbol, No(T.LexicalEnv))) @lazy_field(public=True) def synth(): return T.SynthNode.new(id=Self.id)
def test_struct_iterator(): val = Var(TestStruct.new( count=2, nodes=[No(Example.entity), Entity], )) itr = Var( ArrayLiteral([val, val], element_type=TestStruct).to_iterator) return ArrayLiteral([itr, itr], element_type=T.TestStruct.iterator).to_iterator
def parent_scope_name(): """ Absolute name of the scope that defines this name, assuming that ``prefix`` is the implicit prefix for that name. """ return Self.match( lambda _=Identifier: No(T.String), lambda dn=DottedName: dn.prefix.scope_name, )
class Scope(Def): error = Field() name = Field() defs = Field() env_spec = EnvSpec( add_to_env(New(T.env_assoc, key=Self.name.symbol, val=Self)), add_env(), do(If(Self.error.as_bool, PropertyError(T.FooNode), No(T.FooNode))), )
def rebind(): left_env = Var(Self.left.children_env) right_env = Var(Self.right.children_env) # Depending on whether "left_env" is rebindable, the following will # succeed or raise a PropertyError. The status of "right_env" does not # matter. r = Var(No(T.EnvRebindings).append_rebinding(left_env, right_env)) return Self.children_env.rebind_env(r).env_node
class Def(FooNode): name = Field(type=T.Name) ref = Field(type=T.Name) env_spec = EnvSpec( add_to_env(mappings=New(T.env_assoc, key=Self.name.sym, val=Self), metadata=New(Metadata, node=Self.ref.then(lambda r: r.resolve.node, default_val=No( T.FooNode)))))
class Literal(Expression): token_node = True # This one is private, but it is called by "evaluate" so it's not usused result = ExternalProperty(uses_entity_info=False, uses_envs=False) # See Expression.name names = Property(No(T.Name.array)) evaluate = Property(Self.result, public=True)
def decl_parent_scope_name(): """ If this node can define a named environment (see ``can_have_name``), return the name of its parent scope. Return a null symbol otherwise. """ return If( Self.can_have_name, Self.name_parent.then( lambda np: np.full_name, default_val=Self.self_name.parent_scope_name, ).to_symbol, No(T.Symbol))
def find_atoms_or_exprs(): return Entity.match( # This should match Lit .. Ref lambda a=T.Atom: a.cast(T.Expr).singleton, # This should match the only remaining expression: Plus lambda e=T.Expr: e.singleton, # This should match Def | FooNode.list lambda _: No(T.Expr.entity.array), ).concat(Entity.children.mapcat(lambda c: c.find_atoms_or_exprs))
class PackageDecl(FooNode): name = Field(type=T.Name) public_part = Field(type=T.PublicPart) private_part = Field(type=T.PrivatePart) @langkit_property(return_type=T.Name) def self_name(): return Self.name @langkit_property(return_type=T.Symbol.array) def new_env_names(): """ Return the names for the environment that this package creates. """ # Always register the "regular" name for this package result = Self.full_name # If there is a private part, that's all we need. Otherwise, register # this environment with the name of the private part as well, so that # package bodies can assume there is always a private part. return If( result.length == 0, No(T.Symbol.array), If( Self.private_part.is_null, [result, result.concat(String('.__privatepart'))], [result], ).map(lambda s: s.to_symbol) ) env_spec = EnvSpec( set_initial_env_by_name( If( Self.is_toplevel, Self.decl_parent_scope_name, No(T.Symbol), ), Self.parent.children_env ), add_to_env_kv(Self.name.base_name.to_symbol, Self), add_env(names=Self.new_env_names) ) @langkit_property(return_type=T.PackageBody.entity, public=True) def body_part(): """ Return the PackageBody node corresponding to this PackageDecl. """ return Self.private_part.then( lambda pp: pp, default_val=Self, ).children_env.get_first('__nextpart').cast(T.PackageBody)
def find_exprs(): return Entity.match( # This should match Lit .. Plus lambda e=T.Expr: e.singleton, # This should match nothing (Atom is an Expr subclass), so emit a # warning. lambda a=T.Atom: a.cast(T.Expr).singleton, # This should match Def | FooNode.list lambda _: No(T.Expr.entity.array), ).concat(Entity.children.mapcat(lambda c: c.find_exprs))
class Example(BaseExample): fld_2 = NullField() fld_1 = Field() @langkit_property() def to_public(p=T.PrivatePoint): return Point.new(label=String("from private"), x=p.x, y=p.y) @langkit_property(public=True) def prop(p=T.Point): return Self.to_public(PrivatePoint.new(x=p.x, y=p.y)) @langkit_property(public=True) def result(): return T.NodeResult.new(n=Self, e=Entity) # Test for primitive types id_bool = Property(lambda id=T.Bool: id, public=True) id_int = Property(lambda id=T.Int: id, public=True) id_bigint = Property(lambda id=T.BigInt: id, public=True) id_char = Property(lambda id=T.Character: id, public=True) id_token = Property(lambda id=T.Token: id, public=True) id_sym = Property(lambda id=T.Symbol: id, public=True) id_unit = Property(lambda id=T.AnalysisUnit: id, public=True) id_root_node = Property(lambda id=T.FooNode: id, public=True) id_name = Property(lambda id=T.Name: id, public=True) # Test for enums id_unit_kind = Property(lambda id=T.AnalysisUnitKind: id, public=True) # Test for arrays id_node_array = Property(lambda id=T.FooNode.entity.array: id, public=True) id_expr_array = Property(lambda id=T.Expr.entity.array: id, public=True) id_bigint_array = Property(lambda id=T.BigInt.array: id, public=True) id_unit_array = Property(lambda id=T.AnalysisUnit.array: id, public=True) # Test for iterators create_bigint_iterator = Property( ArrayLiteral([BigIntLiteral(1), BigIntLiteral(2), BigIntLiteral(3)]) .to_iterator, public=True ) id_bigint_iterator = Property(lambda id=T.BigInt.iterator: id, public=True) # Test for default values id_dflt_bool = Property(lambda id=(T.Bool, True): id, public=True) id_dflt_int = Property(lambda id=(T.Int, 42): id, public=True) id_dflt_char = Property( lambda id=(T.Character, CharacterLiteral('\x00')): id, public=True) id_dflt_root_node = Property(lambda id=(T.FooNode, No(T.FooNode)): id, public=True)
def find_refs(): return Entity.match( # This should match Ref lambda r=T.Ref: r.singleton, # This should match Lit lambda _: No(T.Ref.entity.array), # ... and we should not get CASE coverage errors in generated code, # even though we did not cover all possible FooNode kinds. ).concat( Entity.children.mapcat( lambda c: c.cast_or_raise(T.Expr).find_refs))
def test_rebindings(): null = Var(No(T.EnvRebindings)) r1 = Var(Self.get_rebindings(False)) r2 = Var(Self.get_rebindings(True)) concat = Var(r1.concat_rebindings(r2)) arr = Var(ArrayLiteral([ null, r1, r2, concat, ])) return arr.length # BREAK:test_rebindings
class SingleParam(PythonNode): is_varargs = Field(type=T.VarArgsFlag) is_kwargs = Field(type=T.KwArgsFlag) name = Field(type=T.PythonNode) default_value = Field(type=T.Expr) env_spec = EnvSpec( add_to_env( Self.name.match( lambda i=T.Id: new_env_assoc(key=i.sym, val=Self).singleton, lambda l=T.Id.list: l.map(lambda i: new_env_assoc(key=i.sym, val=Self)), lambda _: No(T.env_assoc.array))))
class Number(Expr): token_node = True @langkit_property(external=True, uses_entity_info=False, uses_envs=False) def eval(): pass # Test for default values id_dflt_bool = Property(lambda id=(T.Bool, True): id, public=True) id_dflt_int = Property(lambda id=(T.Int, 42): id, public=True) id_dflt_char = Property( lambda id=(T.Character, CharacterLiteral('\x00')): id, public=True) id_dflt_root_node = Property(lambda id=(T.FooNode, No(T.FooNode)): id, public=True)
class SubpBodyDecls(DeclarativePart): """ Top-level list of declaration in a subprogam body. """ env_spec = EnvSpec( # The only case where we need a declarative part to have a name is when # it is top-level in subprogram body (A), so that separate subprogram # bodies (B) can use this environment as their initial env. Note that # this case is legal only when that (A) is the syntactic root. add_env(names=If( Self.parent.is_a(T.SubpBody) & Self.parent.parent.is_null, [Self.parent.cast(T.SubpBody).name.scope_name.to_symbol], No(T.Symbol.array), )))