001/*
002 * Copyright (c) 2012-2021 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others
003 *
004 * This program and the accompanying materials are made available under the
005 * terms of the Eclipse Public License 2.0 which is available at
006 * http://www.eclipse.org/legal/epl-2.0.
007 *
008 * SPDX-License-Identifier: EPL-2.0
009 */
010
011package org.eclipse.golo.compiler;
012
013import java.io.Reader;
014import java.io.File;
015import java.io.IOException;
016import java.util.List;
017
018import gololang.ir.GoloModule;
019
020/**
021 * Provides a facility to dynamically load Golo source code and access the generated code from a dedicated class loader.
022 * <p>
023 * Golo source files can be compiled and the resulting JVM bytecode be injected into the class loader. It is important
024 * to note that this class loader definition is not thread safe.
025 * <p>
026 * This class loader does not support reloading. Attempts to load source files that may produce the same bytecode
027 * definitions will resulting in exceptions.
028 */
029public final class GoloClassLoader extends ClassLoader {
030
031  private final GoloCompiler compiler;
032
033  /**
034   * Creates a class loader from a parent.
035   *
036   * @param parent the parent classloader.
037   */
038  public GoloClassLoader(ClassLoader parent) {
039    super(parent);
040    compiler = new GoloCompiler(this);
041  }
042
043  /**
044   * Creates a class loader from the default parent.
045   */
046  public GoloClassLoader() {
047    super();
048    compiler = new GoloCompiler(this);
049  }
050
051  public GoloCompiler getCompiler() {
052    return this.compiler;
053  }
054
055  /**
056   * Compiles and loads the resulting JVM bytecode for a Golo source file.
057   *
058   * @param goloSourceFilename    the source file name.
059   * @param sourceCode  the source reader.
060   * @return the class matching the Golo module defined in the source.
061   * @throws GoloCompilationException if either of the compilation phase failed.
062   */
063  public synchronized Class<?> load(String goloSourceFilename, Reader sourceCode) throws GoloCompilationException {
064    return load(compiler.compile(goloSourceFilename, sourceCode));
065  }
066
067  public synchronized Class<?> load(File goloSourceFile) throws GoloCompilationException, IOException {
068    return load(compiler.compile(goloSourceFile));
069  }
070
071  /**
072   * Compiles and loads the resulting JVM bytecode for a Golo module IR.
073   *
074   * @param module  the Golo module IR to load.
075   * @return the class matching the Golo module defined in the IR.
076   * @throws GoloCompilationException if either of the compilation phase failed.
077   */
078  public synchronized Class<?> load(GoloModule module) {
079    compiler.expand(module);
080    compiler.refine(module);
081    return load(compiler.generate(module));
082  }
083
084  public synchronized Class<?> load(List<CodeGenerationResult> results) {
085    Class<?> lastClassIsModule = null;
086    for (CodeGenerationResult result : results) {
087      lastClassIsModule = load(result);
088    }
089    return lastClassIsModule;
090  }
091
092  public synchronized Class<?> load(CodeGenerationResult result) {
093    return defineClass(result.getBinaryName(), result.getBytecode(), 0, result.size());
094  }
095}