mirror of
https://github.com/enso-org/enso.git
synced 2025-01-03 09:42:00 +03:00
Run whole test/Base_Tests in native image runner (#10296)
This commit is contained in:
parent
b5641aa3bd
commit
fe2cf49568
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -33,7 +33,7 @@
|
||||
"request": "launch",
|
||||
"name": "Launch Native Image",
|
||||
"nativeImagePath": "${workspaceFolder}/runner",
|
||||
"args": "--help"
|
||||
"args": "--run ${file}"
|
||||
}
|
||||
]
|
||||
}
|
14
build.sbt
14
build.sbt
@ -2549,8 +2549,10 @@ lazy val `engine-runner` = project
|
||||
if (smallJdkDirectory.exists()) {
|
||||
IO.delete(smallJdkDirectory)
|
||||
}
|
||||
val JS_MODULES =
|
||||
"org.graalvm.nativeimage,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.base,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.objectfile,org.graalvm.nativeimage.pointsto,com.oracle.graal.graal_enterprise,com.oracle.svm.svm_enterprise,jdk.compiler.graal,jdk.httpserver,java.naming,java.net.http"
|
||||
val NI_MODULES =
|
||||
"org.graalvm.nativeimage,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.base,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.objectfile,org.graalvm.nativeimage.pointsto,com.oracle.graal.graal_enterprise,com.oracle.svm.svm_enterprise"
|
||||
val JDK_MODULES =
|
||||
"jdk.localedata,jdk.compiler.graal,jdk.httpserver,java.naming,java.net.http"
|
||||
val DEBUG_MODULES = "jdk.jdwp.agent"
|
||||
val PYTHON_MODULES = "jdk.security.auth,java.naming"
|
||||
|
||||
@ -2578,7 +2580,7 @@ lazy val `engine-runner` = project
|
||||
}
|
||||
|
||||
val exec =
|
||||
s"$jlink --module-path ${modules.mkString(":")} --output $smallJdkDirectory --add-modules $JS_MODULES,$DEBUG_MODULES,$PYTHON_MODULES"
|
||||
s"$jlink --module-path ${modules.mkString(":")} --output $smallJdkDirectory --add-modules $NI_MODULES,$JDK_MODULES,$DEBUG_MODULES,$PYTHON_MODULES"
|
||||
val exitCode = scala.sys.process.Process(exec).!
|
||||
|
||||
if (exitCode != 0) {
|
||||
@ -2610,6 +2612,9 @@ lazy val `engine-runner` = project
|
||||
additionalOptions = Seq(
|
||||
"-Dorg.apache.commons.logging.Log=org.apache.commons.logging.impl.NoOpLog",
|
||||
"-H:IncludeResources=.*Main.enso$",
|
||||
"-H:+AddAllCharsets",
|
||||
"-H:+IncludeAllLocales",
|
||||
"-ea",
|
||||
// useful perf & debug switches:
|
||||
// "-g",
|
||||
// "-H:+SourceLevelDebug",
|
||||
@ -2660,6 +2665,7 @@ lazy val `engine-runner` = project
|
||||
.dependsOn(`logging-service`)
|
||||
.dependsOn(`logging-service-logback` % Runtime)
|
||||
.dependsOn(`polyglot-api`)
|
||||
.dependsOn(`enso-test-java-helpers`)
|
||||
|
||||
lazy val buildSmallJdk =
|
||||
taskKey[File]("Build a minimal JDK used for native image generation")
|
||||
@ -3567,7 +3573,7 @@ ThisBuild / buildEngineDistributionNoIndex := {
|
||||
lazy val runEngineDistribution =
|
||||
inputKey[Unit]("Run or --debug the engine distribution with arguments")
|
||||
runEngineDistribution := {
|
||||
buildEngineDistribution.value
|
||||
buildEngineDistributionNoIndex.value
|
||||
val args: Seq[String] = spaceDelimited("<arg>").parsed
|
||||
DistributionPackage.runEnginePackage(
|
||||
engineDistributionRoot.value,
|
||||
|
@ -630,28 +630,12 @@ pub async fn runner_sanity_test(
|
||||
repo_root: &crate::paths::generated::RepoRoot,
|
||||
enso_java: Option<&str>,
|
||||
) -> Result {
|
||||
let factorial_input = "6";
|
||||
let factorial_expected_output = "720";
|
||||
let engine_package = repo_root.built_distribution.enso_engine_triple.engine_package.as_path();
|
||||
// The engine package is necessary for running the native runner.
|
||||
ide_ci::fs::tokio::require_exist(engine_package).await?;
|
||||
let output = Command::new(&repo_root.runner)
|
||||
.args([
|
||||
"--run",
|
||||
repo_root.engine.runner.src.test.resources.factorial_enso.as_str(),
|
||||
factorial_input,
|
||||
])
|
||||
.set_env_opt(ENSO_JAVA, enso_java)?
|
||||
.set_env(ENSO_DATA_DIRECTORY, engine_package)?
|
||||
.run_stdout()
|
||||
.await?;
|
||||
ensure!(
|
||||
output.contains(factorial_expected_output),
|
||||
"Native runner output does not contain expected result '{factorial_expected_output}'. Output:\n{output}",
|
||||
);
|
||||
if enso_java.is_none() {
|
||||
let test_base = Command::new(&repo_root.runner)
|
||||
.args(["--run", repo_root.test.join("Base_Tests").as_str(), "^Text"])
|
||||
.args(["--run", repo_root.test.join("Base_Tests").as_str()])
|
||||
.set_env_opt(ENSO_JAVA, enso_java)?
|
||||
.set_env(ENSO_DATA_DIRECTORY, engine_package)?
|
||||
.run_stdout()
|
||||
|
@ -4,6 +4,8 @@ import project.Errors.Encoding_Error.Encoding_Error
|
||||
from project.Data.Text.Extensions import all
|
||||
|
||||
polyglot java import java.util.Base64
|
||||
polyglot java import java.util.Base64.Decoder
|
||||
polyglot java import java.util.Base64.Encoder
|
||||
|
||||
## A helper utility for handling base64 encoding.
|
||||
type Base_64
|
||||
|
@ -30,6 +30,7 @@ from project.Data.Text.Extensions import all
|
||||
from project.Metadata.Choice import Option
|
||||
from project.Metadata.Widget import Single_Choice
|
||||
|
||||
polyglot java import com.fasterxml.jackson.core.JsonLocation
|
||||
polyglot java import com.fasterxml.jackson.core.JsonProcessingException
|
||||
polyglot java import com.fasterxml.jackson.databind.JsonNode
|
||||
polyglot java import com.fasterxml.jackson.databind.node.ArrayNode
|
||||
|
@ -9,6 +9,7 @@ import project.Nothing.Nothing
|
||||
import project.Panic.Panic
|
||||
|
||||
polyglot java import org.enso.base.statistics.FitError
|
||||
polyglot java import org.enso.base.statistics.LinearModel
|
||||
polyglot java import org.enso.base.statistics.Regression
|
||||
|
||||
type Model
|
||||
|
@ -34,6 +34,7 @@ polyglot java import java.time.DateTimeException
|
||||
polyglot java import java.time.temporal.ChronoField
|
||||
polyglot java import java.time.temporal.IsoFields
|
||||
polyglot java import org.enso.base.Time_Utils
|
||||
polyglot java import org.enso.base.Time_Utils.AdjustOp
|
||||
|
||||
## PRIVATE
|
||||
Constructs a new Date from a year, month, and day.
|
||||
|
@ -11,7 +11,10 @@ polyglot java import java.time.temporal.TemporalAdjuster
|
||||
polyglot java import java.time.temporal.TemporalAdjusters
|
||||
polyglot java import java.time.temporal.TemporalUnit
|
||||
polyglot java import org.enso.base.time.CustomTemporalUnits
|
||||
polyglot java import org.enso.base.time.Date_Utils
|
||||
polyglot java import org.enso.base.time.Date_Period_Utils
|
||||
polyglot java import org.enso.base.time.Date_Time_Utils
|
||||
polyglot java import org.enso.base.time.Time_Of_Day_Utils
|
||||
polyglot java import org.enso.base.Time_Utils
|
||||
|
||||
## Represents a unit of time longer on the scale of days (longer than a day).
|
||||
|
@ -25,19 +25,18 @@ from project.Data.Range.Extensions import all
|
||||
from project.Data.Text.Extensions import all
|
||||
from project.Metadata import Display, make_single_choice, Widget
|
||||
|
||||
polyglot java import java.io.StringReader
|
||||
polyglot java import java.lang.Exception as JException
|
||||
polyglot java import javax.xml.parsers.DocumentBuilder
|
||||
polyglot java import javax.xml.parsers.DocumentBuilderFactory
|
||||
polyglot java import javax.xml.xpath.XPath
|
||||
polyglot java import javax.xml.xpath.XPathConstants
|
||||
polyglot java import javax.xml.xpath.XPathFactory
|
||||
polyglot java import org.enso.base.XML_Utils
|
||||
polyglot java import org.w3c.dom.Attr
|
||||
polyglot java import org.w3c.dom.Document
|
||||
polyglot java import org.w3c.dom.Element
|
||||
polyglot java import org.w3c.dom.Node
|
||||
polyglot java import org.w3c.dom.NodeList
|
||||
polyglot java import org.w3c.dom.NamedNodeMap
|
||||
polyglot java import org.w3c.dom.Text as Java_Text
|
||||
polyglot java import org.xml.sax.InputSource
|
||||
polyglot java import org.xml.sax.SAXException
|
||||
polyglot java import org.xml.sax.SAXParseException
|
||||
|
||||
@ -75,7 +74,8 @@ type XML_Document
|
||||
from_stream : Input_Stream -> XML_Document ! XML_Error
|
||||
from_stream input_stream:Input_Stream =
|
||||
XML_Error.handle_java_exceptions <|
|
||||
input_stream.with_java_stream java_stream-> XML_Document.from_source java_stream
|
||||
input_stream.with_java_stream java_stream->
|
||||
XML_Document.Value (XML_Utils.parseStream java_stream)
|
||||
|
||||
## GROUP Conversions
|
||||
ICON convert
|
||||
@ -93,20 +93,13 @@ type XML_Document
|
||||
from_text : Text -> XML_Document ! XML_Error
|
||||
from_text xml_string:Text =
|
||||
XML_Error.handle_java_exceptions <|
|
||||
string_reader = StringReader.new xml_string
|
||||
XML_Document.from_source (InputSource.new string_reader)
|
||||
XML_Document.Value (XML_Utils.parseString xml_string)
|
||||
|
||||
## PRIVATE
|
||||
Read XML from an input source.
|
||||
from_source : Any -> XML_Document ! XML_Error
|
||||
from_source input_source =
|
||||
document_builder_factory = DocumentBuilderFactory.newInstance
|
||||
document_builder = document_builder_factory.newDocumentBuilder
|
||||
XML_Utils.setCustomErrorHandler document_builder
|
||||
XML_Document.Value (document_builder.parse input_source)
|
||||
Wrap Java's Document to XML_Document
|
||||
new doc:Document = XML_Document.Value doc
|
||||
|
||||
## PRIVATE
|
||||
Value (java_document:Document)
|
||||
private Value (java_document:Document)
|
||||
|
||||
|
||||
## GROUP Metadata
|
||||
|
@ -24,6 +24,10 @@ from project.Metadata import make_single_choice
|
||||
|
||||
polyglot java import org.enso.base.enso_cloud.EnsoSecretHelper
|
||||
polyglot java import org.enso.base.enso_cloud.HideableValue
|
||||
polyglot java import org.enso.base.enso_cloud.HideableValue.PlainValue
|
||||
polyglot java import org.enso.base.enso_cloud.HideableValue.SecretValue
|
||||
polyglot java import org.enso.base.enso_cloud.HideableValue.ConcatValues
|
||||
polyglot java import org.enso.base.enso_cloud.HideableValue.Base64EncodeValue
|
||||
|
||||
## A reference to a secret stored in the Enso Cloud.
|
||||
type Enso_Secret
|
||||
|
@ -14,3 +14,18 @@ polyglot java import org.enso.base.text.CaseFoldedString.Grapheme
|
||||
|
||||
# needed by Comparator_Spec:
|
||||
polyglot java import org.enso.base.ObjectComparator
|
||||
|
||||
# often used in tests
|
||||
polyglot java import java.util.ArrayList
|
||||
polyglot java import java.util.Map
|
||||
polyglot java import java.nio.CharBuffer
|
||||
polyglot java import java.nio.file.Path
|
||||
polyglot java import java.io.FileInputStream
|
||||
polyglot java import java.io.FileOutputStream
|
||||
polyglot java import java.math.BigInteger
|
||||
polyglot java import java.time.LocalDate
|
||||
polyglot java import java.time.LocalDateTime
|
||||
polyglot java import java.util.function.Function
|
||||
polyglot java import java.lang.Thread
|
||||
polyglot java import java.lang.Thread.State
|
||||
polyglot java import java.lang.Float
|
||||
|
@ -45,7 +45,7 @@ type Project_Description
|
||||
Arguments:
|
||||
- prim_root_file: The primitive root file of the project.
|
||||
- prim_config: The primitive config of the project.
|
||||
private Value prim_root_file prim_config
|
||||
private Value prim_root_file ns:Text n:Text
|
||||
|
||||
## GROUP Metadata
|
||||
ICON folder
|
||||
@ -78,7 +78,7 @@ type Project_Description
|
||||
|
||||
enso_project.name
|
||||
name : Text
|
||||
name self = self.prim_config.name
|
||||
name self = self.n
|
||||
|
||||
## GROUP Metadata
|
||||
ICON metadata
|
||||
@ -89,7 +89,7 @@ type Project_Description
|
||||
|
||||
enso_project.namespace
|
||||
namespace : Text
|
||||
namespace self = self.prim_config.namespace
|
||||
namespace self = self.ns
|
||||
|
||||
## ICON enso_icon
|
||||
Returns the Enso project description for the project that the engine was
|
||||
|
@ -30,12 +30,17 @@ from project.Data.Json.Extensions import all
|
||||
|
||||
polyglot java import java.lang.Exception as JException
|
||||
polyglot java import java.net.http.HttpClient
|
||||
polyglot java import java.net.http.HttpClient.Redirect
|
||||
polyglot java import java.net.http.HttpClient.Version
|
||||
polyglot java import java.net.http.HttpClient.Builder as ClientBuilder
|
||||
polyglot java import java.net.http.HttpRequest
|
||||
polyglot java import java.net.http.HttpRequest.BodyPublisher
|
||||
polyglot java import java.net.http.HttpRequest.BodyPublishers
|
||||
polyglot java import java.net.http.HttpRequest.Builder
|
||||
polyglot java import java.net.InetSocketAddress
|
||||
polyglot java import java.net.ProxySelector
|
||||
polyglot java import java.nio.file.Path
|
||||
polyglot java import javax.net.ssl.SSLContext
|
||||
polyglot java import org.enso.base.file_system.File_Utils
|
||||
polyglot java import org.enso.base.enso_cloud.EnsoSecretHelper
|
||||
polyglot java import org.enso.base.net.http.MultipartBodyBuilder
|
||||
polyglot java import org.enso.base.net.http.UrlencodedBodyBuilder
|
||||
@ -242,7 +247,7 @@ resolve_body_to_publisher_and_boundary body:Request_Body =
|
||||
json.if_not_error <|
|
||||
Pair.new (body_publishers.ofString json) Nothing
|
||||
Request_Body.Binary file ->
|
||||
path = Path.of file.path
|
||||
path = File_Utils.toPath file.path
|
||||
Pair.new (body_publishers.ofFile path) Nothing
|
||||
Request_Body.Form_Data form_data url_encoded ->
|
||||
build_form_body_publisher form_data url_encoded
|
||||
|
@ -25,6 +25,10 @@ from project.Data.Text.Extensions import all
|
||||
from project.Metadata import Display, Widget
|
||||
from project.Network.HTTP.Response_Body import decode_format_selector
|
||||
|
||||
polyglot java import java.net.http.HttpHeaders
|
||||
polyglot java import org.enso.base.enso_cloud.EnsoHttpResponse
|
||||
polyglot java import java.util.Optional
|
||||
|
||||
type Response
|
||||
## PRIVATE
|
||||
|
||||
|
@ -42,13 +42,12 @@ from project.System.File_Format import Auto_Detect, File_Format
|
||||
polyglot java import java.io.File as Java_File
|
||||
polyglot java import java.io.InputStream as Java_Input_Stream
|
||||
polyglot java import java.io.OutputStream as Java_Output_Stream
|
||||
polyglot java import java.nio.file.FileSystems
|
||||
polyglot java import java.nio.file.Path
|
||||
polyglot java import java.nio.file.StandardCopyOption
|
||||
polyglot java import java.nio.file.StandardOpenOption
|
||||
polyglot java import java.time.ZonedDateTime
|
||||
polyglot java import org.enso.base.DryRunFileManager
|
||||
polyglot java import org.enso.base.file_system.FileSystemSPI
|
||||
polyglot java import org.enso.base.file_system.File_Utils
|
||||
|
||||
## PRIVATE
|
||||
file_types : Vector
|
||||
@ -795,11 +794,10 @@ type File
|
||||
_ ->
|
||||
used_filter = if recursive.not || name_filter.contains "**" then name_filter else
|
||||
(if name_filter.starts_with "*" then "*" else "**/") + name_filter
|
||||
fs = FileSystems.getDefault
|
||||
matcher = fs.getPathMatcher "glob:"+used_filter
|
||||
matcher = File_Utils.matchPath "glob:"+used_filter
|
||||
all_files.filter file->
|
||||
pathStr = self.relativize file . path
|
||||
matcher.matches (Path.of pathStr)
|
||||
File_Utils.matches matcher pathStr
|
||||
|
||||
## GROUP Metadata
|
||||
ICON metadata
|
||||
@ -894,11 +892,11 @@ Writable_File.from (that : File) = if Data_Link.is_data_link that then Data_Link
|
||||
## PRIVATE
|
||||
local_file_copy (source : File) (destination : File) (replace_existing : Boolean) -> Nothing =
|
||||
File_Error.handle_java_exceptions source <|
|
||||
copy_options = if replace_existing then [StandardCopyOption.REPLACE_EXISTING] else []
|
||||
copy_options = if replace_existing then [StandardCopyOption.REPLACE_EXISTING.to_text] else []
|
||||
source.copy_builtin destination copy_options
|
||||
|
||||
## PRIVATE
|
||||
local_file_move (source : File) (destination : File) (replace_existing : Boolean) -> Nothing =
|
||||
File_Error.handle_java_exceptions source <|
|
||||
copy_options = if replace_existing then [StandardCopyOption.REPLACE_EXISTING] else []
|
||||
copy_options = if replace_existing then [StandardCopyOption.REPLACE_EXISTING.to_text] else []
|
||||
source.move_builtin destination copy_options
|
||||
|
@ -49,8 +49,9 @@ type File_Access
|
||||
## PRIVATE
|
||||
|
||||
Convert this object into a representation understandable by the JVM.
|
||||
to_java : StandardOpenOption
|
||||
to_java self = case self of
|
||||
to_java : Text
|
||||
to_java self =
|
||||
java_option = case self of
|
||||
File_Access.Append -> StandardOpenOption.APPEND
|
||||
File_Access.Create -> StandardOpenOption.CREATE
|
||||
File_Access.Create_New -> StandardOpenOption.CREATE_NEW
|
||||
@ -61,6 +62,7 @@ type File_Access
|
||||
File_Access.Sync -> StandardOpenOption.SYNC
|
||||
File_Access.Truncate_Existing -> StandardOpenOption.TRUNCATE_EXISTING
|
||||
File_Access.Write -> StandardOpenOption.WRITE
|
||||
java_option.to_text
|
||||
|
||||
## PRIVATE
|
||||
ensure_only_allowed_options (operation_name : Text) (allowed_options : Vector) (got_options : Vector) ~action =
|
||||
|
@ -3,6 +3,8 @@ import project.Data.Text.Text
|
||||
import project.Data.Vector.Vector
|
||||
|
||||
polyglot java import java.nio.file.attribute.PosixFilePermission
|
||||
polyglot java import java.nio.file.attribute.PosixFilePermissions
|
||||
polyglot java import java.util.Set
|
||||
|
||||
type Permission
|
||||
## Permission for read access for a given entity.
|
||||
@ -101,7 +103,8 @@ type File_Permissions
|
||||
## PRIVATE
|
||||
ADVANCED
|
||||
Converts a Java `Set` of Java `PosixFilePermission` to `File_Permissions`.
|
||||
from_java_set java_set =
|
||||
from_java_set permissions:Text =
|
||||
java_set = PosixFilePermissions.fromString permissions
|
||||
vecs = Vector.build_multiple 3 builders->
|
||||
owner = builders.at 0
|
||||
group = builders.at 1
|
||||
|
@ -23,6 +23,7 @@ polyglot java import java.io.InputStream as Java_Input_Stream
|
||||
polyglot java import org.enso.base.encoding.Encoding_Utils
|
||||
polyglot java import org.enso.base.encoding.ReportingStreamDecoder
|
||||
polyglot java import org.enso.base.Stream_Utils
|
||||
polyglot java import org.enso.base.Stream_Utils.InputStreamLike
|
||||
|
||||
## PRIVATE
|
||||
An input stream, allowing for interactive reading of contents.
|
||||
@ -113,7 +114,8 @@ type Input_Stream
|
||||
Arguments:
|
||||
- f: Applies a function over the internal java stream.
|
||||
with_java_stream : (Java_Input_Stream -> Any) -> Any
|
||||
with_java_stream self f = self.stream_resource . with java_stream->
|
||||
with_java_stream self f = self.stream_resource . with java_like_stream->
|
||||
java_stream = Stream_Utils.asInputStream java_like_stream
|
||||
self.error_handler <| f java_stream
|
||||
|
||||
## PRIVATE
|
||||
@ -158,7 +160,8 @@ type Input_Stream
|
||||
The current stream may be invalidated after the conversion, and it should
|
||||
no longer be used - only the returned stream should be used.
|
||||
as_peekable_stream self -> Input_Stream = if self.is_peekable then self else
|
||||
raw_java_stream = self.stream_resource.take
|
||||
raw_stream = self.stream_resource.take
|
||||
raw_java_stream = Stream_Utils.asInputStream raw_stream
|
||||
buffered_stream = BufferedInputStream.new raw_java_stream
|
||||
Input_Stream.new buffered_stream self.error_handler self.associated_source
|
||||
|
||||
|
@ -13,6 +13,7 @@ from project.Data.Boolean import Boolean, False, True
|
||||
from project.Runtime import assert
|
||||
|
||||
polyglot java import org.enso.base.encoding.DecodingProblemAggregator
|
||||
polyglot java import org.enso.base.encoding.DecodingProblem
|
||||
polyglot java import org.enso.base.encoding.Encoding_Utils
|
||||
polyglot java import org.enso.base.encoding.ReportingStreamDecoder
|
||||
|
||||
|
@ -15,6 +15,9 @@ from project.System.Input_Stream import close_stream
|
||||
polyglot java import java.io.ByteArrayOutputStream
|
||||
polyglot java import java.io.OutputStream as Java_Output_Stream
|
||||
polyglot java import org.enso.base.encoding.Encoding_Utils
|
||||
|
||||
polyglot java import org.enso.base.Stream_Utils
|
||||
polyglot java import org.enso.base.Stream_Utils.OutputStreamLike
|
||||
polyglot java import org.enso.base.encoding.ReportingStreamEncoder
|
||||
|
||||
## PRIVATE
|
||||
@ -57,7 +60,7 @@ type Output_Stream
|
||||
- stream_resource: The internal resource that represents the underlying
|
||||
stream.
|
||||
- error_handler: An error handler for IOExceptions thrown when writing.
|
||||
Value stream_resource error_handler
|
||||
private Value stream_resource error_handler
|
||||
|
||||
## PRIVATE
|
||||
ADVANCED
|
||||
@ -66,7 +69,8 @@ type Output_Stream
|
||||
Arguments:
|
||||
- contents: A vector of bytes to write.
|
||||
write_bytes : Vector Integer -> Nothing
|
||||
write_bytes self contents = self.stream_resource . with java_stream->
|
||||
write_bytes self contents = self.stream_resource . with raw_stream->
|
||||
java_stream = Stream_Utils.asOutputStream raw_stream
|
||||
self.error_handler <|
|
||||
java_stream.write contents
|
||||
java_stream.flush
|
||||
@ -80,7 +84,8 @@ type Output_Stream
|
||||
- input_stream: An Input_Stream to write to this stream.
|
||||
write_stream : Input_Stream -> Nothing
|
||||
write_stream self input_stream:Input_Stream =
|
||||
self.stream_resource . with java_output_stream->
|
||||
self.stream_resource . with raw_stream->
|
||||
java_output_stream = Stream_Utils.asOutputStream raw_stream
|
||||
self.error_handler <|
|
||||
input_stream.with_java_stream java_input_stream->
|
||||
java_input_stream.transferTo java_output_stream
|
||||
@ -107,7 +112,9 @@ type Output_Stream
|
||||
Arguments:
|
||||
- f: Applies a function over the internal java stream.
|
||||
with_java_stream : (Java_Output_Stream -> Any) -> Any
|
||||
with_java_stream self f = self.stream_resource . with f
|
||||
with_java_stream self f = self.stream_resource . with raw_stream->
|
||||
java_stream = Stream_Utils.asOutputStream raw_stream
|
||||
f java_stream
|
||||
|
||||
## PRIVATE
|
||||
ADVANCED
|
||||
|
@ -2772,7 +2772,7 @@ type Table
|
||||
if unused_columns.length > 0 then problem_builder.report_other_warning (Unexpected_Extra_Columns.Warning unused_columns)
|
||||
|
||||
problem_builder.attach_problems_before on_problems <|
|
||||
XML_Document.Value (Java_TableToXml.to_xml self.row_count java_element_columns java_attribute_column java_value_column root_name row_name)
|
||||
XML_Document.new (Java_TableToXml.to_xml self.row_count java_element_columns java_attribute_column java_value_column root_name row_name)
|
||||
|
||||
## PRIVATE
|
||||
columns_helper : Table_Column_Helper
|
||||
|
@ -205,8 +205,5 @@ type Test
|
||||
if i % 10 == 0 then
|
||||
IO.println 'Still failing after '+i.to_text+' retries ('+loc.to_display_text+'):\n'+caught_panic.payload.to_display_text
|
||||
Thread.sleep milliseconds_between_attempts
|
||||
## TODO This used to be
|
||||
@Tail_Call go (i+1)
|
||||
We should re-add the tail call once https://github.com/enso-org/enso/issues/9251 is fixed.
|
||||
go (i+1)
|
||||
go 1
|
||||
|
@ -207,17 +207,16 @@ state. To generate the Native Image for runner simply execute
|
||||
sbt> engine-runner/buildNativeImage
|
||||
```
|
||||
|
||||
and execute the binary on a sample factorial test program
|
||||
and execute any program with that binary - for example `test/Base_Tests`
|
||||
|
||||
```bash
|
||||
> runner --run engine/runner/src/test/resources/Factorial.enso 6
|
||||
$ runner --run test/Base_Tests
|
||||
```
|
||||
|
||||
The task that generates the Native Image, along with all the necessary
|
||||
configuration, reside in a separate project due to a bug in the currently used
|
||||
GraalVM version. As September 2023 it can execute all Enso code, but cannot
|
||||
invoke `IO.println` or other library functions that require
|
||||
[polyglot java import](../../docs/polyglot/java.md), but read on...
|
||||
configuration, makes sure that `Standard.Base` library calls into Java via
|
||||
[polyglot java import](../../docs/polyglot/java.md) are compiled into the binary
|
||||
and ready to be used.
|
||||
|
||||
### Engine with Espresso
|
||||
|
||||
|
@ -9,6 +9,7 @@ import java.util.TreeSet;
|
||||
import org.enso.compiler.core.ir.module.scope.imports.Polyglot;
|
||||
import org.enso.pkg.PackageManager$;
|
||||
import org.graalvm.nativeimage.hosted.Feature;
|
||||
import org.graalvm.nativeimage.hosted.RuntimeProxyCreation;
|
||||
import org.graalvm.nativeimage.hosted.RuntimeReflection;
|
||||
|
||||
public final class EnsoLibraryFeature implements Feature {
|
||||
@ -75,6 +76,9 @@ public final class EnsoLibraryFeature implements Feature {
|
||||
RuntimeReflection.registerAllConstructors(clazz);
|
||||
RuntimeReflection.registerAllFields(clazz);
|
||||
RuntimeReflection.registerAllMethods(clazz);
|
||||
if (clazz.isInterface()) {
|
||||
RuntimeProxyCreation.register(clazz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,8 @@
|
||||
{
|
||||
"resources":{
|
||||
"includes":[{
|
||||
"pattern":"\\QMETA-INF/native-image/com.oracle.truffle.espresso/native-image.properties\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/org/enso/interpreter/node/expression/builtin/BuiltinMethods.metadata\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/org/enso/interpreter/node/expression/builtin/BuiltinTypes.metadata\\E"
|
||||
@ -52,6 +54,8 @@
|
||||
"pattern":"\\QMETA-INF/services/java.time.zone.ZoneRulesProvider\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/javax.xml.parsers.DocumentBuilderFactory\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/javax.xml.parsers.SAXParserFactory\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/javax.xml.xpath.XPathFactory\\E"
|
||||
}, {
|
||||
@ -166,6 +170,8 @@
|
||||
"pattern":"\\Qversion.json\\E"
|
||||
}, {
|
||||
"pattern":"\\Qversion.properties\\E"
|
||||
}, {
|
||||
"pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt72b/nfkc.nrm\\E"
|
||||
}, {
|
||||
"pattern":"java.base:\\Qjdk/internal/icu/impl/data/icudt72b/uprops.icu\\E"
|
||||
}, {
|
||||
@ -597,13 +603,13 @@
|
||||
}]},
|
||||
"bundles":[{
|
||||
"name":"com.oracle.js.parser.resources.Messages",
|
||||
"locales":[""]
|
||||
"locales":["", "und"]
|
||||
}, {
|
||||
"name":"com.sun.org.apache.xerces.internal.impl.msg.XMLMessages",
|
||||
"locales":[""]
|
||||
"locales":["", "und"]
|
||||
}, {
|
||||
"name":"com.sun.org.apache.xml.internal.serializer.XMLEntities",
|
||||
"locales":[""]
|
||||
"locales":["", "und"]
|
||||
}, {
|
||||
"name":"com.sun.org.apache.xml.internal.serializer.utils.SerializerMessages",
|
||||
"classNames":["com.sun.org.apache.xml.internal.serializer.utils.SerializerMessages", "com.sun.org.apache.xml.internal.serializer.utils.SerializerMessages_en"]
|
||||
|
@ -1,12 +0,0 @@
|
||||
import Standard.Base.Data.Numbers
|
||||
import Standard.Base.IO
|
||||
|
||||
fac n =
|
||||
facacc n v = if n <= 1 then v else @Tail_Call facacc n-1 n*v
|
||||
|
||||
res = facacc n 1
|
||||
res
|
||||
|
||||
main number=5 =
|
||||
v = fac number
|
||||
IO.println v
|
@ -183,6 +183,7 @@ public abstract class HostMethodCallNode extends Node {
|
||||
return PolyglotCallType.CONVERT_TO_HASH_MAP;
|
||||
}
|
||||
|
||||
try {
|
||||
String methodName = symbol.getName();
|
||||
if (library.isMemberInvocable(self, methodName)) {
|
||||
return PolyglotCallType.CALL_METHOD;
|
||||
@ -191,6 +192,9 @@ public abstract class HostMethodCallNode extends Node {
|
||||
} else if (library.isInstantiable(self) && methodName.equals(NEW_NAME)) {
|
||||
return PolyglotCallType.INSTANTIATE;
|
||||
}
|
||||
} catch (TypeNotPresentException ex) {
|
||||
// no call, get or instantiate is possible
|
||||
}
|
||||
return PolyglotCallType.NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
@ -98,10 +98,11 @@ public abstract class EnsoProjectNode extends Node {
|
||||
|
||||
private static Atom createProjectDescriptionAtom(EnsoContext ctx, Package<TruffleFile> pkg) {
|
||||
var rootPath = new EnsoFile(pkg.root().normalize());
|
||||
var cfg = ctx.asGuestValue(pkg.getConfig());
|
||||
var namespace = pkg.getConfig().namespace();
|
||||
var name = pkg.getConfig().name();
|
||||
var cons = ctx.getBuiltins().getProjectDescription().getUniqueConstructor();
|
||||
|
||||
return AtomNewInstanceNode.getUncached().newInstance(cons, rootPath, cfg);
|
||||
return AtomNewInstanceNode.getUncached().newInstance(cons, rootPath, namespace, name);
|
||||
}
|
||||
|
||||
private DataflowError unsupportedArgsError(Object moduleActual) {
|
||||
|
@ -13,6 +13,6 @@ public class ProjectDescription extends UniquelyConstructibleBuiltin {
|
||||
|
||||
@Override
|
||||
protected List<String> getConstructorParamNames() {
|
||||
return List.of("prim_root_file", "prim_config");
|
||||
return List.of("prim_root_file", "ns", "n");
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,13 @@ import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||
import com.oracle.truffle.api.TruffleFile;
|
||||
import com.oracle.truffle.api.dsl.Bind;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.interop.ArityException;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
|
||||
import com.oracle.truffle.api.interop.UnknownIdentifierException;
|
||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||
import com.oracle.truffle.api.interop.UnsupportedTypeException;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import com.oracle.truffle.api.library.ExportLibrary;
|
||||
import com.oracle.truffle.api.library.ExportMessage;
|
||||
@ -22,16 +26,22 @@ import java.nio.file.LinkOption;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.Function;
|
||||
import org.enso.interpreter.dsl.Builtin;
|
||||
import org.enso.interpreter.runtime.EnsoContext;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeAtNode;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeHelpers;
|
||||
import org.enso.interpreter.runtime.data.vector.ArrayLikeLengthNode;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.library.dispatch.TypesLibrary;
|
||||
|
||||
@ -54,60 +64,273 @@ public final class EnsoFile implements EnsoObject {
|
||||
|
||||
@Builtin.Method(name = "output_stream_builtin")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@Builtin.ReturningGuestObject
|
||||
@Builtin.Specialize
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public OutputStream outputStream(Object opts, EnsoContext ctx) throws IOException {
|
||||
OpenOption[] openOptions =
|
||||
convertInteropArray(opts, InteropLibrary.getUncached(), ctx, OpenOption[]::new);
|
||||
return this.truffleFile.newOutputStream(openOptions);
|
||||
@TruffleBoundary
|
||||
public EnsoObject outputStream(
|
||||
Object opts,
|
||||
@Cached ArrayLikeLengthNode lengthNode,
|
||||
@Cached ArrayLikeAtNode atNode,
|
||||
EnsoContext ctx)
|
||||
throws IOException {
|
||||
var options = namesToValues(opts, lengthNode, atNode, ctx, StandardOpenOption::valueOf);
|
||||
var os = this.truffleFile.newOutputStream(options.toArray(OpenOption[]::new));
|
||||
return new EnsoOutputStream(os);
|
||||
}
|
||||
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
static final class EnsoOutputStream implements EnsoObject {
|
||||
private static final String[] MEMBERS = new String[] {"write", "flush", "close"};
|
||||
private final OutputStream os;
|
||||
|
||||
EnsoOutputStream(OutputStream os) {
|
||||
this.os = os;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasMembers() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
@ExportMessage
|
||||
boolean isMemberInvocable(String member) {
|
||||
return Arrays.asList(MEMBERS).contains(member);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Object getMembers(boolean includeInternal) throws UnsupportedMessageException {
|
||||
return ArrayLikeHelpers.wrapStrings(MEMBERS);
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
@ExportMessage
|
||||
Object invokeMember(
|
||||
String name,
|
||||
Object[] args,
|
||||
@Cached ArrayLikeLengthNode lengthNode,
|
||||
@Cached ArrayLikeAtNode atNode,
|
||||
@CachedLibrary(limit = "3") InteropLibrary iop)
|
||||
throws ArityException, UnsupportedMessageException, UnknownIdentifierException {
|
||||
try {
|
||||
return switch (name) {
|
||||
case "write" -> {
|
||||
long from;
|
||||
long to;
|
||||
switch (args.length) {
|
||||
case 1 -> {
|
||||
from = 0;
|
||||
to = lengthNode.executeLength(args[0]);
|
||||
}
|
||||
case 3 -> {
|
||||
from = iop.asLong(args[1]);
|
||||
to = from + iop.asLong(args[2]);
|
||||
}
|
||||
default -> {
|
||||
throw ArityException.create(1, 3, args.length);
|
||||
}
|
||||
}
|
||||
for (long i = from; i < to; i++) {
|
||||
var elem = atNode.executeAt(args[0], i);
|
||||
var byt = iop.asInt(elem);
|
||||
os.write(byt);
|
||||
}
|
||||
yield this;
|
||||
}
|
||||
case "flush" -> {
|
||||
os.flush();
|
||||
yield this;
|
||||
}
|
||||
case "close" -> {
|
||||
os.close();
|
||||
yield this;
|
||||
}
|
||||
default -> throw UnknownIdentifierException.create(name);
|
||||
};
|
||||
} catch (IOException ex) {
|
||||
throw raiseIOException(iop, ex);
|
||||
} catch (InvalidArrayIndexException ex) {
|
||||
var ctx = EnsoContext.get(iop);
|
||||
throw ctx.raiseAssertionPanic(iop, name, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EnsoOutputStream";
|
||||
}
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "input_stream_builtin")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@Builtin.Specialize
|
||||
@Builtin.ReturningGuestObject
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public InputStream inputStream(Object opts, EnsoContext ctx) throws IOException {
|
||||
OpenOption[] openOptions =
|
||||
convertInteropArray(opts, InteropLibrary.getUncached(), ctx, OpenOption[]::new);
|
||||
return this.truffleFile.newInputStream(openOptions);
|
||||
@TruffleBoundary
|
||||
public EnsoObject inputStream(
|
||||
Object opts,
|
||||
@Cached ArrayLikeLengthNode lengthNode,
|
||||
@Cached ArrayLikeAtNode atNode,
|
||||
EnsoContext ctx)
|
||||
throws IOException {
|
||||
var options = namesToValues(opts, lengthNode, atNode, ctx, StandardOpenOption::valueOf);
|
||||
var is = this.truffleFile.newInputStream(options.toArray(OpenOption[]::new));
|
||||
return new EnsoInputStream(is);
|
||||
}
|
||||
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
static final class EnsoInputStream implements EnsoObject {
|
||||
private static final String[] MEMBERS =
|
||||
new String[] {
|
||||
"read", "readAllBytes", "readNBytes", "skipNBytes", "markSupported", "available", "close"
|
||||
};
|
||||
private final InputStream is;
|
||||
|
||||
EnsoInputStream(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean hasMembers() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
@ExportMessage
|
||||
boolean isMemberInvocable(String member) {
|
||||
return Arrays.asList(MEMBERS).contains(member);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Object getMembers(boolean includeInternal) throws UnsupportedMessageException {
|
||||
return ArrayLikeHelpers.wrapStrings(MEMBERS);
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
@ExportMessage
|
||||
Object invokeMember(String name, Object[] args, @CachedLibrary(limit = "3") InteropLibrary iop)
|
||||
throws UnknownIdentifierException,
|
||||
UnsupportedMessageException,
|
||||
ArityException,
|
||||
UnsupportedTypeException {
|
||||
try {
|
||||
return switch (name) {
|
||||
case "read" -> {
|
||||
if (args.length == 0) {
|
||||
yield is.read();
|
||||
}
|
||||
long from;
|
||||
long to;
|
||||
switch (args.length) {
|
||||
case 1 -> {
|
||||
from = 0;
|
||||
to = iop.getArraySize(args[0]);
|
||||
}
|
||||
case 3 -> {
|
||||
from = iop.asLong(args[1]);
|
||||
to = from + iop.asLong(args[2]);
|
||||
}
|
||||
default -> throw ArityException.create(0, 3, args.length);
|
||||
}
|
||||
for (var i = from; i < to; i++) {
|
||||
var b = is.read();
|
||||
if (b == -1) {
|
||||
var count = i - from;
|
||||
yield count > 0 ? count : -1;
|
||||
}
|
||||
iop.writeArrayElement(args[0], i, (byte) b);
|
||||
}
|
||||
yield to - from;
|
||||
}
|
||||
case "readAllBytes" -> {
|
||||
if (args.length != 0) {
|
||||
throw ArityException.create(0, 0, args.length);
|
||||
}
|
||||
var arr = is.readAllBytes();
|
||||
var buf = ByteBuffer.wrap(arr);
|
||||
yield ArrayLikeHelpers.wrapBuffer(buf);
|
||||
}
|
||||
case "readNBytes" -> {
|
||||
if (args.length != 1) {
|
||||
throw ArityException.create(1, 1, args.length);
|
||||
}
|
||||
var len = iop.asInt(args[0]);
|
||||
var arr = is.readNBytes(len);
|
||||
var buf = ByteBuffer.wrap(arr);
|
||||
yield ArrayLikeHelpers.wrapBuffer(buf);
|
||||
}
|
||||
case "skipNBytes" -> {
|
||||
if (args.length != 1) {
|
||||
throw ArityException.create(1, 1, args.length);
|
||||
}
|
||||
var len = iop.asInt(args[0]);
|
||||
is.skipNBytes(len);
|
||||
yield this;
|
||||
}
|
||||
case "markSupported" -> {
|
||||
if (args.length != 0) {
|
||||
throw ArityException.create(0, 0, args.length);
|
||||
}
|
||||
yield is.markSupported();
|
||||
}
|
||||
case "available" -> {
|
||||
if (args.length != 0) {
|
||||
throw ArityException.create(0, 0, args.length);
|
||||
}
|
||||
yield is.available();
|
||||
}
|
||||
case "close" -> {
|
||||
if (args.length != 0) {
|
||||
throw ArityException.create(0, 0, args.length);
|
||||
}
|
||||
is.close();
|
||||
yield this;
|
||||
}
|
||||
default -> throw UnknownIdentifierException.create(name);
|
||||
};
|
||||
} catch (IOException ex) {
|
||||
throw raiseIOException(iop, ex);
|
||||
} catch (InvalidArrayIndexException ex) {
|
||||
var ctx = EnsoContext.get(iop);
|
||||
throw ctx.raiseAssertionPanic(iop, name, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EnsoInputStream";
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T[] convertInteropArray(
|
||||
Object arr, InteropLibrary interop, EnsoContext ctx, IntFunction<T[]> hostArrayCtor) {
|
||||
if (!interop.hasArrayElements(arr)) {
|
||||
var vecType = ctx.getBuiltins().vector().getType();
|
||||
var typeError = ctx.getBuiltins().error().makeTypeError(vecType, arr, "opts");
|
||||
throw new PanicException(typeError, interop);
|
||||
}
|
||||
T[] hostArr;
|
||||
@TruffleBoundary
|
||||
private static <T> List<T> namesToValues(
|
||||
Object arr,
|
||||
ArrayLikeLengthNode lengthNode,
|
||||
ArrayLikeAtNode atNode,
|
||||
EnsoContext ctx,
|
||||
Function<String, T> convertor) {
|
||||
var size = (int) lengthNode.executeLength(arr);
|
||||
List<T> hostArr = new ArrayList<>();
|
||||
try {
|
||||
int size = Math.toIntExact(interop.getArraySize(arr));
|
||||
hostArr = hostArrayCtor.apply(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object elem = interop.readArrayElement(arr, i);
|
||||
if (!ctx.isJavaPolyglotObject(elem)) {
|
||||
for (var i = 0; i < size; i++) {
|
||||
var elem = atNode.executeAt(arr, i);
|
||||
if (elem instanceof Text name) {
|
||||
hostArr.add(convertor.apply(name.toString()));
|
||||
} else {
|
||||
var err =
|
||||
ctx.getBuiltins()
|
||||
.error()
|
||||
.makeUnsupportedArgumentsError(
|
||||
new Object[] {arr},
|
||||
"Arguments to opts should be host objects from java.io package");
|
||||
throw new PanicException(err, interop);
|
||||
.makeTypeError(ctx.getBuiltins().text(), elem, "File_Access permissions");
|
||||
throw new PanicException(err, lengthNode);
|
||||
}
|
||||
hostArr[i] = (T) ctx.asJavaPolyglotObject(elem);
|
||||
}
|
||||
} catch (ClassCastException | UnsupportedMessageException | InvalidArrayIndexException e) {
|
||||
throw EnsoContext.get(interop).raiseAssertionPanic(interop, null, e);
|
||||
} catch (ClassCastException | InvalidArrayIndexException e) {
|
||||
throw EnsoContext.get(lengthNode).raiseAssertionPanic(lengthNode, null, e);
|
||||
}
|
||||
return hostArr;
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "read_last_bytes_builtin")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public EnsoObject readLastBytes(long n) throws IOException {
|
||||
try (SeekableByteChannel channel =
|
||||
this.truffleFile.newByteChannel(Set.of(StandardOpenOption.READ))) {
|
||||
@ -136,7 +359,7 @@ public final class EnsoFile implements EnsoObject {
|
||||
|
||||
@Builtin.Method(name = "creation_time_builtin")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public EnsoDateTime getCreationTime() throws IOException {
|
||||
return new EnsoDateTime(
|
||||
ZonedDateTime.ofInstant(truffleFile.getCreationTime().toInstant(), ZoneOffset.UTC));
|
||||
@ -144,7 +367,7 @@ public final class EnsoFile implements EnsoObject {
|
||||
|
||||
@Builtin.Method(name = "last_modified_time_builtin")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public EnsoDateTime getLastModifiedTime() throws IOException {
|
||||
return new EnsoDateTime(
|
||||
ZonedDateTime.ofInstant(truffleFile.getLastModifiedTime().toInstant(), ZoneOffset.UTC));
|
||||
@ -152,14 +375,13 @@ public final class EnsoFile implements EnsoObject {
|
||||
|
||||
@Builtin.Method(name = "posix_permissions_builtin")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@Builtin.ReturningGuestObject
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public Set<PosixFilePermission> getPosixPermissions() throws IOException {
|
||||
return truffleFile.getPosixPermissions();
|
||||
@TruffleBoundary
|
||||
public Text getPosixPermissions() throws IOException {
|
||||
return Text.create(PosixFilePermissions.toString(truffleFile.getPosixPermissions()));
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "parent")
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public EnsoObject getParent() {
|
||||
// Normalization is needed to correctly handle paths containing `..` and `.`.
|
||||
var parentOrNull = this.normalize().truffleFile.getParent();
|
||||
@ -179,32 +401,32 @@ public final class EnsoFile implements EnsoObject {
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "absolute")
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public EnsoFile getAbsoluteFile() {
|
||||
return new EnsoFile(this.truffleFile.getAbsoluteFile());
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "path")
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public Text getPath() {
|
||||
return Text.create(this.truffleFile.getPath());
|
||||
}
|
||||
|
||||
@Builtin.Method
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public boolean isAbsolute() {
|
||||
return this.truffleFile.isAbsolute();
|
||||
}
|
||||
|
||||
@Builtin.Method
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public boolean isDirectory() {
|
||||
return this.truffleFile.isDirectory();
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "create_directory_builtin")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public void createDirectories() throws IOException {
|
||||
try {
|
||||
this.truffleFile.createDirectories();
|
||||
@ -282,32 +504,32 @@ public final class EnsoFile implements EnsoObject {
|
||||
|
||||
@Builtin.Method(name = "list_immediate_children_array")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public EnsoObject list() throws IOException {
|
||||
return ArrayLikeHelpers.wrapEnsoObjects(
|
||||
this.truffleFile.list().stream().map(EnsoFile::new).toArray(EnsoFile[]::new));
|
||||
}
|
||||
|
||||
@Builtin.Method
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public EnsoFile relativize(EnsoFile other) {
|
||||
return new EnsoFile(this.truffleFile.relativize(other.truffleFile));
|
||||
}
|
||||
|
||||
@Builtin.Method
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public boolean isRegularFile() {
|
||||
return this.truffleFile.isRegularFile();
|
||||
}
|
||||
|
||||
@Builtin.Method
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public boolean isWritable() {
|
||||
return this.truffleFile.isWritable();
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "name")
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public Text getName() {
|
||||
var name = this.normalize().truffleFile.getName();
|
||||
return Text.create(name == null ? "/" : name);
|
||||
@ -315,7 +537,7 @@ public final class EnsoFile implements EnsoObject {
|
||||
|
||||
@Builtin.Method(name = "size_builtin")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public long getSize() throws IOException {
|
||||
if (this.truffleFile.isDirectory()) {
|
||||
throw new IOException("size can only be called on files.");
|
||||
@ -334,7 +556,7 @@ public final class EnsoFile implements EnsoObject {
|
||||
}
|
||||
|
||||
@Builtin.Method
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public EnsoFile normalize() {
|
||||
TruffleFile simplyNormalized = truffleFile.normalize();
|
||||
String name = simplyNormalized.getName();
|
||||
@ -347,7 +569,7 @@ public final class EnsoFile implements EnsoObject {
|
||||
|
||||
@Builtin.Method(name = "delete_builtin")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public void delete(boolean recursive) throws IOException {
|
||||
if (recursive && truffleFile.isDirectory(LinkOption.NOFOLLOW_LINKS)) {
|
||||
deleteRecursively(truffleFile);
|
||||
@ -368,25 +590,35 @@ public final class EnsoFile implements EnsoObject {
|
||||
@Builtin.Method(name = "copy_builtin", description = "Copy this file to a target destination")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@Builtin.Specialize
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public void copy(EnsoFile target, Object options, EnsoContext ctx) throws IOException {
|
||||
CopyOption[] copyOptions =
|
||||
convertInteropArray(options, InteropLibrary.getUncached(), ctx, CopyOption[]::new);
|
||||
truffleFile.copy(target.truffleFile, copyOptions);
|
||||
@TruffleBoundary
|
||||
public void copy(
|
||||
EnsoFile target,
|
||||
Object options,
|
||||
@Cached ArrayLikeLengthNode lengthNode,
|
||||
@Cached ArrayLikeAtNode atNode,
|
||||
EnsoContext ctx)
|
||||
throws IOException {
|
||||
var copyOptions = namesToValues(options, lengthNode, atNode, ctx, StandardCopyOption::valueOf);
|
||||
truffleFile.copy(target.truffleFile, copyOptions.toArray(CopyOption[]::new));
|
||||
}
|
||||
|
||||
@Builtin.Method(name = "move_builtin", description = "Move this file to a target destination")
|
||||
@Builtin.WrapException(from = IOException.class)
|
||||
@Builtin.Specialize
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public void move(EnsoFile target, Object options, EnsoContext ctx) throws IOException {
|
||||
CopyOption[] copyOptions =
|
||||
convertInteropArray(options, InteropLibrary.getUncached(), ctx, CopyOption[]::new);
|
||||
truffleFile.move(target.truffleFile, copyOptions);
|
||||
@TruffleBoundary
|
||||
public void move(
|
||||
EnsoFile target,
|
||||
Object options,
|
||||
@Cached ArrayLikeLengthNode lengthNode,
|
||||
@Cached ArrayLikeAtNode atNode,
|
||||
EnsoContext ctx)
|
||||
throws IOException {
|
||||
var copyOptions = namesToValues(options, lengthNode, atNode, ctx, StandardCopyOption::valueOf);
|
||||
truffleFile.move(target.truffleFile, copyOptions.toArray(CopyOption[]::new));
|
||||
}
|
||||
|
||||
@Builtin.Method
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public boolean startsWith(EnsoFile parent) {
|
||||
return truffleFile.startsWith(parent.truffleFile);
|
||||
}
|
||||
@ -397,7 +629,7 @@ public final class EnsoFile implements EnsoObject {
|
||||
"Takes the text representation of a path and returns a TruffleFile corresponding to it.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public static EnsoFile fromString(EnsoContext context, String path) {
|
||||
TruffleFile file = context.getPublicTruffleFile(path);
|
||||
return new EnsoFile(file);
|
||||
@ -408,7 +640,7 @@ public final class EnsoFile implements EnsoObject {
|
||||
description = "A file corresponding to the current working directory.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public static EnsoFile currentDirectory(EnsoContext context) {
|
||||
TruffleFile file = context.getCurrentWorkingDirectory();
|
||||
return new EnsoFile(file);
|
||||
@ -419,13 +651,13 @@ public final class EnsoFile implements EnsoObject {
|
||||
description = "Gets the user's system-defined home directory.",
|
||||
autoRegister = false)
|
||||
@Builtin.Specialize
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public static EnsoFile userHome(EnsoContext context) {
|
||||
return fromString(context, System.getProperty("user.home"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
@TruffleBoundary
|
||||
public String toString() {
|
||||
return "(File " + truffleFile.getPath() + ")";
|
||||
}
|
||||
@ -449,4 +681,10 @@ public final class EnsoFile implements EnsoObject {
|
||||
Type getType(@Bind("$node") Node node) {
|
||||
return EnsoContext.get(node).getBuiltins().file();
|
||||
}
|
||||
|
||||
static RuntimeException raiseIOException(Node where, IOException ex) {
|
||||
var ctx = EnsoContext.get(where);
|
||||
var guestEx = ctx.asGuestValue(ex);
|
||||
throw new PanicException(guestEx, where);
|
||||
}
|
||||
}
|
||||
|
@ -111,8 +111,12 @@ public final class PanicException extends AbstractTruffleException implements En
|
||||
}
|
||||
|
||||
@NeverDefault
|
||||
static UnresolvedSymbol toDisplayText(IndirectInvokeMethodNode payloads) {
|
||||
static UnresolvedSymbol toDisplayText(IndirectInvokeMethodNode payloads)
|
||||
throws UnsupportedMessageException {
|
||||
var ctx = EnsoContext.get(payloads);
|
||||
if (ctx == null) {
|
||||
throw UnsupportedMessageException.create();
|
||||
}
|
||||
var scope = ctx.getBuiltins().panic().getDefinitionScope();
|
||||
return UnresolvedSymbol.build("to_display_text", scope);
|
||||
}
|
||||
|
@ -24,26 +24,31 @@ public final class Parser implements AutoCloseable {
|
||||
name = "libenso_parser.so";
|
||||
}
|
||||
|
||||
File parser = null;
|
||||
try {
|
||||
var whereAmI = Parser.class.getProtectionDomain().getCodeSource().getLocation();
|
||||
var d = new File(whereAmI.toURI()).getParentFile();
|
||||
File root;
|
||||
try {
|
||||
root = new File(whereAmI.toURI()).getParentFile();
|
||||
} catch (URISyntaxException ex) {
|
||||
root = new File(".").getAbsoluteFile();
|
||||
}
|
||||
try {
|
||||
var d = root;
|
||||
File path = null;
|
||||
while (d != null) {
|
||||
path = new File(d, name);
|
||||
if (path.exists()) break;
|
||||
d = d.getParentFile();
|
||||
}
|
||||
if (d == null) {
|
||||
throw new LinkageError(
|
||||
"Cannot find parser in " + new File(whereAmI.toURI()).getParentFile());
|
||||
if (d == null || path == null) {
|
||||
throw new LinkageError("Cannot find parser in " + root);
|
||||
}
|
||||
parser = path;
|
||||
System.load(parser.getAbsolutePath());
|
||||
} catch (IllegalArgumentException | URISyntaxException | LinkageError e) {
|
||||
File root = new File(".").getAbsoluteFile();
|
||||
System.load(path.getAbsolutePath());
|
||||
} catch (NullPointerException | IllegalArgumentException | LinkageError e) {
|
||||
if (!searchFromDirToTop(e, root, "target", "rust", "debug", name)) {
|
||||
throw new IllegalStateException("Cannot load parser from " + parser, e);
|
||||
if (!searchFromDirToTop(
|
||||
e, new File(".").getAbsoluteFile(), "target", "rust", "debug", name)) {
|
||||
throw new IllegalStateException("Cannot load parser from " + root, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -289,48 +289,6 @@ public @interface Builtin {
|
||||
WrapException[] value() default {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation approving implicit {@link
|
||||
* com.oracle.truffle.api.TruffleLanguage#asGuestValue(Object)} translation done on the return
|
||||
* object. The conversion is generated automatically, depending on the type of the value.
|
||||
*
|
||||
* <p>Note that while explicit translations to interop value are discouraged, we still want to
|
||||
* occasionally support it to easy builtins-writing process. The presence of the {@link
|
||||
* ReturningGuestObject} only ensures that it is intentional.
|
||||
*
|
||||
* <p>Consider a method returning an {@link java.io.OutputStream} which is not an interop value,
|
||||
* for the sake of the example:
|
||||
*
|
||||
* <pre>
|
||||
* class Foo {
|
||||
* {@link Builtin.Method @Builtin.Method}
|
||||
* {@link Builtin.ReturningGuestObject @Builtin.ReturningGuestObject}
|
||||
* java.lang.OutputStream foo(Object item) {
|
||||
* return // ...
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* The processor will detect the return type of method {@code foo} and perform an automatic
|
||||
* conversion:
|
||||
*
|
||||
* <pre>
|
||||
* {@link BuiltinMethod @BuiltinMethod}(type = "Foo", name = "create")
|
||||
* public class CreateFooNode extends Node {
|
||||
* java.lang.Object execute(Foo self, Object item) {
|
||||
* return context
|
||||
* .asGuestValue(self.foo(item));
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Without converting the object to the guest language value, it would crash during runtime.
|
||||
* Without the presence of the annotation, the processor would detect the potential value
|
||||
* requiring {@link com.oracle.truffle.api.TruffleLanguage#asGuestValue(Object)} translation but
|
||||
* stop and report the error since it didn't seem to be intended by the user.
|
||||
*/
|
||||
@interface ReturningGuestObject {}
|
||||
|
||||
/**
|
||||
* A Method marked with {@link Builtin.Specialize} annotation will generate specializations for
|
||||
* overloaded and non-overloaded methods. The annotation requires presence of {@link
|
||||
|
@ -180,10 +180,6 @@ public class BuiltinsProcessor extends AbstractProcessor {
|
||||
|
||||
OK:
|
||||
if (!TypeWithKind.isValidGuestType(processingEnv, method.getReturnType())) {
|
||||
if (method.getAnnotation(Builtin.ReturningGuestObject.class) != null) {
|
||||
// guest objects can be of any type
|
||||
break OK;
|
||||
}
|
||||
if (method.getAnnotation(SuppressWarnings.class) instanceof SuppressWarnings sw
|
||||
&& Arrays.asList(sw.value()).contains("generic-enso-builtin-type")) {
|
||||
// assume the case was review
|
||||
|
@ -105,8 +105,7 @@ public abstract class MethodGenerator {
|
||||
Kind.ERROR,
|
||||
"Automatic conversion of value of type "
|
||||
+ tpe.baseType()
|
||||
+ " to guest value requires explicit '@Builtin.ReturningGuestObject'"
|
||||
+ " annotation");
|
||||
+ " is no longer supported.");
|
||||
}
|
||||
return "Object";
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import java.util.List;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.tools.JavaFileObject;
|
||||
import org.enso.interpreter.dsl.Builtin;
|
||||
|
||||
public abstract class MethodNodeClassGenerator {
|
||||
ClassName builtinNode;
|
||||
@ -29,7 +28,7 @@ public abstract class MethodNodeClassGenerator {
|
||||
* @return true if the annotation exists, false otherwise
|
||||
*/
|
||||
protected boolean needsGuestValueConversion(Element origin) {
|
||||
return origin.getAnnotation(Builtin.ReturningGuestObject.class) != null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void generate(
|
||||
|
@ -41,9 +41,7 @@ public final class NoSpecializationClassGenerator extends MethodNodeClassGenerat
|
||||
processingEnvironment
|
||||
.getMessager()
|
||||
.printMessage(
|
||||
Kind.ERROR,
|
||||
"Value is already TruffleObject, don't use @Builtin.ReturningGuestObject",
|
||||
origin);
|
||||
Kind.ERROR, "Value is already TruffleObject, don't need any conversions", origin);
|
||||
}
|
||||
return new ExecuteMethodImplGenerator(
|
||||
processingEnvironment, origin, asGuestValue, varArgExpansion);
|
||||
|
@ -38,14 +38,12 @@ public final class SpecializedMethodsGenerator extends MethodGenerator {
|
||||
elements,
|
||||
first.getModifiers().contains(Modifier.STATIC),
|
||||
first.getKind() == ElementKind.CONSTRUCTOR,
|
||||
first.getAnnotation(Builtin.ReturningGuestObject.class) != null,
|
||||
false,
|
||||
TypeWithKind.createFromTpe(first.getReturnType().toString()));
|
||||
|
||||
// Make sure all methods were defined the same way, except for paramters' types
|
||||
assert (allEqual(elements.stream().map(e -> e.getModifiers().contains(Modifier.STATIC))));
|
||||
assert (allEqual(elements.stream().map(e -> e.getKind() == ElementKind.CONSTRUCTOR)));
|
||||
assert (allEqual(
|
||||
elements.stream().map(e -> e.getAnnotation(Builtin.ReturningGuestObject.class) != null)));
|
||||
assert (allEqual(
|
||||
elements.stream().map(e -> TypeWithKind.createFromTpe(e.getReturnType().toString()))));
|
||||
}
|
||||
|
@ -2,9 +2,84 @@ package org.enso.base;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Stream_Utils {
|
||||
public final class Stream_Utils {
|
||||
private Stream_Utils() {}
|
||||
|
||||
/**
|
||||
* Conversion interface. Any Enso/Truffle object with invocable {@read} member that takes three
|
||||
* arguments is eligible for being treated as host Java {@link InputStream}. There are two
|
||||
* overloaded {@link #asInputStream conversion methods}. The <em>hosted Java interop</em> system
|
||||
* of Truffle will pick the more suitable one depending on the type of argument.
|
||||
*
|
||||
* @see #asInputStream
|
||||
*/
|
||||
public static interface InputStreamLike {
|
||||
public int read(byte[] arr, int off, int len) throws IOException;
|
||||
|
||||
public default int available() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* No conversion conversion. When the argument is already {@link InputStream} there is no need for
|
||||
* doing any further conversions.
|
||||
*
|
||||
* @param is
|
||||
* @return the {@code is} itself
|
||||
*/
|
||||
public static InputStream asInputStream(InputStream is) {
|
||||
return is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversion to {@link InputStream}. When the argument <em>looks like</em> an input stream, let's
|
||||
* wrap it.
|
||||
*
|
||||
* @param inputStreamLike any guest object with {@code read} method
|
||||
* @return proper
|
||||
*/
|
||||
public static InputStream asInputStream(InputStreamLike inputStreamLike) {
|
||||
return new GuestInputStream(inputStreamLike);
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversion interface. Any Enso/Truffle object with invocable {@write} member that takes three
|
||||
* arguments is eligible for being treated as host Java {@link OutputStream}. There are two
|
||||
* overloaded {@link #asOutputStream conversion methods}. The <em>hosted Java interop</em> system
|
||||
* of Truffle will pick the more suitable one depending on the type of argument.
|
||||
*
|
||||
* @see #asOutputStream
|
||||
*/
|
||||
public static interface OutputStreamLike {
|
||||
public void write(byte[] arr, int off, int len) throws IOException;
|
||||
}
|
||||
|
||||
/**
|
||||
* No conversion conversion. When the argument is already {@link OutputStream} there is no need
|
||||
* for doing any further conversions.
|
||||
*
|
||||
* @param os
|
||||
* @return the {@code is} itself
|
||||
*/
|
||||
public static OutputStream asOutputStream(OutputStream os) {
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversion to {@link OutputStream}. When the argument <em>looks like</em> an output stream,
|
||||
* let's wrap it.
|
||||
*
|
||||
* @param outputStreamLike any guest object with {@code write} method
|
||||
* @return proper
|
||||
*/
|
||||
public static OutputStream asOutputStream(OutputStreamLike outputStreamLike) {
|
||||
return new GuestOutputStream(outputStreamLike);
|
||||
}
|
||||
|
||||
public static byte[] peek(InputStream stream, int n) throws IOException {
|
||||
assert n >= 0;
|
||||
assert stream.markSupported();
|
||||
@ -25,4 +100,64 @@ public class Stream_Utils {
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private static class GuestInputStream extends InputStream {
|
||||
private final InputStreamLike inputStreamLike;
|
||||
|
||||
private GuestInputStream(InputStreamLike inputStreamLike) {
|
||||
this.inputStreamLike = inputStreamLike;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
return inputStreamLike.read(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
byte[] arr = new byte[1];
|
||||
int read = read(arr, 0, 1);
|
||||
if (read == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (read != 1) {
|
||||
throw new IOException();
|
||||
}
|
||||
return arr[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
try {
|
||||
return inputStreamLike.available();
|
||||
} catch (Error | Exception e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class GuestOutputStream extends OutputStream {
|
||||
|
||||
private final OutputStreamLike outputStreamLike;
|
||||
|
||||
private GuestOutputStream(OutputStreamLike os) {
|
||||
this.outputStreamLike = os;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
byte[] arr = new byte[] {(byte) b};
|
||||
write(arr, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
outputStreamLike.write(b, off, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,14 @@
|
||||
package org.enso.base;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.w3c.dom.DOMConfiguration;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
|
||||
@ -10,6 +16,7 @@ import org.w3c.dom.ls.DOMImplementationLS;
|
||||
import org.w3c.dom.ls.LSOutput;
|
||||
import org.w3c.dom.ls.LSSerializer;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
@ -62,7 +69,25 @@ public class XML_Utils {
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
public static void setCustomErrorHandler(DocumentBuilder documentBuilder) {
|
||||
public static Document parseStream(InputStream is)
|
||||
throws ParserConfigurationException, SAXException, IOException {
|
||||
return doParse(new InputSource(is));
|
||||
}
|
||||
|
||||
public static Document parseString(String text)
|
||||
throws ParserConfigurationException, SAXException, IOException {
|
||||
return doParse(new InputSource(new StringReader(text)));
|
||||
}
|
||||
|
||||
private static Document doParse(InputSource is)
|
||||
throws ParserConfigurationException, SAXException, IOException {
|
||||
var factory = DocumentBuilderFactory.newInstance();
|
||||
var builder = factory.newDocumentBuilder();
|
||||
configureErrorHandler(builder);
|
||||
return builder.parse(is);
|
||||
}
|
||||
|
||||
private static void configureErrorHandler(DocumentBuilder documentBuilder) {
|
||||
documentBuilder.setErrorHandler(
|
||||
new ErrorHandler() {
|
||||
@Override
|
||||
|
@ -0,0 +1,23 @@
|
||||
package org.enso.base.file_system;
|
||||
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
|
||||
public final class File_Utils {
|
||||
private File_Utils() {}
|
||||
|
||||
public static Path toPath(String path) {
|
||||
return Path.of(path);
|
||||
}
|
||||
|
||||
public static PathMatcher matchPath(String filter) {
|
||||
var fs = FileSystems.getDefault();
|
||||
var matcher = fs.getPathMatcher(filter);
|
||||
return matcher;
|
||||
}
|
||||
|
||||
public static boolean matches(PathMatcher matcher, String pathStr) {
|
||||
return matcher.matches(Path.of(pathStr));
|
||||
}
|
||||
}
|
@ -5,8 +5,8 @@ import Standard.Base.Errors.No_Such_Key.No_Such_Key
|
||||
from Standard.Test import all
|
||||
|
||||
|
||||
polyglot java import java.nio.file.Path as JavaPath
|
||||
polyglot java import java.util.Map as JavaMap
|
||||
polyglot java import org.enso.base.file_system.File_Utils
|
||||
|
||||
## Type that violates reflexivity
|
||||
type My_Nan
|
||||
@ -278,11 +278,11 @@ add_specs suite_builder =
|
||||
map.get (js_str "A") . should_equal 42
|
||||
|
||||
group_builder.specify "should support host objects as keys" <|
|
||||
# JavaPath has proper implementation of hashCode
|
||||
map = Map.singleton (JavaPath.of "/home/user/file.txt") 42
|
||||
# java.nio.path.Path has proper implementation of hashCode
|
||||
map = Map.singleton (File_Utils.toPath "/home/user/file.txt") 42
|
||||
map.get "X" . should_equal Nothing
|
||||
map.get "A" . should_equal Nothing
|
||||
map.get (JavaPath.of "/home/user/file.txt") . should_equal 42
|
||||
map.get (File_Utils.toPath "/home/user/file.txt") . should_equal 42
|
||||
|
||||
group_builder.specify "should support Python objects as keys" pending=pending_python_missing <|
|
||||
py_obj = py_wrapper 42
|
||||
@ -558,7 +558,11 @@ add_common_specs suite_builder prefix:Text (pending : (Text | Nothing)) (empty_m
|
||||
empty_map.insert Nothing 1 . insert Nothing 2 . get Nothing . should_equal 2
|
||||
empty_map.insert Nothing 1 . should_equal (empty_map.insert Nothing 1)
|
||||
empty_map.insert Nothing 1 . insert Nothing 2 . at Nothing . should_equal 2
|
||||
|
||||
group_builder.specify "should handle JavaScript null as keys" <|
|
||||
empty_map.insert js_null 1 . at Nothing . should_equal 1
|
||||
|
||||
group_builder.specify "should handle Python None as keys" pending=pending_python_missing <|
|
||||
empty_map.insert py_none 1 . at Nothing . should_equal 1
|
||||
|
||||
group_builder.specify "should define a well-defined text conversion" <|
|
||||
|
@ -85,6 +85,7 @@ import project.Runtime.Stack_Traces_Spec
|
||||
import project.System.Environment_Spec
|
||||
import project.System.File_Spec
|
||||
import project.System.File_Read_Spec
|
||||
import project.System.Input_Stream_Spec
|
||||
import project.System.Process_Spec
|
||||
import project.System.Reporting_Stream_Decoder_Spec
|
||||
import project.System.Reporting_Stream_Encoder_Spec
|
||||
@ -112,6 +113,7 @@ main filter=Nothing =
|
||||
File_Spec.add_specs suite_builder
|
||||
Temporary_File_Spec.add_specs suite_builder
|
||||
File_Read_Spec.add_specs suite_builder
|
||||
Input_Stream_Spec.add_specs suite_builder
|
||||
Reporting_Stream_Decoder_Spec.add_specs suite_builder
|
||||
Reporting_Stream_Encoder_Spec.add_specs suite_builder
|
||||
Http_Header_Spec.add_specs suite_builder
|
||||
|
@ -5,8 +5,8 @@ from Standard.Test import all
|
||||
|
||||
|
||||
polyglot java import java.math.BigInteger as Java_Big_Integer
|
||||
polyglot java import java.nio.file.Path as Java_Path
|
||||
polyglot java import java.util.Random as Java_Random
|
||||
polyglot java import org.enso.base.file_system.File_Utils
|
||||
polyglot java import org.enso.base_test_helpers.IntHolder
|
||||
polyglot java import org.enso.base_test_helpers.IntHolderEquals
|
||||
|
||||
@ -180,8 +180,8 @@ add_specs suite_builder =
|
||||
((CustomEqType.C1 0) == (CustomEqType.C2 7 3)).should_be_false
|
||||
|
||||
group_builder.specify "should dispatch to equals on host values" <|
|
||||
path1 = Java_Path.of "home" "user" . resolve "file.txt"
|
||||
path2 = Java_Path.of "home" "user" "file.txt"
|
||||
path1 = File_Utils.toPath "home" . resolve "user" . resolve "file.txt"
|
||||
path2 = File_Utils.toPath "home" . resolve "user" . resolve "file.txt"
|
||||
(path1 == path2).should_be_true
|
||||
path3 = path1.resolve "subfile.txt"
|
||||
(path3 == path2).should_be_false
|
||||
|
@ -6,12 +6,33 @@ import Standard.Base.System.Input_Stream.Input_Stream
|
||||
from Standard.Test import all
|
||||
|
||||
polyglot java import org.enso.base_test_helpers.RangeStream
|
||||
polyglot java import org.enso.base.Stream_Utils
|
||||
|
||||
main filter=Nothing =
|
||||
suite = Test.build suite_builder->
|
||||
add_specs suite_builder
|
||||
suite.run_with_filter filter
|
||||
|
||||
|
||||
foreign js is_like data available = """
|
||||
let at = 0
|
||||
let is = {
|
||||
read : function(arr, off, len) {
|
||||
let cnt = 0;
|
||||
while (len-- > 0) {
|
||||
arr[off++] = data[at++];
|
||||
cnt++;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
}
|
||||
if (available) {
|
||||
is.available = function() {
|
||||
return data.length - at;
|
||||
};
|
||||
}
|
||||
return is;
|
||||
|
||||
add_specs suite_builder = suite_builder.group "Input Stream" group_builder->
|
||||
group_builder.specify "should be peekable if backed by memory" <|
|
||||
Managed_Resource.bracket (Input_Stream.from_bytes [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) (.close) stream->
|
||||
@ -61,3 +82,33 @@ add_specs suite_builder = suite_builder.group "Input Stream" group_builder->
|
||||
promoted_stream.peek_bytes 10 . should_equal [100, 101, 102, 103, 104]
|
||||
# The read still succeeds - ensuring there isn't some early EOF
|
||||
promoted_stream.read_n_bytes 10 . should_equal [100, 101, 102, 103, 104]
|
||||
|
||||
group_builder.specify "read without available" <|
|
||||
stream_like = is_like [20, 5, 1, 10] False
|
||||
is = Stream_Utils.asInputStream stream_like
|
||||
is.available . should_equal 0
|
||||
|
||||
is.read . should_equal 20
|
||||
is.read . should_equal 5
|
||||
|
||||
is.available . should_equal 0
|
||||
|
||||
is.read . should_equal 1
|
||||
is.read . should_equal 10
|
||||
|
||||
is.available . should_equal 0
|
||||
|
||||
group_builder.specify "read with available" <|
|
||||
stream_like = is_like [20, 6, 8, 23] True
|
||||
is = Stream_Utils.asInputStream stream_like
|
||||
is.available . should_equal 4
|
||||
|
||||
is.read . should_equal 20
|
||||
is.read . should_equal 6
|
||||
|
||||
is.available . should_equal 2
|
||||
|
||||
is.read . should_equal 8
|
||||
is.read . should_equal 23
|
||||
|
||||
is.available . should_equal 0
|
||||
|
Loading…
Reference in New Issue
Block a user