예제 #1
0
 /** read all source files to their compilation units. Return true if no error. */
 public boolean readSourceFiles() {
   for (CompilationUnit compilationUnit : program.getCompilationUnitList()) {
     try {
       compilationUnit.readSourceFile();
     } catch (Exception e) {
       return false;
     }
   }
   return true;
 }
예제 #2
0
  private static void apply_ati_ActionsToGenericPrototype(Env env, CompilationUnit compUnit) {
    ICompiler_ati compiler_ati = new Compiler_ati(env);
    CompilerManager_ati compilerManager = new CompilerManager_ati(env);

    compUnit.ati_actions(compiler_ati, compilerManager);

    /*
     * all changes demanded by metaobject calls collected above are made in the call
     * to CompilerManager_ati#changeCheckProgram.
     */
    compilerManager.changeCheckProgram();
  }
예제 #3
0
  /**
   * compile the project passed as parameter to the constructor. The basic packages of Cyan, stored
   * in project <code>cyanLangPackageProject</code>, are added to the project. Currently there is
   * only one basic package of the language: "cyan.lang". This should be included in every
   * compilation.
   *
   * @return <code>false</code> in error
   */
  public boolean compile(HashSet<saci.CompilationInstruction> compInstSet) {

    Compiler compiler;

    try {

      // list of non-generic prototypes of the programc
      nonGenericCompilationUnitList = new ArrayList<CompilationUnit>();
      // list of generic prototypes of the program
      ArrayList<CompilationUnit> genericCompilationUnitList = new ArrayList<CompilationUnit>();

      /* separates the compilation units (source files) that have generic prototypes from
         those that don´t.
         A prototype whose file has a digit after '(' is a generic prototype. For example,
            Proto(1)(1).cyan has a generic prototype Proto<T><R>. And file
         MyData<main.Person><Int> is put in file MyData(main.Person)(Int).cyan.
      */

      for (CompilationUnit compilationUnit : program.getCompilationUnitList()) {

        /*
        // if the file name has a '(' character followed by a digit, then it is a
        // generic prototype. Note that "Stack(Int).cyan" contains prototype "Stack<Int>"
        // which is not considered generic
        	 *
        	 */
        String filename = compilationUnit.getFilename();
        boolean foundDigit = false;
        int ifn = 0;
        int sizeFilename = filename.length();
        while (ifn < sizeFilename) {
          if (filename.charAt(ifn) == '(' && Character.isDigit(filename.charAt(ifn + 1))) {
            foundDigit = true;
            break;
          }
          ++ifn;
        }
        if (foundDigit) {
          compilationUnit.setHasGenericPrototype(true);
          genericCompilationUnitList.add(compilationUnit);
        } else nonGenericCompilationUnitList.add(compilationUnit);
        /*
        if ( indexOfLeftPar > 0 && Character.isDigit(compilationUnit.getFilename().charAt(indexOfLeftPar + 1))  )
        	genericCompilationUnitList.add(compilationUnit);
        else
        	nonGenericCompilationUnitList.add(compilationUnit);
        */
      }

      /**
       * delete all files from "tmp" directories. If a generic prototype is in a directory "D", the
       * Compiler creates the generic instantiations in "D\tmp". For example, if "Stack<T>" is in
       * directory "util", the Compiler creates prototypes "Stack<Int>" and "Stack<Person>"
       * (assuming the program uses "Stack<Int>" and "Stack<Person>") in directory "util\tmp".
       */
      Set<String> pathCompilationUnitTable = new HashSet<String>();
      for (CompilationUnit c : genericCompilationUnitList) {
        pathCompilationUnitTable.add(c.getPackageCanonicalPath());

        c.getCyanPackage().setHasGenericPrototype(true);
      }
      for (String path : pathCompilationUnitTable) {
        File dir = new File(path + NameServer.temporaryDirName);
        if (dir.exists()) for (File file : dir.listFiles()) file.delete();
      }

      String dotExtension = "." + NameServer.cyanSourceFileExtension;

      boolean hasCompilationError = false;

      /**
       * first of all, parse all generic prototypes. This is not allowed in step 7 of the
       * compilation because all generic prototype instantiation should have been created before
       * that.
       */
      if (this.compilationStep.compareTo(CompilationStep.step_7) < 0) {
        for (CompilationUnit compilationUnit : genericCompilationUnitList) {
          compiler = new Compiler(compilationUnit, compInstSet, compilationStep, project, null);
          compiler.parse();
          /**
           * print the errors found in the generic prototypes and apply all actions to them. An
           * action is a small refactoring like insert a ";"
           */
          if (compilationUnit.hasCompilationError()) {
            // compilationUnit.printErrorList(printWriter);
            hasCompilationError = true;
          }
          if (compilationUnit.getActionList().size() > 0) compilationUnit.doActionList(printWriter);
        }
      }

      /* if ( hasCompilationError )
      	return false;
      */

      /*
       * in the first step of this while statement, all non-generic prototypes are compiled.
       *
       * In the second step of the while statement, the real prototypes created in the previous step
       * are compiled. They may instantiate new generic prototypes. For example, Stack<Int> may
       * declare a variable of type "Array<Int>". This new Cyan prototype should be created and
       * compiled. The process continues till no new prototypes should be created.
       */
      CompilationUnit compilationUnit;
      int numCompilationUnitsAlreadyCompiled = 0;
      int sizeNonGenericCompilationUnitList;
      while (numCompilationUnitsAlreadyCompiled < nonGenericCompilationUnitList.size()) {

        sizeNonGenericCompilationUnitList = nonGenericCompilationUnitList.size();
        boolean thereWasErrors = false;

        // parse of all source files that were not yet parsed. That may include some
        // generic prototypes that were instantiated in the previous round of the above
        // while statement.
        for (int i = numCompilationUnitsAlreadyCompiled;
            i < sizeNonGenericCompilationUnitList;
            i++) {
          compilationUnit = nonGenericCompilationUnitList.get(i);

          // System.out.println("cc: " + compilationUnit.getFilename());
          compiler = new Compiler(compilationUnit, compInstSet, compilationStep, project, null);
          compiler.parse();
          // if ( ! compilationUnit.hasCompilationError() ) {
          // }
          if (compilationUnit.hasCompilationError()) {
            thereWasErrors = true;
            // compilationUnit.printErrorList(printWriter);
          } else if (compInstSet.contains(CompilationInstruction.createPrototypesForInterfaces)
              && compilationUnit.getPrototypeIsNotGeneric()
              && compilationUnit.getPublicPrototype() instanceof InterfaceDec) {
            // if public program unit is an interface, create ProtoInterface
            CompilationUnit newCompilationUnit = compilationUnit.createProtoInterface();
            if (newCompilationUnit == null) {
              if (compilationUnit.hasCompilationError()) {
                thereWasErrors = true;
                compilationUnit.printErrorList(printWriter);
              }
            } else {
              CyanPackage thisCyanPackage = compilationUnit.getCyanPackage();

              thisCyanPackage.addCompilationUnit(newCompilationUnit);
              newCompilationUnit.setCyanPackage(thisCyanPackage);
              nonGenericCompilationUnitList.add(newCompilationUnit);

              String name = newCompilationUnit.getFilename();
              int indexDotCyan = name.indexOf(dotExtension);
              if (indexDotCyan > 0) name = name.substring(0, indexDotCyan);

              program.addCompilationUnit(newCompilationUnit);

              if (nameSet.contains(newCompilationUnit.getFilename()))
                System.out.println("error: " + newCompilationUnit.getFilename());
              else nameSet.add(newCompilationUnit.getFilename());
            }
          }
          // if there was not any errors and there is a list of actions ...
          /*if ( compilationUnit.getActionList().size() > 0 )
          	compilationUnit.doActionList(printWriter);
          compilationUnit.clearErrorsActions(); */
        }

        if (thereWasErrors) {
          return false;
        }
        numCompilationUnitsAlreadyCompiled = sizeNonGenericCompilationUnitList;
      }

    } catch (Exception e) {
      System.out.println(
          "Internal error at CompilerManager::compile(). e = " + e.getClass().getName());
      e.printStackTrace();
      return false;
    }

    project.printErrorList(printWriter);
    return true;
  }
