[nem-en] Late Binding in Nemerle

Snaury snaury at gmail.com
Fri Jul 21 20:08:34 CEST 2006


Hi Kamil,

I've looked at your patches (I didn't know I could use env like that),
and actually can see that your patch does not solve the problem
completely. For Nemerle.IO.print you are only lucky because Nemerle.IO
is a type name and gets rejected in can_be_late (but then in my
implementation it was called again for Nemerle.IO and then Nemerle is
not a type name anymore and we had a problem). If print macro was in,
say, Nemerle.IOMacro, you won't even get a chance to test if it is
macro or not, because this line:

        | _ when latebound(expr, out expr', deep) => expr'

Will return before you get a chance to test for macro in PExpr.Call.
The patch for this follows (I'm also attaching it, inline here in case
it doesn't come thru):

Index: macros/Late.n
===================================================================
--- macros/Late.n	(revision 6459)
+++ macros/Late.n	(working copy)
@@ -149,6 +149,22 @@
         else
           call

+    /// returns true is expr is of some special kind
+    /// and shouldn't be transformed by late rules
+    public special(expr : PExpr) : bool
+        | PExpr.This => true
+        | PExpr.Base => true
+        | _ => match(Util.QidOfExpr(expr))
+          | Some((id, name)) =>
+            def ctx = name.GetEnv(env)
+            if(ctx.LookupType(id) is Some(_))
+              true
+            else if(ctx.LookupMacro(id) is Some(_))
+              true
+            else
+              false
+          | _ => false
+
     /// returns expression that does all late invokes in chain
     /// expr_name is used to hold expr with each invoke
     public static build(expr_name : Name, expr : PExpr, chain :
list[LateCall]) : PExpr
@@ -168,30 +184,27 @@

     /// scans single expression and returns (expr, list[LateCall])
     /// returns (expr, []) if nothing in expression can be late bound
-    public static scan(expr : PExpr) : PExpr * list[LateCall]
+    public scan(expr : PExpr) : PExpr * list[LateCall]
       def loop(expr, r = [])
-        def can_be_late(expr)
-          | PExpr.This => false
-          | PExpr.Base => false
-          | _ when Macros.IsTypeName(expr) => false
-          | _ => true
         match(expr)
           | null => (expr, r)
-          | <[ $rest . $(id : name) [.. $args] = $value ]> when
can_be_late(rest) \
-          | <[ $rest . $(id : name) = $value ]> when
can_be_late(rest) with (args = []) \
-          | <[ $rest . [.. $args] = $value ]> when can_be_late(rest)
with(id = Name("")) \
-          | <[ $rest [.. $args] = $value ]> when can_be_late(rest)
with(id = Name("")) =>
+          | <[ $rest (.. $_) ]> when special(rest) \
+          | <[ $rest [.. $_] ]> when special(rest) => (expr, r)
+          | <[ $rest . $(id : name) [.. $args] = $value ]> when
!special(rest) \
+          | <[ $rest . $(id : name) = $value ]> when !special(rest)
with (args = []) \
+          | <[ $rest . [.. $args] = $value ]> when !special(rest)
with(id = Name("")) \
+          | <[ $rest [.. $args] = $value ]> when !special(rest)
with(id = Name("")) =>
             when(id.Id == "" && args.Length == 0)
               Message.FatalError(expr.Location, "default indexer must
have parameters")
             loop(rest, LateCall.SetProperty(expr.Location,
CallInfo(id.Id, args, [value])) :: r)
-          | <[ $rest . $(id : name) [.. $args] ]> when can_be_late(rest) \
-          | <[ $rest . $(id : name) ]> when can_be_late(rest) with(args = []) \
-          | <[ $rest . [.. $args] ]> when can_be_late(rest) with(id =
Name("")) \
-          | <[ $rest [.. $args] ]> when can_be_late(rest) with(id =
Name("")) =>
+          | <[ $rest . $(id : name) [.. $args] ]> when !special(rest) \
+          | <[ $rest . $(id : name) ]> when !special(rest) with(args = []) \
+          | <[ $rest . [.. $args] ]> when !special(rest) with(id = Name("")) \
+          | <[ $rest [.. $args] ]> when !special(rest) with(id = Name("")) =>
             when(id.Id == "" && args.Length == 0)
               Message.FatalError(expr.Location, "default indexer must
have parameters")
             loop(rest, LateCall.GetProperty(expr.Location,
CallInfo(id.Id, args)) :: r)
-          | <[ $rest . $(id : name) (.. $args) ]> when can_be_late(rest) =>
+          | <[ $rest . $(id : name) (.. $args) ]> when !special(rest) =>
             loop(rest, LateCall.Method(expr.Location, CallInfo(id.Id,
args)) :: r)
           | _ => (expr, r)
       loop(expr)
@@ -266,14 +279,7 @@
           else
             PExpr.Member(loc, recurse(obj), mem)
         | PExpr.Call(func, parms) =>
-          def ismacro = match (Util.QidOfExpr (func))
-            | Some ((id, name)) =>
-              def ctx = name.GetEnv (env)
-              match (ctx.LookupMacro (id))
-                | Some (_) => true
-                | None => false
-            | None => false
-          if (ismacro)
+          if (special(func))
             PExpr.Call(loc, func, parms.Map(recurse))
           else
             PExpr.Call(loc, recurse(func), parms.Map(recurse))
@@ -300,7 +306,11 @@
         | PExpr.Tuple(args) => PExpr.Tuple(loc, args.Map(recurse))
         | PExpr.Array(rank, args) => PExpr.Array(loc, recurse(rank),
recurse(args))
         | PExpr.EmptyArray(sizes) => PExpr.EmptyArray(loc, sizes.Map(recurse))
-        | PExpr.Indexer(obj, args) => PExpr.Indexer(loc,
recurse(obj), args.Map(recurse))
+        | PExpr.Indexer(obj, args) =>
+          if(special(obj))
+            PExpr.Indexer(loc, obj, args.Map(recurse))
+          else
+            PExpr.Indexer(loc, recurse(obj), args.Map(recurse))
         | PExpr.ParmByRef \
         | PExpr.ParmOut \
         | PExpr.Error => expr

However, there is even more that would be good to check: whether qid
is some namespace, but it seems GlobalEnv doesn't allow that...

On 7/21/06, Kamil Skalski <kamil.skalski at gmail.com> wrote:
> This is now commited. Also, I just realized we could try to add the
> support for operators, though I'm not sure if this is possible:
> + / - / * / etc. should be changed to op_Addition / op_Minus / ...
> static methods from type of ONE of operands.
> Probably the most problematic is to chose whose operand's type should we use...
-------------- next part --------------
A non-text attachment was scrubbed...
Name: nemerle-fix-late-type-and-macro.patch
Type: application/octet-stream
Size: 4924 bytes
Desc: not available
Url : /mailman/pipermail/devel-en/attachments/20060721/af486060/nemerle-fix-late-type-and-macro.obj


More information about the devel-en mailing list