Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port TypeScript code generator to Kotlin. #431

Merged
merged 18 commits into from
Jul 26, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
512d568
Port preamble and parameter generation parts of TypeScript code gener…
hokeun Jul 25, 2021
6833440
Port reactor skeleton generation part of TypeScript code generator to…
hokeun Jul 25, 2021
f22b4e0
Port reaction generation part of TypeScript code generator to Kotlin.
hokeun Jul 25, 2021
e2cde0d
Port runtime part of TypeScript code generation to Kotlin.
hokeun Jul 25, 2021
661032b
Fix a few bugs in TypeScript reactor generation.
hokeun Jul 25, 2021
032400a
Kotlin code clean up.
hokeun Jul 25, 2021
acf6bd9
Add build and compile comments for Kotlin TypeScript generator.
hokeun Jul 25, 2021
89955f6
Switch TypeScript code generator from xtext to Kotlin in LFGenerator.…
hokeun Jul 25, 2021
7e35870
Fix compile error:
hokeun Jul 25, 2021
d8e5b5d
Fix error in code generation for reactor's typeParams for example, in…
hokeun Jul 26, 2021
04f8c9a
Fix errors in list and reference type code generation.
hokeun Jul 26, 2021
6afcb59
Fix errors in ProtoNoPacking.lf test, including proto file generation…
hokeun Jul 26, 2021
9f3114a
Address reviewers' comments:
hokeun Jul 26, 2021
7ea1942
Fix error in createFileConfig for targets other than CPP and TS.
hokeun Jul 26, 2021
bd6d6db
Let error messages read the enum directly. (toString() will be called…
hokeun Jul 26, 2021
2c50c49
Retrieve package name and class name prefix for the code generator in…
hokeun Jul 26, 2021
69778b4
Retrieve package name and class name prefix for the file config in Ko…
hokeun Jul 26, 2021
c77beff
Change class name prefixes for TypeScript target from Ts to TS.
hokeun Jul 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 85 additions & 3 deletions org.lflang/src/org/lflang/generator/LFGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ private FileConfig createFileConfig(final Target target, Resource resource,
return createCppFileConfig(resource, fsa, context);
}
case TS: {
return new TypeScriptFileConfig(resource, fsa, context);
// return new TypeScriptFileConfig(resource, fsa, context);
return createTsFileConfig(resource, fsa, context);
}
default: {
return new FileConfig(resource, fsa, context);
Expand Down Expand Up @@ -100,6 +101,43 @@ private FileConfig createCppFileConfig(Resource resource,
}
}

/**
* Create a TypeScript specific FileConfig object
*
* Since the CppFileConfig class is implemented in Kotlin, the class is is
* not visible from all contexts. If the RCA is run from within Eclipse via
* "Run as Eclipse Application", the Kotlin classes are unfortunately not
* available at runtime due to bugs in the Eclipse Kotlin plugin. (See
* https://stackoverflow.com/questions/68095816/is-ist-possible-to-build-mixed-kotlin-and-java-applications-with-a-recent-eclips)
*
* If the CppFileConfig class is found, this method returns an instance.
* Otherwise, it returns an Instance of FileConfig.
*
* @return A CppFileConfig object if the class can be found
* @throws IOException
*/
private FileConfig createTsFileConfig(Resource resource,
IFileSystemAccess2 fsa,
IGeneratorContext context)
throws IOException {
// Since our Eclipse Plugin uses code injection via guice, we need to
// play a few tricks here so that CppFileConfig does not appear as an
// import. Instead we look the class up at runtime and instantiate it if
// found.
try {
return (FileConfig) Class
.forName("org.lflang.generator.ts.TsFileConfig")
.getDeclaredConstructor(Resource.class,
IFileSystemAccess2.class, IGeneratorContext.class)
.newInstance(resource, fsa, context);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException
| ClassNotFoundException e) {
return new FileConfig(resource, fsa, context);
}
}

/** Create a generator object for the given target */
private GeneratorBase createGenerator(Target target, FileConfig fileConfig,
ErrorReporter errorReporter) {
Expand All @@ -114,8 +152,9 @@ private GeneratorBase createGenerator(Target target, FileConfig fileConfig,
return createCppGenerator(fileConfig, errorReporter);
}
case TS: {
return new TypeScriptGenerator(
(TypeScriptFileConfig) fileConfig, errorReporter);
// return new TypeScriptGenerator(
// (TypeScriptFileConfig) fileConfig, errorReporter);
return createTsGenerator(fileConfig, errorReporter);
}
case Python: {
return new PythonGenerator(fileConfig, errorReporter);
Expand Down Expand Up @@ -169,6 +208,49 @@ private GeneratorBase createCppGenerator(FileConfig fileConfig,
}
}

/**
* Create a TypeScript code generator
*
* Since the Typeenerator class is implemented in Kotlin, the class is
* not visible from all contexts. If the RCA is run from within Eclipse via
* "Run as Eclipse Application", the Kotlin classes are unfortunately not
* available at runtime due to bugs in the Eclipse Kotlin plugin. (See
* https://stackoverflow.com/questions/68095816/is-ist-possible-to-build-mixed-kotlin-and-java-applications-with-a-recent-eclips)
* In this case, the method returns null
*
* @return A TypeScriptGenerator object if the class can be found
*/
private GeneratorBase createTsGenerator(FileConfig fileConfig,
ErrorReporter errorReporter) {
// Since our Eclipse Plugin uses code injection via guice, we need to
// play a few tricks here so that TypeScriptFileConfig and
// TypeScriptGenerator do not appear as an import. Instead we look the
// class up at runtime and instantiate it if found.
try {
return (GeneratorBase) Class
.forName("org.lflang.generator.ts.TsGenerator")
.getDeclaredConstructor(
Class.forName(
"org.lflang.generator.ts.TsFileConfig"),
ErrorReporter.class, LFGlobalScopeProvider.class)
.newInstance(fileConfig, errorReporter, scopeProvider);
} catch (InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException
| ClassNotFoundException e) {
generatorErrorsOccurred = true;
errorReporter.reportError(
"The code generator for the TypeScript target could not be found. "
+ "This is likely because you are running the RCA from"
+ "Eclipse. The TypeScript code generator is written in Kotlin"
+ "and, unfortunately, the Eclipse Kotlin plugin is "
+ "broken, preventing us from loading the generator"
+ "properly. Please consider building the RCA via Maven.");
// FIXME: Add a link to the wiki with more information.
return null;
}
}

@Override
public void doGenerate(Resource resource, IFileSystemAccess2 fsa,
IGeneratorContext context) {
Expand Down
61 changes: 61 additions & 0 deletions org.lflang/src/org/lflang/generator/ts/TsFileConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*************
* Copyright (c) 2019-2020, The University of California at Berkeley.

* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:

* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.

* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
***************/

package org.lflang.generator.ts

import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.IFileSystemAccess2
import org.eclipse.xtext.generator.IGeneratorContext
import org.lflang.FileConfig
import java.io.IOException
import java.nio.file.Path

/** Generator for TypeScript target.
*
* @author {Hokeun Kim <hokeunkim@berkeley.edu>}
*/
class TsFileConfig(resource: Resource, fsa: IFileSystemAccess2,
context: IGeneratorContext) :
FileConfig(resource, fsa, context) {

/**
* Clean any artifacts produced by the TypeScript code generator.
*/
@Throws(IOException::class)
override fun doClean() {
super.doClean()
deleteDirectory(getSrcGenPath())
}

/**
* Path to TypeScript source code.
*/
fun tsSrcGenPath(): Path = getSrcGenPath().resolve("src")

/**
* Path to TypeScript core source code.
*/
fun tsCoreGenPath(): Path = tsSrcGenPath().resolve("core")
}
Loading