예제 #4
0
  /**
   * Create an instantiation of a generic prototype given by parameter gt
   *
   * @param gt
   * @param env
   * @return
   */
  private CompilationUnit createGenericPrototypeInstantiation(
      ExprGenericPrototypeInstantiation gt, Env env) {

    CompilationUnit genericProto = null;

    /* if ( gt.getName().equals("generic02.gb.G1<X>") ) {
    	System.out.println("generic02.gb.G1<X>");
    	gt.ifPrototypeReturnsNameWithPackageAndType(env);
    } */

    String genSourceFileName = gt.getGenericSourceFileName();

    String genSourceFileNameVaryingNumberOfParameters =
        gt.getGenericSourceFileNameWithVaryingNumberOfParameters();
    // if ( gt.getRealTypeListList().size() > 1 )
    // System.out.println("3");

    boolean isInterface = false;
    if (NameServer.isPrototypeFromInterface(genSourceFileName)) {
      // int sizePrefix = NameServer.prefixProtoInterface.length();
      isInterface = true;
      /*
      genSourceFileName = genSourceFileName.substring(sizePrefix);
      genSourceFileNameVaryingNumberOfParameters = genSourceFileNameVaryingNumberOfParameters.substring(sizePrefix);
      */
      genSourceFileName = NameServer.prototypeFileNameFromInterfaceFileName(genSourceFileName);
      genSourceFileNameVaryingNumberOfParameters =
          NameServer.prototypeFileNameFromInterfaceFileName(
              genSourceFileNameVaryingNumberOfParameters);
    }
    // something like util.Stack if gt is "util.Stack<Int>" or
    // Stack if gt is Stack<Int>
    ExprIdentStar typeIdent = gt.getTypeIdent();
    if (typeIdent.getIdentSymbolArray().size() == 1) {
      // no package preceding the generic prototype name as in "Stack<Int>"
      ProgramUnit pu =
          env.searchProgramUnitBySourceFileName(genSourceFileName, gt.getFirstSymbol(), false);
      if (pu != null) {
        genericProto = pu.getCompilationUnit();
        ProgramUnit pu2 =
            env.searchProgramUnitBySourceFileName(
                genSourceFileNameVaryingNumberOfParameters, gt.getFirstSymbol(), false);
        if (pu2 != null)
          /* found both generic prototype and generic prototype with varying number of parameters
           * Example: found both Tuple<T> and Tuple<T+>
           */
          env.error(
              gt.getFirstSymbol(),
              "Ambiguity in creating a real prototype from a generic prototype. There is both "
                  + pu.getCompilationUnit().getPackageName()
                  + "."
                  + genSourceFileName
                  + " and "
                  + pu2.getCompilationUnit().getPackageName()
                  + "."
                  + genSourceFileNameVaryingNumberOfParameters,
              true);
      }
      if (genericProto == null) {
        pu =
            env.searchProgramUnitBySourceFileName(
                genSourceFileNameVaryingNumberOfParameters, gt.getFirstSymbol(), false);
        if (pu != null) genericProto = pu.getCompilationUnit();
      }
    } else {
      // package preceding the generic prototype name as in "util.Stack<Int>"
      int i = 0;
      ArrayList<Symbol> symbolList = typeIdent.getIdentSymbolArray();
      int sizeLessOne = symbolList.size() - 1;
      String packageName = "";
      while (i < sizeLessOne) {
        packageName = packageName + symbolList.get(i).getSymbolString();
        ++i;
        if (i < sizeLessOne) packageName += ".";
      }
      CyanPackage cyanPackage = env.getProject().searchPackage(packageName);
      if (cyanPackage == null) {
        env.error(typeIdent.getFirstSymbol(), "Package '" + packageName + "' was not found", true);
        return null;
      }
      // first searches for something like "Stack(1)" in package 'util'
      for (CompilationUnit cunit : cyanPackage.getCompilationUnitList()) {
        if (genSourceFileName.equals(cunit.getFileNameWithoutExtension())) {
          genericProto = cunit;
          break;
        }
      }
      CompilationUnit genericProto2 = null;
      // searches for a generic prototype with varying number of parameters
      // something like "Stack(1+)"
      for (CompilationUnit cunit : cyanPackage.getCompilationUnitList()) {
        if (genSourceFileNameVaryingNumberOfParameters.equals(
            cunit.getFileNameWithoutExtension())) {
          genericProto2 = cunit;
          break;
        }
      }

      if (genericProto != null && genericProto2 != null) {
        env.error(
            gt.getFirstSymbol(),
            "Ambiguity in creating a real prototype from a generic prototype. There is both "
                + genericProto.getPackageName()
                + "."
                + genSourceFileName
                + " and "
                + genericProto2.getPackageName()
                + "."
                + genSourceFileNameVaryingNumberOfParameters,
            true);
      }
      if (genericProto == null) genericProto = genericProto2;
    }

    // genericProto = nameGenProtoUnitTable.get(genSourceFileName);

    if (genericProto == null) {
      env.error(
          true,
          gt.getFirstSymbol(),
          "Prototype '" + gt.getName() + "' was not found",
          gt.getName(),
          ErrorKind.prototype_was_not_found_inside_method);
      /*gt.getProgramUnit().getCompilationUnit().error(null,
      "Internal error at CompilerManager::createInterfaceObjectFunctionAndArray: cannot create " + gt.getName()); */
      return null;
    } else {
      /**
       * if there was no compilation error in "Stack(1).cyan", then create an instance of the
       * generic prototype
       */
      if (isInterface) {
        gt.removeProtoPrefix();
      }

      CompilationUnit newCompilationUnit = genericProto.createInstanceGenericPrototype(gt, env);
      CompilationUnit interCompilationUnit = null;
      /**
       * if the package for this generic prototype instantiation was not created before, create it
       * now.
       */
      CyanPackage cyanPackage = genericProto.getCyanPackage();

      cyanPackage.addCompilationUnit(newCompilationUnit);
      newCompilationUnit.setCyanPackage(cyanPackage);
      nonGenericCompilationUnitList.add(newCompilationUnit);

      if (nameSet.contains(newCompilationUnit.getFullFileNamePath())) {
        env.error(gt.getFirstSymbol(), "Internal error in CompilerManager");
        gt.ifPrototypeReturnsNameWithPackageAndType(env);
      } else nameSet.add(newCompilationUnit.getFullFileNamePath());

      program.addCompilationUnit(newCompilationUnit);

      newCompilationUnit.readSourceFile();
      HashSet<saci.CompilationInstruction> compInstSet = new HashSet<>();
      compInstSet.add(CompilationInstruction.dpa_actions);
      compInstSet.add(CompilationInstruction.pp_addCode);
      if (compilationStep.compareTo(CompilationStep.step_5) >= 0)
        compInstSet.add(CompilationInstruction.new_addCode);
      Compiler compiler =
          new Compiler(newCompilationUnit, compInstSet, compilationStep, project, null);
      compiler.parse();

      if (newCompilationUnit.hasCompilationError()) {
        // newCompilationUnit.printErrorList(printWriter);
        env.setThereWasError(true);
        throw new CompileErrorException();
      } else if (compInstSet.contains(CompilationInstruction.createPrototypesForInterfaces)
          && newCompilationUnit.getPrototypeIsNotGeneric()
          && newCompilationUnit.getPublicPrototype() instanceof InterfaceDec) {
        // if public program unit is an interface, create ProtoInterface

        interCompilationUnit = newCompilationUnit.createProtoInterface();
        if (interCompilationUnit != null) {

          interCompilationUnit.setCyanPackage(cyanPackage);
          cyanPackage.addCompilationUnit(interCompilationUnit);
          newCompilationUnit.setCyanPackage(cyanPackage);
          nonGenericCompilationUnitList.add(interCompilationUnit);

          String nameInter = interCompilationUnit.getFilename();
          if (nameInter.endsWith(NameServer.dotCyanSourceFileExtension))
            nameInter =
                nameInter.substring(
                    0, nameInter.length() - NameServer.sizeCyanSourceFileExtensionPlusOne);

          // nameRealGenProtoUnitTable.put(nameInter, interCompilationUnit);
          program.addCompilationUnit(interCompilationUnit);

          interCompilationUnit.readSourceFile();
          compiler =
              new Compiler(interCompilationUnit, compInstSet, compilationStep, project, null);
          compiler.parse();
          if (interCompilationUnit.getActionList().size() > 0)
            interCompilationUnit.doActionList(printWriter);
          interCompilationUnit.clearErrorsActions();
        }
      }
      // newCompilationUnit.clearErrorsActions();
      if (isInterface) return interCompilationUnit;
      else return newCompilationUnit;
    }
  }
예제 #5
0
  /**
   * Create a generic prototype from parameter gpi. The new prototype is compiled. If it is an
   * interface, the prototype Proto_IntefaceName is created too. Methods calcInterfaceTypes and
   * calcInternalTypes are called for both the prototype and its Proto_InterfaceName, if any.
   *
   * @param gpi
   * @param env
   * @return
   */
  public static ProgramUnit createGenericPrototype(ExprGenericPrototypeInstantiation gpi, Env env) {

    saci.Tuple<String, Type> t = gpi.ifPrototypeReturnsNameWithPackageAndType(env);

    // t.f1 is the name of the prototype
    if (t != null && t.f2 != null) {
      /*
       * prototype has already been created before
       */
      if (t.f2 instanceof ProgramUnit) {
        return (ProgramUnit) t.f2;
      } else {
        env.error(
            gpi.getFirstSymbol(),
            "Internal error: a type that is not a program unit is used to instantiate a generic prototype");
        return null;
      }

    } else {
      /*
       * prototype has not been created. Create it.
       */
      // if ( env.getCurrentMethod() != null && env.getCurrentMethod().getName().contains("run2") )
      //	gpi.ifPrototypeReturnsItsNameWithPackage(env);

      /*
       * first, create all prototypes that are real parameters to this generic prototype instantiation
       */
      for (ArrayList<Expr> realTypeList : gpi.getRealTypeListList()) {
        for (Expr realType : realTypeList) {
          if (realType instanceof ExprGenericPrototypeInstantiation) {
            ExprGenericPrototypeInstantiation genRealType =
                (ExprGenericPrototypeInstantiation) realType;
            genRealType.setType(createGenericPrototype(genRealType, env));
            // 		javaName = type.getJavaName();
            genRealType.setJavaName(genRealType.getType().getJavaName());
          }
        }
      }

      CompilationUnit compUnit =
          env.getProject().getCompilerManager().createGenericPrototypeInstantiation(gpi, env);

      Env newEnv = new Env(env.getProject());
      /*
      * If a generic prototype is created when method calcInterfaceTypes of Program is being executed
      * (env.getProject().getProgram().getInCalcInterfaceTypes() returns true), it is not necessary
      * to call its method calcInterfaceTypes. It will be called in the loop of
      * method Program::calcInterfaceTypes.

      * If a generic prototype is created when method calcInternalTypes of Program is being executed,
      * method calcInterfaceTypes of this generic prototype should be called because the interface
      * of this prototype is necessary in methods calcInternalTypes. Method calcInternalTypes
      * of this newly created generic prototype will be called in the loop of
      * method Program::calcInternalTypes.
      *
      * calcInternalTypes cannot be called when a generic prototype is created when
      * the compiler is calling calcInterfaceTypes. If this is allowed, some calcInternalType
      * method could try to use the interface of some prototype P whose method calcInterfaceTypes
      * have not been called.
      */
      if (!env.getProject().getProgram().getInCalcInterfaceTypes()) {
        compUnit.calcInterfaceTypes(newEnv);
        // compUnit.calcInternalTypes(newEnv);
      }
      CompilationUnit interfaceCompilationUnit = compUnit.getInterfaceCompilationUnit();
      if (interfaceCompilationUnit != null) {
        newEnv = new Env(env.getProject());
        if (!env.getProject().getProgram().getInCalcInterfaceTypes()) {
          interfaceCompilationUnit.calcInterfaceTypes(newEnv);
        }
      }
      /*
       * if the generic prototype was created from phase (4), included, onwards, then execute
       * the ati actions. A generic prototype instantiation can only change itself and
       * no other prototype can change it.
       */
      if (env.getProject().getCompilerManager().getCompilationStep().ordinal()
          > CompilationStep.step_3.ordinal()) {
        apply_ati_ActionsToGenericPrototype(newEnv, compUnit);
        if (interfaceCompilationUnit != null) {
          apply_ati_ActionsToGenericPrototype(env, interfaceCompilationUnit);
        }
      }

      return compUnit.getPublicPrototype();
    }
  }