IMPLEMENTATION MODULE YaflSystem;

IMPORT ModuleTable;
IMPORT Space;
IMPORT SYSTEM;
FROM YaflClDefinition IMPORT ClassDefinition;
FROM YaflMetDefinition IMPORT MethodDefinition;
FROM YaflMethods      IMPORT MethodDeclaration;
FROM YaflModules      IMPORT DefinitionModule;
FROM YaflNTList       IMPORT DeclList;
FROM YaflPredefined   IMPORT PredefItems;

------------------------------------------------------
  CLASS SystemMethod;
    METHOD Strap(Meth: MethodDeclaration);
      BEGIN
      Meth.Strap(THIS);
      END Strap;
  END SystemMethod;
------------------------------------------------------
  CLASS PatternSystemMethod;  
    INHERITS SystemMethod;
    
    VAR
      Pattern: ARRAY OF ARRAY OF CHAR;
      TheMethod: MethodDeclaration;
      
    CONST
      EscapeChar = '#';
      
    METHOD CheckArity (Arity: INTEGER);
      VAR
        a: ARRAY OF CHAR;
        Next: CHAR;
      BEGIN
      FOR j := 0 TO Pattern.SIZE - 1 DO
        a := Pattern[j];
        FOR i := 0 TO a.SIZE - 1 DO
          IF a[i] = EscapeChar THEN
            IF i+1 < a.SIZE THEN
              Next := a[i+1];
              IF (Next < '1') OR (Next > SYSTEM.CHR(SYSTEM.ORD('0') + Arity)) 
                                        THEN
                TheMethod.Error ("Illegal argument reference in " +
                                 "strapping pattern: " + a);
                END;
             ELSE
              TheMethod.Error ("Illegal strapping pattern: " + a);
              END;
            END;
          END;
        END;
      END CheckArity;
      
    REDEFINE METHOD CREATE (Meth: MethodDeclaration;
                            Pattern: ARRAY OF ARRAY OF CHAR);
      BEGIN      
      ASSERT Pattern <> VOID; 
      ASSERT Meth <> VOID;
      THIS.Pattern := Pattern;
      Meth.Strap (THIS);
      TheMethod := Meth;
      CheckArity (Meth.Arity);
      END CREATE;
      
    REDEFINE METHOD GenerateCode(Ctx: CGcContext;
                                 Output: YaflGC;
                                 Args: NTList(Actual);
                                 Functional: BOOLEAN);
      VAR
         Pos, ArgNr: INTEGER;
        a: ARRAY OF CHAR;
      BEGIN            
      Output.NoCut;
      FOR i := 0 TO Pattern.SIZE - 1 DO
        a := Pattern[i];
        IF a <> VOID THEN
          Pos := 0;
          WHILE Pos < a.SIZE DO
            IF (a[Pos] = EscapeChar) THEN
              ASSERT Pos + 1 < a.SIZE;
              Pos := Pos + 1;
              ArgNr := SYSTEM.ORD(a[Pos]) - SYSTEM.ORD('0'); 
              ASSERT ArgNr > 0;
              ASSERT ArgNr <= TheMethod.Arity;
	      IF Functional THEN
                Args.Get(ArgNr-1).Gc.GenerateCode; ---OOO
	       ELSE
		Output.UniqueItem (Args.Get(ArgNr - 1).Expr.Gc.Number);
	        END;
             ELSE
              Output.WriteChar (a[Pos]);
              END;
            Pos := Pos + 1;
            END;
          END;
        END;          
      Output.Cut;
      Output.WriteLn;
      END GenerateCode;
    
  END PatternSystemMethod;

END YaflSystem;
