-
Notifications
You must be signed in to change notification settings - Fork 324
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
Stub Out the Parser Interface #1065
Merged
Merged
Changes from 15 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
4ef5b89
wip
Kesanov 928ac84
Merge branch 'main' into wip/jv/parser
Kesanov fabb232
now it actually works
Kesanov 4c0567d
now with rust code
Kesanov bffed28
lint
Kesanov 3a7ef9f
remove plugin
Kesanov ad79c91
more methods and comments
Kesanov 69d5d07
jvm generation
Kesanov a6593a7
docs
Kesanov ea48aae
Merge branch 'main' into wip/jv/parser
Kesanov 13ef355
check version
Kesanov ebc9898
more docs
Kesanov 59d0e3c
grammar
Kesanov c5e0fe6
cargo
Kesanov 9d4ff2d
cargo
Kesanov abd4fc3
docs
Kesanov cf0bce7
Merge branch 'main' into wip/jv/parser
Kesanov e28383a
Merge branch 'main' into wip/jv/parser
Kesanov File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
--- | ||
layout: developer-doc | ||
title: Rust | ||
category: infrastructure | ||
tags: [infrastructure, build] | ||
order: 1 | ||
--- | ||
|
||
# Rust | ||
|
||
The Rust project is built using Cargo which manages dependencies between the | ||
projects as well as external dependencies and allows for incremental | ||
compilation. The build configuration is defined in | ||
[`Cargo.toml`](../../Cargo.toml). | ||
|
||
<!-- MarkdownTOC levels="2,3" autolink="true" --> | ||
|
||
- [Shared Libraries](#shared-libraries) | ||
|
||
<!-- /MarkdownTOC --> | ||
|
||
# Java Native Interface | ||
|
||
Although the entry point of the Enso project is a Java archive, it can still | ||
make use of native libraries built in Rust trough the JVM foreign function | ||
interface (FFI) named | ||
[Java Native Interface](https://en.wikipedia.org/wiki/Java_Native_Interface) | ||
(JNI). | ||
|
||
In order to generate a shared library, the `Cargo.toml` needs to enable | ||
compilation into a dynamic system library: | ||
|
||
``` | ||
crate-type = ["cdylib"] | ||
``` | ||
|
||
Invoking `cargo build` will then output the library into `target/rust/debug` | ||
with the extension `.so` on Linux, `.dll` on Windows and `.dylib` on macOS. | ||
|
||
Then, if the Java application is started with the option | ||
`-Djava.library.path=path/to/lib_folder`, it can load the shared library by | ||
`System.loadLibrary("lib_name")`. | ||
iamrecursion marked this conversation as resolved.
Show resolved
Hide resolved
Kesanov marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
[package] | ||
name = "parser" | ||
version = "0.1.0" | ||
authors = ["Enso Team <[email protected]>"] | ||
edition = "2018" | ||
|
||
description = "A parser for the Enso language" | ||
readme = "README.md" | ||
homepage = "https://github.com/enso-org/enso/lib/rust/parser" | ||
repository = "https://github.com/enso-org/enso" | ||
license-file = "../../../LICENSE" | ||
|
||
keywords = ["parser"] | ||
categories = ["parsing"] | ||
|
||
publish = false | ||
|
||
[lib] | ||
name = "parser" | ||
crate-type = ["cdylib", "rlib"] | ||
test = true | ||
bench = true | ||
|
||
[dependencies] | ||
jni = { version = "0.17.0" } | ||
ast = { version = "0.1.0", path = "../ast" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
//! This module exports JNI interface for parser methods implemented in Rust. | ||
//! | ||
//! The basics steps to add a new method are following: | ||
//! 1. Add the new method in Scala (in `org.enso.parser.Parser`). | ||
//! 2. (Optional) Run `scalac Parser.scala; javah Parser` to generate the C API in `Parser.h`. | ||
//! Note that you can skip this step. It is merely a guidance for you, as it generates | ||
//! the correct function names and type signatures of all `Parser` native methods. | ||
//! Generally, the method interface is going to have the following shape: | ||
//! ```c | ||
//! JNIEXPORT $returnType JNICALL Java_$package_$className_$methodName | ||
//! (JNIEnv* env, jobject this, $argType1 $arg1, $argType2 $arg2) | ||
//! ``` | ||
//! For example if the definition is: | ||
//! ```scala | ||
//! package org.enso.parser | ||
//! | ||
//! class Parser { | ||
//! @native def newMethod(string: String, array: Array[Int]) | ||
//! } | ||
//! ``` | ||
//! Then the JNI API is going to be: | ||
//! ```c | ||
//! JNIEXPORT jobject JNICALL Java_org_enso_parser_Parser_newMethod | ||
//! (JNIEnv* env, jobject this, jstring string, jintArray array) | ||
//! ``` | ||
//! The list of all available types can be found in | ||
//! [oracle documentation](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html). | ||
//! 3. Implement the new parser method in this file. | ||
//! For the above definition the implementation is going to be: | ||
//! ```rust | ||
//! use jni::JNIEnv; | ||
//! use jni::objects::*; | ||
//! use jni::sys::*; | ||
//! | ||
//! #[no_mangle] | ||
//! pub extern "system" fn Java_org_enso_parser_Parser_newMethod( | ||
//! env : JNIEnv, // the JVM enviroment, used for calling methods and constructors | ||
//! this : JClass, // the instance of `Parser` | ||
//! string : JString, | ||
//! array : jintArray, | ||
//! ) -> jweak { unimplemented!() } | ||
//! ``` | ||
//! 4. (Optional) Generate a shared library from the Rust definition by `cargo build`. | ||
//! It will be generated into `target/rust/debug/`. | ||
//! This step is done automatically by `sbt`. | ||
|
||
use jni::JNIEnv; | ||
use jni::objects::*; | ||
use jni::sys::*; | ||
|
||
|
||
|
||
// ====================== | ||
// === Parser JNI API === | ||
// ====================== | ||
|
||
/// Parses a content a of single source file. | ||
#[no_mangle] | ||
pub extern "system" fn Java_org_enso_parser_Parser_parseStr( | ||
env : JNIEnv, | ||
_this : JClass, | ||
input : JString, | ||
) -> jweak { | ||
let txt = env.new_object( | ||
env.find_class("org/enso/ast/Ast$Txt$Text").unwrap(), | ||
"(Ljava/lang/String;)V", | ||
&[input.into()], | ||
).unwrap(); | ||
|
||
let non = env.get_static_field( | ||
env.find_class("scala/None$").unwrap(), | ||
"MODULE$", | ||
"Lscala/None$;", | ||
).unwrap().l().unwrap(); | ||
|
||
let ast = env.new_object( | ||
env.find_class("org/enso/ast/Ast$Ast").unwrap(), | ||
"(Lscala/Option;JJLjava/lang/Object;)V", | ||
&[non.into(), 0i64.into(), 0i64.into(), txt.into()], | ||
).unwrap(); | ||
|
||
ast.into_inner() | ||
} | ||
|
||
/// Parses a single source file. | ||
#[no_mangle] | ||
pub extern "system" fn Java_org_enso_parser_Parser_parseFile( | ||
env : JNIEnv, | ||
this : JClass, | ||
filename : JString, | ||
) -> jweak { | ||
Java_org_enso_parser_Parser_parseStr(env, this, filename) | ||
} | ||
|
||
|
||
// === Tokens === | ||
|
||
/// Parses a content of a single source file into a stream of tokens. | ||
#[no_mangle] | ||
pub extern "system" fn Java_org_enso_parser_Parser_lexStr( | ||
env : JNIEnv, | ||
this : JClass, | ||
input : JString, | ||
) -> jweak { | ||
Java_org_enso_parser_Parser_parseStr(env, this, input) | ||
} | ||
|
||
/// Parses a single source file into a stream of tokens. | ||
#[no_mangle] | ||
pub extern "system" fn Java_org_enso_parser_Parser_lexFile( | ||
env : JNIEnv, | ||
this : JClass, | ||
filename : JString, | ||
) -> jweak { | ||
Java_org_enso_parser_Parser_parseStr(env, this, filename) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#![feature(test)] | ||
#![deny(unconditional_recursion)] | ||
#![warn(missing_copy_implementations)] | ||
#![warn(missing_debug_implementations)] | ||
#![warn(missing_docs)] | ||
#![warn(trivial_casts)] | ||
#![warn(trivial_numeric_casts)] | ||
#![warn(unsafe_code)] | ||
#![warn(unused_import_braces)] | ||
|
||
//! This module exports the implementation of parser for the Enso language. | ||
|
||
mod jni; | ||
|
||
pub use crate::jni::*; | ||
|
||
use ast::AnyAst; | ||
use ast::Ast; | ||
|
||
|
||
|
||
// ======================= | ||
// === Parser Rust API === | ||
// ======================= | ||
|
||
/// Parse a content of a single source file. | ||
pub fn parse_str(input:String) -> AnyAst { | ||
Ast::new(ast::txt::Text{text:input}) | ||
} | ||
|
||
/// Parse a single source file. | ||
pub fn parse_file(filename:String) -> AnyAst { | ||
parse_str(filename) | ||
} | ||
|
||
|
||
// === Tokens === | ||
|
||
/// Parse a content of single source file. | ||
pub fn lexe_str(input:String) -> AnyAst { | ||
Kesanov marked this conversation as resolved.
Show resolved
Hide resolved
|
||
parse_str(input) | ||
} | ||
|
||
/// Parse a single source file. | ||
pub fn lexe_file(filename:String) -> AnyAst { | ||
parse_str(filename) | ||
} |
41 changes: 41 additions & 0 deletions
41
lib/scala/parser/src/main/scala/org/enso/parser/Parser.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package org.enso.parser | ||
|
||
import org.enso.ast.Ast | ||
|
||
import scala.annotation.unused | ||
|
||
|
||
/** This is the Enso language parser. | ||
* | ||
* It is a wrapper of parser written in Rust that uses JNI to efficiently | ||
* construct scala AST directly without any serialization overhead. | ||
* | ||
* The methods are loaded from a native shared library `parser` that is located | ||
* in a directory specified by `-Djava.library.path` and has one of the extensions | ||
* `.dll`, `.so` or `dylib` depending on the platform (windows, linux or mac). | ||
* | ||
* The shared library itself is generated into `target/rust/debug` by executing | ||
* `cargo build -p parser`. Each method marked by `@native` must have a | ||
* corresponding counterpart in rust, otherwise the loading of the shared library | ||
* is going to fail at runtime with `UnsatisfiedLinkingError`. | ||
*/ | ||
class Parser private () { | ||
/** Parses a content of a single source file. */ | ||
@native def parseStr(@unused input: String): Ast.AnyAst | ||
|
||
/** Parses a single source file. */ | ||
@native def parseFile(@unused filename: String): Ast.AnyAst | ||
|
||
/** Parses a content of a single source file into a stream of tokens. */ | ||
@native def lexStr(@unused input: String): Ast.AnyAst | ||
|
||
/** Parses a single source file into a stream of tokens. */ | ||
@native def lexFile(@unused filename: String): Ast.AnyAst | ||
} | ||
|
||
object Parser { | ||
System.loadLibrary("parser") | ||
|
||
/** Constructs a new parser */ | ||
def apply(): Parser = new Parser() | ||
} |
20 changes: 20 additions & 0 deletions
20
lib/scala/parser/src/test/scala/org/enso/parser/ParserTest.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.enso.parser | ||
|
||
import org.enso.ast.Ast | ||
|
||
import org.scalatest.flatspec.AnyFlatSpec | ||
import org.scalatest.matchers.should.Matchers | ||
|
||
|
||
|
||
class ParserTest extends AnyFlatSpec with Matchers { | ||
val parser: Parser = Parser() | ||
|
||
it should "parse file" in { | ||
val expected = Ast.Ast(uid=None, len=0, off=0, ast=Ast.Txt.Text("Hello!")) | ||
assert(expected == parser.parseStr("Hello!")) | ||
assert(expected == parser.parseFile("Hello!")) | ||
assert(expected == parser.lexStr("Hello!")) | ||
assert(expected == parser.lexFile("Hello!")) | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.