소스 검색

feat: class results and chained post-call method calls

(b) A function/method may now return a CLASS (dropped the last result
   230); like record/array/set it uses the sret ABI (copy the object).

(a) `F().M(args)` chains a method call on a call result:
   - ResultComp's `.` branch now resolves methods as well as fields,
     exposing the method name/class (mname/methCls/isM);
   - Fact loops `{ ResultComp [ ArgList ] }`, so a call may follow a
     suffix; astNArgs is reset before the nested call so the inner
     call's arguments do not leak into the outer one;
   - Lower.IsMethodCall handles a call base (CallResultType resolves the
     inner call's result), so LowerMethodCall lowers it (LowerDesign
     already handled the call-base designator).

Regression: t_chain.mod (`Mk(7).Get()` and `Mk(8).x`).  Suite 187/187;
FIXPOINT OK (3,405,882 bytes).
Eric Streit 3 일 전
부모
커밋
38aa98e7af
5개의 변경된 파일과 2130개의 추가작업 그리고 2049개의 파일을 삭제
  1. 1 0
      compiler/run_tests.sh
  2. 26 3
      compiler/src/Lower.mod
  3. 30 14
      compiler/src/M2.atg
  4. 2048 2032
      compiler/src/M2.lst
  5. 25 0
      compiler/tests/t_chain.mod

+ 1 - 0
compiler/run_tests.sh

@@ -98,6 +98,7 @@ expect_run t_arrrecbig.mod 42
 expect_run t_stmtsfx.mod 42
 expect_run t_retrec.mod 42
 expect_run t_retmeth.mod 42
+expect_run t_chain.mod 42
 expect_run t_under.mod 42
 expect_run t_with.mod 114
 expect_run t_set.mod 131

+ 26 - 3
compiler/src/Lower.mod

@@ -575,6 +575,24 @@ PROCEDURE CalleeName (call: AST.Node; VAR nm: SymTab.Name);
     IF (d # AST.NoNode) AND (AST.Kind(d) = AST.NkIdent) THEN Name(d, nm) END
   END CalleeName;
 
+PROCEDURE CallResultType (call: AST.Node; VAR t: SymTab.TypeIndex): BOOLEAN;
+(* The result type of a call used as a designator base (F().M()). *)
+  VAR nm: SymTab.Name; uid, depth, np: CARDINAL; res: SymTab.TypeIndex;
+      ext: BOOLEAN; pi: INTEGER;
+  BEGIN
+    t := SymTab.InvalidType;
+    CalleeName(call, nm);
+    pi := FindProc(nm);
+    IF pi >= 0 THEN
+      IF ProcInfoIdx(pi, uid, res, depth, ext, np) THEN t := res; RETURN TRUE END;
+      RETURN FALSE
+    END;
+    IF SymTab.Lookup(nm) AND (SymTab.SymKind(nm) = SymTab.KindProc) THEN
+      t := SymTab.ProcRes(nm); RETURN TRUE
+    END;
+    RETURN FALSE
+  END CallResultType;
+
 PROCEDURE IsMethodCall (n: AST.Node): BOOLEAN;
 (* n is a call whose callee resolves to a class method: `obj.Method`,
    `p^.Method`, or a bare sibling name inside an implementation. *)
@@ -590,8 +608,13 @@ PROCEDURE IsMethodCall (n: AST.Node): BOOLEAN;
       RETURN (curImplCls # SymTab.InvalidType)
              AND SymTab.MethodExists(curImplCls, nm)
     END;
-    Name(AST.Child(d, 0), nm);
-    IF NOT Resolve(nm, k, t) THEN RETURN FALSE END;
+    IF AST.Kind(AST.Child(d, 0)) = AST.NkCall THEN
+      (* F().M(): the base is a call; take its result type *)
+      IF NOT CallResultType(AST.Child(d, 0), t) THEN RETURN FALSE END
+    ELSE
+      Name(AST.Child(d, 0), nm);
+      IF NOT Resolve(nm, k, t) THEN RETURN FALSE END
+    END;
     i := 1;
     WHILE i < AST.NChild(d) DO
       sel := AST.Child(d, i);
@@ -824,7 +847,7 @@ PROCEDURE CompositeRes (t: SymTab.TypeIndex): BOOLEAN;
     IF t = SymTab.InvalidType THEN RETURN FALSE END;
     cls := SymTab.ClassOf(t);
     RETURN (cls = SymTab.ClRecord) OR (cls = SymTab.ClArray)
-        OR (cls = SymTab.ClSet)
+        OR (cls = SymTab.ClSet) OR (cls = SymTab.ClClass)
   END CompositeRes;
 
 PROCEDURE LowerCall (n: AST.Node; VAR t: SymTab.TypeIndex;

+ 30 - 14
compiler/src/M2.atg

@@ -1193,12 +1193,7 @@ PRODUCTIONS
       [ FormalParams ]
       [ ":" TypeIdent<t>                (. IF NOT SymTab.SetProcRes(t) THEN
                                              SemError(235) END;
-                                           Lower.SetProcRes(t);
-                                           IF (t #
-                                              SymTab.InvalidType)
- AND (SymTab.ClassOf(t)
-                                                 = SymTab.ClClass) THEN
-                                             SemError(230) END; .) ] .
+                                           Lower.SetProcRes(t); .) ] .
   FormalParams
     = "(" [ ParamSection { ";" ParamSection } ] ")" .
   ParamSection                          (. VAR t: SymTab.TypeIndex;
@@ -1458,7 +1453,7 @@ PRODUCTIONS
                                              q2, mg0: QbeGen.QVal;
                                              isR, conv, wconv: BOOLEAN;
                                              called, sfx: BOOLEAN;
-                                             astLhs, astRes: AST.Node; .)
+                                             astLhs, astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN; .)
     = Design<dt, dk, qd, qn, sfx>
       (. astLhs := astCur; astNArgs := 0; .)
       ( ":="
@@ -1497,7 +1492,7 @@ PRODUCTIONS
       | ArgList<qn, dt, qd, TRUE, TRUE, methCls, ct2, q2, called>
                                         (. astRes := AstCallNode(astLhs);
                                            sfx := FALSE; .)
-        ( { ResultComp<ct2, q2, sfx, astRes> }
+        ( { ResultComp<ct2, q2, sfx, astRes, mname, methCls, isM> }
           ":=" Expr<et, qe>             (. astStmt := AST.MakeBin(
                                              AST.NkAssign, 0, astRes, astCur);
                                            IF NOT sfx THEN
@@ -2194,7 +2189,9 @@ PRODUCTIONS
      (a value, or a descriptor address for aggregates); each component
      descends one level exactly like the Design components. *)
   ResultComp<VAR t: SymTab.TypeIndex; VAR q: QbeGen.QVal;
-             VAR sfx: BOOLEAN; VAR node: AST.Node>          (. VAR it, eT, bt: SymTab.TypeIndex;
+             VAR sfx: BOOLEAN; VAR node: AST.Node;
+             VAR mname: SymTab.Name; VAR methCls: SymTab.TypeIndex;
+             VAR isM: BOOLEAN>          (. VAR it, eT, bt: SymTab.TypeIndex;
                                              iq, ql, qlo, qhi, qe, qb:
                                                QbeGen.QVal;
                                              lo, hi, fo: INTEGER;
@@ -2202,7 +2199,8 @@ PRODUCTIONS
                                              fname: SymTab.Name;
                                              astWrap, astSel: AST.Node; .)
     = "[" Expr<it, iq>
-                                        (. IF AST.Kind(node) # AST.NkDesignator THEN
+                                        (. isM := FALSE;
+                                           IF AST.Kind(node) # AST.NkDesignator THEN
                                              astWrap := AST.MakeNode(
                                                AST.NkDesignator);
                                              AST.SetChild(astWrap, 0, node);
@@ -2226,7 +2224,8 @@ PRODUCTIONS
                                             END; .)
       "]"
     | "." GetIdent<fname>
-                                        (. IF AST.Kind(node) # AST.NkDesignator THEN
+                                        (. isM := FALSE;
+                                           IF AST.Kind(node) # AST.NkDesignator THEN
                                              astWrap := AST.MakeNode(
                                                AST.NkDesignator);
                                              AST.SetChild(astWrap, 0, node);
@@ -2242,6 +2241,15 @@ PRODUCTIONS
   AND (SymTab.ClassOf(t) # SymTab.ClClass) THEN
                                              SemError(215);
                                              t := SymTab.InvalidType
+                                            ELSIF (SymTab.ClassOf(t) =
+                                                   SymTab.ClClass)
+  AND SymTab.MethodExists(t, fname) THEN
+                                              (* a method on the call result:
+                                                 a following ArgList makes
+                                                 the call *)
+                                              mname := fname;
+                                              methCls := t; isM := TRUE;
+                                              t := SymTab.InvalidType
                                            ELSIF NOT SymTab.FieldExists(t,
                                                     fname) THEN
                                              SemError(216);
@@ -2250,7 +2258,8 @@ PRODUCTIONS
                                               t := SymTab.FieldType(t, fname);
                                               sfx := TRUE
                                             END; .)
-    | "^"                               (. IF AST.Kind(node) # AST.NkDesignator THEN
+    | "^"                               (. isM := FALSE;
+                                           IF AST.Kind(node) # AST.NkDesignator THEN
                                              astWrap := AST.MakeNode(
                                                AST.NkDesignator);
                                              AST.SetChild(astWrap, 0, node);
@@ -2542,7 +2551,7 @@ PRODUCTIONS
                                               j: CARDINAL;
                                               astArg2: AST.Node;
                                               astBrace: AST.Node;
-                                              astRes: AST.Node; .)
+                                              astRes: AST.Node; mname: SymTab.Name; isM: BOOLEAN; .)
     = (. astIsLit := FALSE; .)
     ( integer                           (. LexString(s);
                                            QbeGen.NormInt(s, q); IF twoPhase THEN astIsLit := TRUE; astCur := AST.MakeLeaf(AST.NkIntLit, s) END;
@@ -2611,7 +2620,14 @@ PRODUCTIONS
                                            t := ct2;
                                            QbeGen.CopyOp(q2, q);
                                            sfx := FALSE; .)
-        { ResultComp<t, q, sfx, astRes> }
+        { ResultComp<t, q, sfx, astRes, mname, methCls, isM>
+          [ (. astNArgs := 0; .)
+            ArgList<mname, t, q, TRUE, FALSE, methCls, ct2, q2, called>
+                                        (. astNode := AstCallNode(astRes);
+                                           astRes := astNode;
+                                           t := ct2;
+                                           QbeGen.CopyOp(q2, q);
+                                           sfx := FALSE; .) ] }
                                         (. IF sfx THEN
                                              IF t = SymTab.InvalidType THEN
                                                QbeGen.CopyOp("0", q)

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 2048 - 2032
compiler/src/M2.lst


+ 25 - 0
compiler/tests/t_chain.mod

@@ -0,0 +1,25 @@
+MODULE TChain;
+(* Chained post-call method call on a class result (`Mk(7).Get()`) and a
+   field of a class result (`Mk(8).x`).  Exit 42. *)
+VAR ExitCode, got : INTEGER;
+
+TYPE
+  CLASS C;
+    x : INTEGER;
+    PROCEDURE Get () : INTEGER;
+  END C;
+
+CLASS IMPLEMENTATION C;
+  PROCEDURE Get () : INTEGER; BEGIN RETURN x END Get;
+END C;
+
+PROCEDURE Mk (v : INTEGER) : C;
+VAR q : C;
+BEGIN q.x := v; RETURN q END Mk;
+
+BEGIN
+  got := 0;
+  IF Mk(7).Get() = 7 THEN INC(got) END;
+  IF Mk(8).x = 8 THEN INC(got) END;
+  IF got = 2 THEN ExitCode := 42 ELSE ExitCode := got END
+END TChain.

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.