diff --git a/.github/workflows/enso4igv.yml b/.github/workflows/enso4igv.yml new file mode 100644 index 00000000000..b090f7b4d8c --- /dev/null +++ b/.github/workflows/enso4igv.yml @@ -0,0 +1,41 @@ +# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Enso Language Support for IGV + +on: + push: + branches: [develop] + pull_request: + branches: [develop] + paths: + - "tools/enso4igv/**/*" + +jobs: + build: + runs-on: ubuntu-20.04 + strategy: + matrix: + java: ["8"] + + steps: + - uses: actions/checkout@v2 + - name: Set up Java + uses: actions/setup-java@v2 + with: + distribution: "zulu" + java-version: ${{ matrix.java }} + cache: maven + + - name: Update project version + working-directory: tools/enso4igv + run: | + mvn versions:set -DnewVersion=`mvn -q -DforceStdout help:evaluate -Dexpression=project.version | cut -f1 -d -`.$GITHUB_RUN_NUMBER + + - name: Build with Maven + run: mvn -B package --file tools/enso4igv/pom.xml + - name: Archive NBM file + uses: actions/upload-artifact@v3 + with: + name: Enso IGV Plugin + path: tools/enso4igv/target/*.nbm diff --git a/CHANGELOG.md b/CHANGELOG.md index aa0044b31c3..12756632d5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -248,6 +248,7 @@ builtins from method signatures][3454] - [Avoid needless concatenations of warning/error messages][3465] - [Added a full-blown DSL for builtins][3471] +- [Integration of Enso with Ideal Graph Visualizer][3533] - [Lazy evaluation of RHS argument for || and &&][3492] - [Drop Core implementation of IR][3512] - [Replace `this` with `self`][3524] @@ -276,6 +277,7 @@ [3461]: https://github.com/enso-org/enso/pull/3461 [3465]: https://github.com/enso-org/enso/pull/3465 [3471]: https://github.com/enso-org/enso/pull/3471 +[3533]: https://github.com/enso-org/enso/pull/3533 [3492]: https://github.com/enso-org/enso/pull/3492 [3493]: https://github.com/enso-org/enso/pull/3493 [3505]: https://github.com/enso-org/enso/pull/3505 diff --git a/distribution/bin/enso b/distribution/bin/enso index 2c34c242061..6826c641072 100755 --- a/distribution/bin/enso +++ b/distribution/bin/enso @@ -1,3 +1,12 @@ COMP_PATH=$(dirname "$0")/../component -exec java -jar -Dtruffle.class.path.append="$COMP_PATH/runtime.jar" $JAVA_OPTS $COMP_PATH/runner.jar "$@" + +EXTRA_OPTS="-Dgraal.PrintGraph=Network" +for opt in "$@"; do + if [ "$opt" = "--dump-graphs" ]; then + EXTRA_OPTS="$EXTRA_OPTS -Dgraal.Dump=:1" + fi +done + + +exec java -jar -Dtruffle.class.path.append="$COMP_PATH/runtime.jar" $EXTRA_OPTS $JAVA_OPTS $COMP_PATH/runner.jar "$@" exit diff --git a/distribution/bin/enso.bat b/distribution/bin/enso.bat index b2a117de5e9..271f5e52d69 100644 --- a/distribution/bin/enso.bat +++ b/distribution/bin/enso.bat @@ -1,3 +1,10 @@ -@set comp-dir=%~dp0\..\component -@java -jar -Dtruffle.class.path.append=%comp-dir%\runtime.jar -Dpolyglot.engine.IterativePartialEscape=true %JAVA_OPTS% %comp-dir%\runner.jar %* -@exit /B %errorlevel% +@echo off +set comp-dir=%~dp0\..\component +set EXTRA_OPTS=-Dgraal.PrintGraph=Network +FOR %%A in (%*) DO ( +if /I %%A==--dump-graphs ( +set EXTRA_OPTS=%EXTRA_OPTS% -Dgraal.Dump=Truffle:1 +) +) +java -jar -Dtruffle.class.path.append=%comp-dir%\runtime.jar -Dpolyglot.engine.IterativePartialEscape=true %EXTRA_OPTS% %JAVA_OPTS% %comp-dir%\runner.jar %* +exit /B %errorlevel% diff --git a/docs/runtime-guide.md b/docs/runtime-guide.md index 50ce9c6e4e4..b636ed74531 100644 --- a/docs/runtime-guide.md +++ b/docs/runtime-guide.md @@ -50,7 +50,8 @@ order: 7 [IGV](https://www.graalvm.org/graalvm-as-a-platform/language-implementation-framework/Profiling/). It's a horrible tool. It's clunky, ugly, and painful to use. It has also saved us more times than we can count, definitely worth investing the time to - understand it. Use + understand it. Download + [Enso Language Support for IGV](../tools/enso4igv/README.md). Use [this tutorial](https://shopify.engineering/understanding-programs-using-graphs) (and [the follow up post](https://chrisseaton.com/truffleruby/basic-truffle-graphs/)) @@ -62,8 +63,9 @@ order: 7 debugging options. 3. Use [hsdis](https://github.com/liuzhengyang/hsdis/) for printing the generated assembly – you can often spot obvious problems with compilations. - That being said, IGV is usually the better tool, if you take a look at the - later compilation stages. + That being said, IGV (with + [Enso Language Support](../tools/enso4igv/README.md)) is usually the better + tool, if you take a look at the later compilation stages. 4. Pay attention to making things `final` and `@CompilationFinal`. This is the most important way Graal does constant-folding. Whenever a loop bound can be compilation final, take advantage (and use `@ExplodeLoop`). @@ -179,7 +181,8 @@ design choices. Here's a list with some explanations: if any benchmark is more than 20% slower than the fastest recorded run. Don't use your computer when running these. It is also worth noting that these can be run through the `withDebug` utility, which allows you to test truffle - compilations (and e.g. watch the graphs in IGV). + compilations (and e.g. watch the graphs in IGV with + [Enso Language Support](../tools/enso4igv/README.md)). 8. **Tests**: There are scalatests that comprehensively test all of the language semantics and compiler passes. These are run with `sbt runtime/test`. For newer functionalities, we prefer adding tests to the `Tests` project in the diff --git a/engine/runner/src/main/scala/org/enso/runner/Main.scala b/engine/runner/src/main/scala/org/enso/runner/Main.scala index 0376d67f17d..642ba662682 100644 --- a/engine/runner/src/main/scala/org/enso/runner/Main.scala +++ b/engine/runner/src/main/scala/org/enso/runner/Main.scala @@ -17,7 +17,7 @@ import org.graalvm.polyglot.PolyglotException import java.io.File import java.nio.file.{Path, Paths} -import java.util.{Collections, UUID} +import java.util.{HashMap, UUID} import scala.Console.err import scala.concurrent.duration._ @@ -30,6 +30,7 @@ object Main { private val RUN_OPTION = "run" private val INSPECT_OPTION = "inspect" + private val DUMP_GRAPHS_OPTION = "dump-graphs" private val HELP_OPTION = "help" private val NEW_OPTION = "new" private val PROJECT_NAME_OPTION = "new-project-name" @@ -99,6 +100,10 @@ object Main { .longOpt(INSPECT_OPTION) .desc("Start the Chrome inspector when --run is used.") .build + val dumpGraphs = CliOption.builder + .longOpt(DUMP_GRAPHS_OPTION) + .desc("Dumps IGV graphs when --run is used.") + .build val docs = CliOption.builder .longOpt(DOCS_OPTION) .desc("Runs the Enso documentation generator.") @@ -345,6 +350,7 @@ object Main { .addOption(repl) .addOption(run) .addOption(inspect) + .addOption(dumpGraphs) .addOption(docs) .addOption(preinstall) .addOption(newOpt) @@ -505,6 +511,7 @@ object Main { * @param logMasking is the log masking enabled * @param enableIrCaches are IR caches enabled * @param inspect shall inspect option be enabled + * @param dump shall graphs be sent to the IGV */ private def run( path: String, @@ -513,7 +520,8 @@ object Main { logMasking: Boolean, enableIrCaches: Boolean, enableAutoParallelism: Boolean, - inspect: Boolean + inspect: Boolean, + dump: Boolean ): Unit = { val file = new File(path) if (!file.exists) { @@ -535,6 +543,14 @@ object Main { } file.getAbsolutePath } else projectPath.getOrElse("") + val options = new HashMap[String, String]() + if (dump) { + options.put("engine.TraceCompilation", "true") + options.put("engine.MultiTier", "false") + } + if (inspect) { + options.put("inspect", "") + } val context = new ContextFactory().create( projectRoot, System.in, @@ -545,9 +561,7 @@ object Main { enableIrCaches, strictErrors = true, enableAutoParallelism = enableAutoParallelism, - options = - if (inspect) Collections.singletonMap("inspect", "") - else Collections.emptyMap + options = options ) if (projectMode) { PackageManager.Default.loadPackage(file) match { @@ -1013,7 +1027,8 @@ object Main { logMasking, shouldEnableIrCaches(line), line.hasOption(AUTO_PARALLELISM_OPTION), - line.hasOption(INSPECT_OPTION) + line.hasOption(INSPECT_OPTION), + line.hasOption(DUMP_GRAPHS_OPTION) ) } if (line.hasOption(REPL_OPTION)) { diff --git a/tools/enso4igv/README.md b/tools/enso4igv/README.md new file mode 100644 index 00000000000..24e88955cd3 --- /dev/null +++ b/tools/enso4igv/README.md @@ -0,0 +1,130 @@ +# Enso Language Support for NetBeans & Ideal Graph Visualizer + +[![Enso Language Support for IGV](https://github.com/enso-org/enso/actions/workflows/enso4igv.yml/badge.svg)](https://github.com/enso-org/enso/actions/workflows/enso4igv.yml) + +[Enso language](http://enso.org) runtime engine is built on top of +[GraalVM](http://graalvm.org) and its _Truffle framework_. Enso, as a good +citizen of the GraalVM ecosystem, benefits from polyglot capabilities of GraalVM +as well as its rich tooling offering. One of such tools is _IGV_ - the _Ideal +Graph Visualizer_ - an excellent tool to get insights into behavior of Graal +compiler. + +This document shows how to use _IGV_ with the _Enso language_. The command line +instructions format is Unix oriented. Use instructions appropriate for your +operating system to perform the same on different _OS_. _IGV_ itself as well as +the _Enso language_ support are platform neutral with launch scripts for all +major operating systems. + +## Installation + +Visit [GraalVM.org](http://graalvm.org) download page and continue towards +_enterprise edition_ option. There is an _Ideal Graph Visualizer_ option. After +clicking through the confirmation dialogs you should get a ZIP - I've just got +`idealgraphvisualizer-22.1.0.zip` and then: + +```bash +$ unzip idealgraphvisualizer-22.1.0.zip +$ ./idealgraphvisualizer/bin/idealgraphvisualizer --userdir /tmp/emptyuserdir +``` + +launches the _IGV_ application. One doesn't have to use the `--userdir` option, +but doing so ensures the newly running _IGV_ process is isolated from any +settings left around by previous usage of _IGV_. + +IGV understands Enso when +[Enso Language Support module](https://github.com/enso-org/enso/actions/workflows/enso4igv.yml) +is installed. Login to GitHub, follow the +[GitHub actions link](https://github.com/enso-org/enso/actions/workflows/enso4igv.yml) +and select a build. Unless you have some special needs choose the latest one. +The build summary page provides various information as well as list of artifacts +at the bottom. Download the _Enso IGV Plugin_ ZIP file (make sure you are logged +into GitHub - artifacts are only available to those logged in). Unzip it and get +`enso*.nbm` file. This file can be installed into _IGV_ (or any other +[NetBeans](http://netbeans.apache.org) based application). Go to +_Tools_/_Plugins_/_Downloaded_/_Add Plugins_ and select the NBM file. + +![Tools/Plugins/Downloaded](https://user-images.githubusercontent.com/26887752/174608153-9f0b54fa-b507-45be-83de-d7911186d121.png) + +Proceed by clicking _Install_. You may be asked to download _TextMate Lexer_ - a +necessary dependency of the _Enso support_ module. Continue through the wizard +to _finish_ the installation. + +![Tools/Plugins/Downloaded](https://user-images.githubusercontent.com/26887752/174608219-1faf2728-0045-478b-a297-e3c06f691b19.png) + +## Using the IGV + +Get an instance of the Enso runtime engine (see +[Running Enso](../../docs/CONTRIBUTING.md#running-enso)) and then launch it with +special `--dump-graphs` option: + +```bash +enso$ ./built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/bin/enso --dump-graphs --run yourprogram.enso +``` + +When executed on [GraalVM 21.3.0](http://graalvm.org) these options instruct the +_Graal/Truffle compiler_ to dump files into `graal_dumps/_sometimestamp_` +directory. Generating these files takes a while - make sure `yourprogram.enso` +runs long enough for the system to warmup, compile the code and run at _full +speed_. + +#### Sieve of Eratosthenes Example + +As an example you can download +[sieve.enso](https://github.com/jtulach/sieve/blob/5b32450da35415322e683bb9769aa45f0d71f1df/enso/sieve.enso) +which computes hundred thousand of prime numbers repeatedly and measures time of +each round. Download the file and launch Enso with `--dump-graphs` argument: + +```bash +enso$ ./built-distribution/enso-engine-0.0.0-dev-linux-amd64/enso-0.0.0-dev/bin/enso --dump-graphs --run sieve.enso +``` + +Bunch of files in `graal_dumps/*` subdirectory is going to be generated: + +```bash +enso$ ls graal_dumps/*/Truffle* | tail -n5 +graal_dumps/2022.06.20.06.18.21.733/TruffleHotSpotCompilation-9889[argument<2>].bgv +graal_dumps/2022.06.20.06.18.21.733/TruffleHotSpotCompilation-9896[IfThenElseMethodGen@3af870b9_]_1.bgv +graal_dumps/2022.06.20.06.18.21.733/TruffleHotSpotCompilation-9896[IfThenElseMethodGen@3af870b9_].bgv +graal_dumps/2022.06.20.06.18.21.733/TruffleHotSpotCompilation-9935[Primes.next_]_1.bgv +graal_dumps/2022.06.20.06.18.21.733/TruffleHotSpotCompilation-9935[Primes.next_].bgv +``` + +Let's launch IGV with Enso integration and let's open graph for one of the +top-most functions: `TruffleHotSpotCompilation*Primes*next*.bgv`. Choose +compilation phase _"Before lowering"_: + +![Before Lowering Graph](https://user-images.githubusercontent.com/26887752/174608397-331a4438-1f12-40b0-9fcd-59eda5e53fb6.png) + +Now you can inspect the _compiler graphs_ the regular _IGV_ way. Let's locate +for example `LoadField#FunctionSchema.isFullyApplied` node and let's check how +it got _inlined_(you can use search box in the top-right corner) + +![Inlining Stacktrace](https://user-images.githubusercontent.com/26887752/174608478-e7002c43-d746-42c0-b61c-92ceb9d9f124.png) + +The stack trace shows what methods of the Enso interpreter and Truffle runtime +are _"inlined on stack"_ when this node is being compiled. This is all regular +_IGV_ functionality, but now we can switch to _Enso view_: + +![Enso Source](https://user-images.githubusercontent.com/26887752/174608595-4ce80b00-949a-4b28-84a7-60d5988bfc70.png) + +By choosing the _Enso language icon_ in front of the stack trace combo, the +source code of our `.enso` program is opened and we can analyze what _compiler +nodes_ refer to what lines in the our _Enso_ program. Click _Navigate to Source_ +icon in the _Stack View_ to get from graph node to source. Select a drop down +widget in the editor toolbar to show you what compiler nodes as associated with +currently selected line. + +## Building + +The plugin can be rebuilt using [Apache Maven](http://maven.apache.org). The +build is platform independent. The following instructions are for Unix like +environment. Switch to this directory and invoke: + +```bash +enso/tools/enso4igv$ mvn clean install +enso/tools/enso4igv$ ls target/*.nbm +target/enso4igv-1.0-SNAPSHOT.nbm +``` + +an NBM file is generated which can be installed into IGV, NetBeans or any other +NetBeans based application. diff --git a/tools/enso4igv/pom.xml b/tools/enso4igv/pom.xml new file mode 100644 index 00000000000..c44e24bd30b --- /dev/null +++ b/tools/enso4igv/pom.xml @@ -0,0 +1,111 @@ + + + 4.0.0 + org.enso.tools + enso4igv + nbm + Enso Language Support for NetBeans & Ideal Graph Visualizer + 1.0-SNAPSHOT + + + + org.apache.netbeans.utilities + nbm-maven-plugin + true + 4.7 + + true + Enso.org + Apache 2.0 + ../../LICENSE + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.2 + + + ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + + + + + + + org.netbeans.api + org-netbeans-api-annotations-common + ${netbeans.version} + + + org.netbeans.api + org-netbeans-modules-textmate-lexer + ${netbeans.version} + + + org.netbeans.api + org-netbeans-api-templates + ${netbeans.version} + + + org.netbeans.api + org-openide-filesystems + ${netbeans.version} + + + org.netbeans.api + org-openide-loaders + ${netbeans.version} + + + org.netbeans.api + org-openide-nodes + ${netbeans.version} + + + org.netbeans.api + org-openide-util + ${netbeans.version} + + + org.netbeans.api + org-openide-util-lookup + ${netbeans.version} + + + org.netbeans.api + org-openide-util-ui + ${netbeans.version} + + + org.netbeans.api + org-openide-windows + ${netbeans.version} + + + org.netbeans.api + org-openide-text + ${netbeans.version} + + + org.netbeans.api + org-netbeans-core-multiview + ${netbeans.version} + + + org.netbeans.api + org-openide-awt + ${netbeans.version} + + + org.netbeans.api + org-openide-dialogs + ${netbeans.version} + + + + UTF-8 + RELEASE113 + + diff --git a/tools/enso4igv/src/main/java/org/enso/tools/enso4igv/EnsoDataObject.java b/tools/enso4igv/src/main/java/org/enso/tools/enso4igv/EnsoDataObject.java new file mode 100644 index 00000000000..2009c77a33e --- /dev/null +++ b/tools/enso4igv/src/main/java/org/enso/tools/enso4igv/EnsoDataObject.java @@ -0,0 +1,112 @@ +package org.enso.tools.enso4igv; + +import java.io.IOException; +import org.netbeans.core.spi.multiview.MultiViewElement; +import org.netbeans.core.spi.multiview.text.MultiViewEditorElement; +import org.netbeans.modules.textmate.lexer.api.GrammarRegistration; +import org.openide.awt.ActionID; +import org.openide.awt.ActionReference; +import org.openide.awt.ActionReferences; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.MIMEResolver; +import org.openide.loaders.DataObject; +import org.openide.loaders.DataObjectExistsException; +import org.openide.loaders.MultiDataObject; +import org.openide.loaders.MultiFileLoader; +import org.openide.util.Lookup; +import org.openide.util.NbBundle.Messages; +import org.openide.windows.TopComponent; + +@Messages({ + "LBL_Enso_LOADER=Files of Enso" +}) +@MIMEResolver.ExtensionRegistration( + displayName = "#LBL_Enso_LOADER", + mimeType = "application/x-enso", + extension = {"enso"} +) +@GrammarRegistration(mimeType = "application/x-enso", grammar = "enso.tmLanguage.json") +@DataObject.Registration( + mimeType = "application/x-enso", + iconBase = "org/enso/tools/enso4igv/enso.png", + displayName = "#LBL_Enso_LOADER", + position = 300 +) +@ActionReferences({ + @ActionReference( + path = "Loaders/application/x-enso/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.OpenAction"), + position = 100, + separatorAfter = 200 + ), + @ActionReference( + path = "Loaders/application/x-enso/Actions", + id = @ActionID(category = "Edit", id = "org.openide.actions.CutAction"), + position = 300 + ), + @ActionReference( + path = "Loaders/application/x-enso/Actions", + id = @ActionID(category = "Edit", id = "org.openide.actions.CopyAction"), + position = 400, + separatorAfter = 500 + ), + @ActionReference( + path = "Loaders/application/x-enso/Actions", + id = @ActionID(category = "Edit", id = "org.openide.actions.DeleteAction"), + position = 600 + ), + @ActionReference( + path = "Loaders/application/x-enso/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.RenameAction"), + position = 700, + separatorAfter = 800 + ), + @ActionReference( + path = "Loaders/application/x-enso/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.SaveAsTemplateAction"), + position = 900, + separatorAfter = 1000 + ), + @ActionReference( + path = "Loaders/application/x-enso/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.FileSystemAction"), + position = 1100, + separatorAfter = 1200 + ), + @ActionReference( + path = "Loaders/application/x-enso/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.ToolsAction"), + position = 1300 + ), + @ActionReference( + path = "Loaders/application/x-enso/Actions", + id = @ActionID(category = "System", id = "org.openide.actions.PropertiesAction"), + position = 1400 + ) +}) +public class EnsoDataObject extends MultiDataObject { + + public EnsoDataObject(FileObject pf, MultiFileLoader loader) throws DataObjectExistsException, IOException { + super(pf, loader); + registerEditor("application/x-enso", true); + } + + @Override + protected int associateLookup() { + return 1; + } + + @MultiViewElement.Registration( + displayName = "#LBL_Enso_EDITOR", + iconBase = "org/enso/tools/enso4igv/enso.png", + mimeType = "application/x-enso", + persistenceType = TopComponent.PERSISTENCE_ONLY_OPENED, + preferredID = "Enso", + position = 1000 + ) + @Messages("LBL_Enso_EDITOR=Source") + public static MultiViewEditorElement createEditor(Lookup lkp) { + return new MultiViewEditorElement(lkp); + } + +} diff --git a/tools/enso4igv/src/main/java/org/enso/tools/enso4igv/package-info.java b/tools/enso4igv/src/main/java/org/enso/tools/enso4igv/package-info.java new file mode 100644 index 00000000000..67cd9f82bd0 --- /dev/null +++ b/tools/enso4igv/src/main/java/org/enso/tools/enso4igv/package-info.java @@ -0,0 +1,4 @@ +@TemplateRegistration(folder = "Other", content = "EnsoTemplate.enso") +package org.enso.tools.enso4igv; + +import org.netbeans.api.templates.TemplateRegistration; diff --git a/tools/enso4igv/src/main/nbm/manifest.mf b/tools/enso4igv/src/main/nbm/manifest.mf new file mode 100644 index 00000000000..31b7189a6d2 --- /dev/null +++ b/tools/enso4igv/src/main/nbm/manifest.mf @@ -0,0 +1,4 @@ +Manifest-Version: 1.0 +OpenIDE-Module-Layer: org/enso/tools/enso4igv/layer.xml +OpenIDE-Module-Localizing-Bundle: org/enso/tools/enso4igv/Bundle.properties + diff --git a/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/Bundle.properties b/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/Bundle.properties new file mode 100644 index 00000000000..f2b9d45f188 --- /dev/null +++ b/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/Bundle.properties @@ -0,0 +1,7 @@ +EnsoLanguage=Enso +OpenIDE-Module-Name=Enso for IGV +OpenIDE-Module-Short-Description=Enso language support for IGV +OpenIDE-Module-Long-Description=Provides Text Mate grammar for Enso language \ + as well as integration with IGV to properly analyze IGV graphs generated \ + for the Enso programs. +OpenIDE-Module-Display-Category=Editing diff --git a/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/EnsoTemplate.enso b/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/EnsoTemplate.enso new file mode 100644 index 00000000000..09419957860 --- /dev/null +++ b/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/EnsoTemplate.enso @@ -0,0 +1,10 @@ +from Standard.Base import all + +fac : Number -> Number +fac n = + facacc : Number -> Number -> Number + facacc n v = if n <= 1 then v else @Tail_Call facacc n-1 n*v + + facacc n 1 + +main = IO.println (here.fac 6) diff --git a/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/enso.png b/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/enso.png new file mode 100644 index 00000000000..cdde0d0e298 Binary files /dev/null and b/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/enso.png differ diff --git a/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/enso.tmLanguage.json b/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/enso.tmLanguage.json new file mode 100644 index 00000000000..cf6b2a0ca8f --- /dev/null +++ b/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/enso.tmLanguage.json @@ -0,0 +1,148 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "Enso", + "patterns": [{ + "include": "#keywords" + }, + { + "include": "#strings" + }, + { + "include": "#entity" + }, + { + "include": "#constant" + }, + { + "include":"#comments" + } + ], + "repository": { + "keywords": { + "patterns": [{ + "name": "keyword.other", + "match": "\\b(here|this|type)\\b" + }, { + "name": "keyword.control", + "match": "\\b(case|of|if|then|else)\\b" + }, { + "name": "keyword.control.import", + "match": "\\b(import as|export as|from all hiding|polyglot java)\\b" + }, + { + "name": "keyword.control.import", + "match": "^import\\s+.+(\\s+as.+)?$" + }, + { + "name": "keyword.control.import", + "match": "^from\\s+.+(\\s+as.+)?\\s+import.+$" + }, + { + "name": "keyword.control.import", + "match": "^export\\s+.+(\\s+as.+)?$" + }, + { + "name": "keyword.control.import.enso", + "match": "^from\\s+.+(\\s+as.+)?\\s+export.+$" + }, + { + "name": "keyword.control.import", + "match": "^polyglot\\s+java\\s+import\\s+.+(\\s+as.+)?$" + }, + { + "name": "keyword.operator", + "match": "[-!$%&\\*\\+\/<=>\\?^|~:.]+|\\b_\\b" + }, + { + "name": "keyword.operator", + "match": "=" + } + ] + }, + "entity": { + "patterns": [{ + "name": "entity.name.function", + "match": "\\b[a-z][a-z|_]*\\b" + }, + { + "name": "entity.name.type", + "match": "\\b[A-Z][a-z|0-9]*(_|[A-Z|0-9]|[a-z|0-9]*)*\\b" + }, + { + "name": "entity.name", + "match": "\\b[a-z|A-Z]\\w*\\b" + } + ] + }, + "strings": { + "name": "string.quoted.double", + "patterns": [{ + "name": "string.quoted.double", + "begin": "\"", + "end": "\"", + "patterns": [{ + "name": "constant.character.escape", + "matches": "\\\"" + }] + }, + { + "name": "string.quoted.single", + "begin": "\\'", + "end": "\\'", + "patterns": [{ + "name": "constant.character.escape", + "matches": "\\\\'" + }] + } + ] + }, + "constant": { + "patterns": [{ + "name": "constant.character", + "match": "\\\\u\\{[A-F|0-9]{1,8}\\}" + }, + { + "name": "constant.character", + "match": "\\\\u\\{[A-F|0-9]{4}\\}" + }, + { + "name": "constant.character", + "match": "\\\\U\\{[A-F|0-9]{8}\\}" + }, + { + "name": "constant.character.escape", + "match": "\\\\" + }, + { + "name": "constant.character.escape", + "match": "\\\"" + }, + { + "name": "constant.character.escape", + "match": "\\'" + }, + { + "name": "constant.character.escape", + "match": "\\[abfnrtve]" + }, + { + "name": "constant.character.numeric", + "match": "\\b[0-9]+(\\.[0-9]+)?" + } + ] + }, + "comments":{ + "patterns": [{ + "name": "comment.block.documentation", + "begin": "^(\\s*)##", + "end": "^(?!\\1\\s+)(?!\\s*$)" + }, + { + "name":"comment.line.number-sign", + "begin": "#", + "end": "$" + }] + } + }, + "scopeName": "source.enso" +} \ No newline at end of file diff --git a/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/layer.xml b/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/layer.xml new file mode 100644 index 00000000000..7e3d07ca03d --- /dev/null +++ b/tools/enso4igv/src/main/resources/org/enso/tools/enso4igv/layer.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + +