using Nemerle;
using Nemerle.Collections;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using Nemerle.Compiler.Typedtree;
using Nemerle.Text;
using Nemerle.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MacroLibrary
{
macro DoCalcDependencies(code : PExpr)
{
DoCalcDependenciesImpl.DoTransform(Macros.ImplicitCTX(), code)
}
module DoCalcDependenciesImpl
{
public DoTransform(typer : Typer, code : PExpr) : PExpr
{
Macros.DefineCTX(typer);
def analyse(_code, typed)
{
def parms = typer.CurrentMethodBuilder.Header.parms;
def isParametr(x : LocalValue) { parms.Exists(p => p.decl.Equals(x)) }
def wolk(info : ExprWalkInfo) : void // Walk through typed body representation (typed expression)
{
match (info.Node)
{ // typed representation of <[ $x.$y = $e2 ]>
| TExpr.Assign(TExpr.PropertyMember(TExpr.LocalRef(local1), prop) as e1, e2) when isParametr(local1) =>
//assert2(false); // use it if you need to debug this code
// collect dependences...
def dependOn = List();
def collectDependences(info : ExprWalkInfo) : void
{
match (info.Node)
{
// match member access on same local variable (i.e. on one of parameters)
| TExpr.MethodRef (TExpr.LocalRef(local2), member, _, _) as e when local2.Equals(local1)
| TExpr.FieldMember (TExpr.LocalRef(local2), member) as e when local2.Equals(local1)
| TExpr.PropertyMember(TExpr.LocalRef(local2), member) as e when local2.Equals(local1) =>
dependOn.Add((e, member));
| _ => ()
}
}
def wolker = ExprWalker();
wolker.Walk(e2, collectDependences);
// Print collected dependences as compiler hints
if (dependOn.IsEmpty())
Message.Hint(e1.Location, $"The $(local1.Name).$(prop.Name) has no dependences.");
else
{
Message.Hint(e1.Location, $"The $(local1.Name).$(prop.Name) dependent on:");
foreach ((expr, member) in dependOn)
Message.Hint(expr.Location, member.ToString());
}
| _ => ()
}
}
def wolker = ExprWalker();
wolker.Walk(typed, wolk); // Walk through typed body representation (typed expression)
<[ $(typed : typed) ]> // Returning of the typed expressin prevent us from retyping, but we can return "code".
}
def typed = typer.TypeExpr(code); // type the expression manually
// Now expression is typed, but it can has delayed typing actions (not inferred yet subexpressions).
// We should wait while compiler infer all types in subexpressions.
typer.TransformWhenAllTypesWouldBeInfered(analyse, typed, code); // wait for type enferrence is finished and call 'analyse'
}
}
}
Using macros...