mirror of
https://github.com/enso-org/enso.git
synced 2024-12-22 18:38:11 +03:00
Enso's Text Type (#1166)
This commit is contained in:
parent
bd9689a2b4
commit
a1748c3978
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@ -188,6 +188,12 @@ jobs:
|
||||
run: |
|
||||
cp enso.exe ${{ env.LAUNCHER_DIST_DIR }}/bin/
|
||||
|
||||
- name: Build Base Java Extensions
|
||||
shell: bash
|
||||
run: |
|
||||
cd std-bits
|
||||
mvn package
|
||||
|
||||
# The way artifacts are uploaded currently does not preserve the
|
||||
# executable bits for Unix. However putting artifacts into a ZIP would
|
||||
# create a twice nested ZIP file. For now, users downloading artifacts
|
||||
|
6
.github/workflows/scala.yml
vendored
6
.github/workflows/scala.yml
vendored
@ -320,6 +320,12 @@ jobs:
|
||||
run: |
|
||||
cp enso.exe ${{ env.LAUNCHER_DIST_DIR }}/bin/
|
||||
|
||||
- name: Build Base Java Extensions
|
||||
shell: bash
|
||||
run: |
|
||||
cd std-bits
|
||||
mvn package
|
||||
|
||||
# The way artifacts are uploaded currently does not preserve the
|
||||
# executable bits for Unix. However putting artifacts into a ZIP would
|
||||
# create a twice nested ZIP file. For now, users downloading artifacts
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -13,6 +13,7 @@ graal_dumps/
|
||||
target/
|
||||
*.class
|
||||
*.log
|
||||
.java-version
|
||||
|
||||
##########
|
||||
## Rust ##
|
||||
@ -62,6 +63,7 @@ package-lock.json
|
||||
*.swp
|
||||
.projections.json
|
||||
.nvmrc
|
||||
*.iml
|
||||
|
||||
############################
|
||||
## Rendered Documentation ##
|
||||
|
18
build.sbt
18
build.sbt
@ -4,6 +4,7 @@ import com.typesafe.sbt.SbtLicenseReport.autoImportImpl.{
|
||||
licenseReportNotes,
|
||||
licenseReportStyleRules
|
||||
}
|
||||
import scala.sys.process._
|
||||
import org.enso.build.BenchTasks._
|
||||
import org.enso.build.WithDebugCommand
|
||||
import sbt.Keys.{libraryDependencies, scalacOptions}
|
||||
@ -893,6 +894,21 @@ lazy val runtime = (project in file("engine/runtime"))
|
||||
.dependsOn(Def.task { (Compile / sourceManaged).value.mkdirs })
|
||||
.value
|
||||
)
|
||||
.settings(
|
||||
(Test / compile) := (Test / compile)
|
||||
.dependsOn(Def.task {
|
||||
val cmd = Seq("mvn", "package", "-f", "std-bits")
|
||||
val exitCode = if (sys.props("os.name").toLowerCase().contains("win")) {
|
||||
(Seq("cmd", "/c") ++ cmd).!
|
||||
} else {
|
||||
cmd.!
|
||||
}
|
||||
if (exitCode != 0) {
|
||||
throw new RuntimeException("std-bits build failed.")
|
||||
}
|
||||
})
|
||||
.value
|
||||
)
|
||||
.settings(
|
||||
logBuffered := false,
|
||||
bench := (test in Benchmark).tag(Exclusive).value,
|
||||
@ -994,7 +1010,7 @@ lazy val runner = project
|
||||
"commons-cli" % "commons-cli" % commonsCliVersion,
|
||||
"com.monovore" %% "decline" % declineVersion,
|
||||
"org.jline" % "jline" % jlineVersion,
|
||||
"org.typelevel" %% "cats-core" % catsVersion,
|
||||
"org.typelevel" %% "cats-core" % catsVersion
|
||||
),
|
||||
connectInput in run := true
|
||||
)
|
||||
|
@ -1,13 +1,15 @@
|
||||
import Base.List
|
||||
import Base.Vector
|
||||
import Base.Number.Extensions
|
||||
from Builtins import Unit, Number, Integer
|
||||
import Base.Text.Extensions
|
||||
from Builtins import Unit, Number, Integer, Any, True, False
|
||||
|
||||
from Builtins export all
|
||||
|
||||
from Base.List export Nil, Cons
|
||||
from Base.Vector export Vector
|
||||
from Base.Number.Extensions export all hiding Math
|
||||
from Base.Text.Extensions export Text
|
||||
|
||||
## Represents a right-exclusive range of integer values.
|
||||
type Range
|
||||
@ -44,9 +46,22 @@ type Range
|
||||
res = it initial this.start this.end
|
||||
res
|
||||
|
||||
## Checks whether `predicate` is satisfied for every number in this range.
|
||||
every predicate =
|
||||
it start end = if start==end then True else
|
||||
r = predicate start
|
||||
if r then (it start+1 end) else False
|
||||
res = it this.start this.end
|
||||
res
|
||||
|
||||
type Math
|
||||
|
||||
## The mathematical constant pi, equal to the ratio of a circle circumference
|
||||
to its diameter.
|
||||
Math.pi : Decimal
|
||||
Math.pi = 3.141592653589793
|
||||
|
||||
## Equality definition for types defining `==`.
|
||||
|
||||
TODO remove when operators can be defined in-language.
|
||||
Any.equals that = this == that
|
||||
|
@ -82,4 +82,4 @@ Integer.upto n = Range this n
|
||||
|
||||
Returns `True` when `this` and `that` are at most `epsilon` apart.
|
||||
Number.equals : Number -> Number -> Boolean
|
||||
Number.equals that epsilon = (this - that).abs <= epsilon
|
||||
Number.equals that epsilon=0.0 = (this - that).abs <= epsilon
|
||||
|
@ -1,4 +1,5 @@
|
||||
from Builtins import System
|
||||
from Base import all
|
||||
|
||||
type Os
|
||||
type Linux
|
||||
@ -10,7 +11,7 @@ type Os
|
||||
Create an Os object from text.
|
||||
from_text: Text -> Os
|
||||
from_text os =
|
||||
if os == "linux" then Linux else if os == "macos" then MacOS else if os == "windows" then Windows else Unknown
|
||||
if os.equals "linux" then Linux else if os.equals "macos" then MacOS else if os.equals "windows" then Windows else Unknown
|
||||
|
||||
## Return the type of operating system.
|
||||
|
||||
|
@ -22,16 +22,18 @@ Suite.is_fail = this.specs.any is_fail
|
||||
type Assertion
|
||||
type Success
|
||||
type Failure message
|
||||
type Pending
|
||||
|
||||
is_fail = case this of
|
||||
Success -> False
|
||||
Failure _ -> True
|
||||
Pending -> False
|
||||
|
||||
## Fail a test with the given message.
|
||||
fail message = Panic.throw (Failure message)
|
||||
|
||||
## Asserts that `this` value is equal to the expected value.
|
||||
Any.should_equal that = case this == that of
|
||||
Any.should_equal that = case this.equals that of
|
||||
True -> Success
|
||||
False ->
|
||||
msg = this.to_text + " did not equal " + that.to_text + "."
|
||||
@ -64,6 +66,8 @@ Spec.print_report =
|
||||
Failure msg ->
|
||||
IO.print_err (" - [FAILED] " + behavior.name)
|
||||
IO.print_err (" Reason: " + msg)
|
||||
Pending ->
|
||||
IO.print_err (" - [PENDING] " + behavior.name)
|
||||
|
||||
## Creates a new test group, desribing properties of the object
|
||||
described by `this`.
|
||||
@ -93,16 +97,21 @@ Text.describe ~behaviors =
|
||||
2+3 . should_equal 5
|
||||
it "should define multiplication" <|
|
||||
2*3 . should_equal 6
|
||||
Text.it ~behavior =
|
||||
Text.it ~behavior pending=False =
|
||||
result = if pending then Pending else here.run_spec behavior
|
||||
spec = State.get Spec
|
||||
new_spec = Spec spec.name (Cons (Behavior this result) spec.behaviors)
|
||||
State.put Spec new_spec
|
||||
|
||||
run_spec ~behavior =
|
||||
maybeExc = case Panic.recover behavior of
|
||||
_ -> Success
|
||||
result = maybeExc.catch ex->
|
||||
case ex of
|
||||
Failure _ -> ex
|
||||
_ -> Failure ("Unexpected error has been thrown: " + ex.to_text)
|
||||
new_spec = Spec spec.name (Cons (Behavior this result) spec.behaviors)
|
||||
State.put Spec new_spec
|
||||
result
|
||||
|
||||
|
||||
## Runs a suite of tests, consisting of multiple `describe` blocks.
|
||||
|
||||
|
105
distribution/std-lib/Base/src/Text/Extensions.enso
Normal file
105
distribution/std-lib/Base/src/Text/Extensions.enso
Normal file
@ -0,0 +1,105 @@
|
||||
from Base import all
|
||||
from Builtins import Text, Prim_Text_Helpers
|
||||
|
||||
from Builtins export Text
|
||||
|
||||
polyglot java import com.ibm.icu.text.BreakIterator
|
||||
polyglot java import org.enso.base.Text_Utils
|
||||
|
||||
## Applies `function` to each character in `this`.
|
||||
|
||||
A character is defined as an Extended Grapheme Cluster, see
|
||||
[Unicode Standard Annex #29](https://unicode.org/reports/tr29/).
|
||||
|
||||
This is the smallest unit that still has semantic meaning in most
|
||||
text-processing applications.
|
||||
Text.each : (Text -> Any) -> Unit
|
||||
Text.each function =
|
||||
iterator = BreakIterator.getCharacterInstance []
|
||||
iterator.setText [this]
|
||||
|
||||
fst = iterator.first []
|
||||
nxt = iterator.next []
|
||||
|
||||
iterate prev nxt = if nxt == -1 then Unit else
|
||||
function (Text_Utils.substring [this, prev, nxt])
|
||||
next_nxt = iterator.next []
|
||||
iterate nxt next_nxt
|
||||
iterate fst nxt
|
||||
Unit
|
||||
|
||||
## Returns a vector containing all characters in the given text.
|
||||
|
||||
A character is defined as an Extended Grapheme Cluster, see
|
||||
[Unicode Standard Annex #29](https://unicode.org/reports/tr29/).
|
||||
|
||||
This is the smallest unit that still has semantic meaning in most
|
||||
text-processing applications.
|
||||
Text.characters : Vector
|
||||
Text.characters =
|
||||
bldr = Vector.new_builder
|
||||
this.each bldr.append
|
||||
r = bldr.to_vector
|
||||
r
|
||||
|
||||
## Takes a separator string and returns a vector resulting from splitting
|
||||
`this` on each occurence of `separator`.
|
||||
|
||||
> Example
|
||||
In the following example, we'll split the text into a vector of
|
||||
comma-separated items:
|
||||
"ham,eggs,cheese,tomatoes".split_at ","
|
||||
The code above returns:
|
||||
["ham", "eggs", "cheese", "tomatoes"]
|
||||
Text.split_at : Text -> Vector
|
||||
Text.split_at separator =
|
||||
Vector.from_polyglot_array (Text_Utils.split_at [this, separator])
|
||||
|
||||
## Checks whether `this` is equal to `that`.
|
||||
|
||||
The definition of equality includes Unicode canonicalization. I.e. two texts
|
||||
are equal if they are identical after canonical decomposition. This ensures
|
||||
that different ways of expressing the same character in the underlying
|
||||
binary representation are considered equal.
|
||||
|
||||
> Example
|
||||
The string 'é' (i.e. the character U+00E9, LATIN SMALL LETTER E WITH
|
||||
ACUTE) is canonically the same as the string 'e\u0301' (i.e. the letter
|
||||
`e` followed by U+0301, COMBINING ACUTE ACCENT). Therefore:
|
||||
('é'.equals 'e\u0301') == True
|
||||
Text.equals : Text -> Boolean
|
||||
Text.equals that = Text_Utils.equals [this, that]
|
||||
|
||||
## Returns a vector containing bytes representing the UTF-8 encoding of the
|
||||
input text.
|
||||
|
||||
This is useful for low-level operations, such as binary data encoding and
|
||||
decoding.
|
||||
Text.utf_8 : Vector
|
||||
Text.utf_8 = Vector.from_polyglot_array (Text_Utils.get_bytes [this])
|
||||
|
||||
## Takes an array of bytes and returns Text resulting from decoding it as
|
||||
UTF-8.
|
||||
|
||||
This is useful for low-level operations, such as binary data encoding and
|
||||
decoding.
|
||||
Text.from_utf_8 : Vector -> Text
|
||||
Text.from_utf_8 bytes = Text_Utils.from_utf_8 [bytes.to_array]
|
||||
|
||||
## Returns a vector containing integers representing the Unicode codepoints of
|
||||
the input text.
|
||||
|
||||
This is useful for low-level operations, such as binary data encoding and
|
||||
decoding.
|
||||
Text.codepoints : Vector
|
||||
Text.codepoints =
|
||||
Vector.from_polyglot_array (Text_Utils.get_codepoints [this])
|
||||
|
||||
## Takes an array of numbers and returns the text resulting from interpreting it
|
||||
as a sequence of Unicode codepoints.
|
||||
|
||||
This is useful for low-level operations, such as binary data encoding and
|
||||
decoding.
|
||||
Text.from_codepoints : Vector -> Text
|
||||
Text.from_codepoints codepoints = Text_Utils.from_codepoints [codepoints.to_array]
|
||||
|
@ -25,6 +25,40 @@ type Vector
|
||||
at : Number -> Any
|
||||
at index = this.to_array.at index
|
||||
|
||||
## Creates a new vector builder instance.
|
||||
|
||||
A vector builder is a mutable data structure, that allows for gathering
|
||||
a number of elements and then converting them into a vector. This is
|
||||
particularly useful when the number of elements is not known upfront.
|
||||
|
||||
> Example
|
||||
In the following example we'll read items from the standard input,
|
||||
until the string "end" is entered by the user and then return a vector
|
||||
containing all items.
|
||||
from Base import all
|
||||
|
||||
main =
|
||||
builder = Vector.new_builder
|
||||
do_read =
|
||||
item = IO.readln
|
||||
if item.equals "end" then Unit else
|
||||
builder.append item
|
||||
do_read
|
||||
do_read
|
||||
vec = builder.to_vector
|
||||
IO.println vec
|
||||
new_builder : Builder
|
||||
new_builder = Builder.new
|
||||
|
||||
## Converts a polyglot value representing an array into a vector. This is
|
||||
useful when wrapping polyglot APIs for further use in Enso.
|
||||
from_polyglot_array : Any -> Vector
|
||||
from_polyglot_array arr =
|
||||
a = Array.new arr.length
|
||||
0.upto arr.length . each i->
|
||||
a.set_at i (arr.at i)
|
||||
Vector a
|
||||
|
||||
## Returns the number of elements stored in this vector.
|
||||
length : Number
|
||||
length = this.to_array.length
|
||||
@ -104,3 +138,71 @@ type Vector
|
||||
folder = str -> ix -> str + ", " + (arr.at ix).to_text
|
||||
tail_elems = 1.upto arr.length . fold "" folder
|
||||
"[" + (arr.at 0 . to_text) + tail_elems + "]"
|
||||
|
||||
## Checks whether this vector is equal to `that`. Two vectors are considered
|
||||
equal, when they have the same length and their items are pairwise equal.
|
||||
equals : Vector -> Boolean
|
||||
equals that =
|
||||
arr1 = this.to_array
|
||||
arr2 = that.to_array
|
||||
eq_at i = (arr1.at i) . equals (arr2.at i)
|
||||
r = if arr1.length == arr2.length then 0.upto arr1.length . every eq_at else False
|
||||
r
|
||||
|
||||
## A builder type for Enso vectors.
|
||||
|
||||
A vector builder is a mutable data structure, that allows to gather a
|
||||
number of elements and then convert them to a vector. This is
|
||||
particularly useful when the number of elements is not known upfront.
|
||||
|
||||
> Example
|
||||
In the following example we'll read items from the standard input,
|
||||
until the string "end" is entered by the user and then return a vector
|
||||
containing all items.
|
||||
from Base import all
|
||||
|
||||
main =
|
||||
builder = Vector.new_builder
|
||||
do_read =
|
||||
item = IO.readln
|
||||
if item.equals "end" then Unit else
|
||||
builder.append item
|
||||
do_read
|
||||
do_read
|
||||
vec = builder.to_vector
|
||||
IO.println vec
|
||||
type Builder
|
||||
type Builder to_array length
|
||||
|
||||
## Creates a new builder.
|
||||
new = Builder (Array.new 1) 0
|
||||
|
||||
## Returns the current capacity (i.e. the size of the underlying storage)
|
||||
of this builder.
|
||||
capacity = this.to_array.length
|
||||
|
||||
## Appends a new element into this builder.
|
||||
append : Any -> Unit
|
||||
append item = case this.capacity > this.length of
|
||||
True ->
|
||||
this.to_array.set_at this.length item
|
||||
Unsafe.set_atom_field this 1 (this.length + 1)
|
||||
False ->
|
||||
old_array = this.to_array
|
||||
new_array = Array.new old_array.length*2
|
||||
0.upto this.length . each i->
|
||||
new_array.set_at i (old_array.at i)
|
||||
Unit
|
||||
Unsafe.set_atom_field this 0 new_array
|
||||
this.append item
|
||||
Unit
|
||||
|
||||
## Converts this builder to a vector containing all the appended elements.
|
||||
to_vector : Vector
|
||||
to_vector =
|
||||
old_array = this.to_array
|
||||
new_array = Array.new this.length
|
||||
0.upto this.length . each i->
|
||||
new_array.set_at i (old_array.at i)
|
||||
Unit
|
||||
Vector new_array
|
||||
|
@ -0,0 +1,3 @@
|
||||
|
||||
Lists of 1 third-party dependencies.
|
||||
(Unicode/ICU License) ICU4J (com.ibm.icu:icu4j:67.1 - http://icu-project.org/)
|
@ -0,0 +1,414 @@
|
||||
COPYRIGHT AND PERMISSION NOTICE (ICU 58 and later)
|
||||
|
||||
Copyright © 1991-2020 Unicode, Inc. All rights reserved.
|
||||
Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Unicode data files and any associated documentation
|
||||
(the "Data Files") or Unicode software and any associated documentation
|
||||
(the "Software") to deal in the Data Files or Software
|
||||
without restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
the Data Files or Software, and to permit persons to whom the Data Files
|
||||
or Software are furnished to do so, provided that either
|
||||
(a) this copyright and permission notice appear with all copies
|
||||
of the Data Files or Software, or
|
||||
(b) this copyright and permission notice appear in associated
|
||||
Documentation.
|
||||
|
||||
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in these Data Files or Software without prior
|
||||
written authorization of the copyright holder.
|
||||
|
||||
---------------------
|
||||
|
||||
Third-Party Software Licenses
|
||||
|
||||
This section contains third-party software notices and/or additional
|
||||
terms for licensed third-party software components included within ICU
|
||||
libraries.
|
||||
|
||||
1. ICU License - ICU 1.8.1 to ICU 57.1
|
||||
|
||||
COPYRIGHT AND PERMISSION NOTICE
|
||||
|
||||
Copyright (c) 1995-2016 International Business Machines Corporation and others
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, and/or sell copies of the Software, and to permit persons
|
||||
to whom the Software is furnished to do so, provided that the above
|
||||
copyright notice(s) and this permission notice appear in all copies of
|
||||
the Software and that both the above copyright notice(s) and this
|
||||
permission notice appear in supporting documentation.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
|
||||
SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
|
||||
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder
|
||||
shall not be used in advertising or otherwise to promote the sale, use
|
||||
or other dealings in this Software without prior written authorization
|
||||
of the copyright holder.
|
||||
|
||||
All trademarks and registered trademarks mentioned herein are the
|
||||
property of their respective owners.
|
||||
|
||||
2. Chinese/Japanese Word Break Dictionary Data (cjdict.txt)
|
||||
|
||||
# The Google Chrome software developed by Google is licensed under
|
||||
# the BSD license. Other software included in this distribution is
|
||||
# provided under other licenses, as set forth below.
|
||||
#
|
||||
# The BSD License
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
# Copyright (C) 2006-2008, Google Inc.
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
# Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided with
|
||||
# the distribution.
|
||||
# Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
#
|
||||
# The word list in cjdict.txt are generated by combining three word lists
|
||||
# listed below with further processing for compound word breaking. The
|
||||
# frequency is generated with an iterative training against Google web
|
||||
# corpora.
|
||||
#
|
||||
# * Libtabe (Chinese)
|
||||
# - https://sourceforge.net/project/?group_id=1519
|
||||
# - Its license terms and conditions are shown below.
|
||||
#
|
||||
# * IPADIC (Japanese)
|
||||
# - http://chasen.aist-nara.ac.jp/chasen/distribution.html
|
||||
# - Its license terms and conditions are shown below.
|
||||
#
|
||||
# ---------COPYING.libtabe ---- BEGIN--------------------
|
||||
#
|
||||
# /*
|
||||
# * Copyright (c) 1999 TaBE Project.
|
||||
# * Copyright (c) 1999 Pai-Hsiang Hsiao.
|
||||
# * All rights reserved.
|
||||
# *
|
||||
# * Redistribution and use in source and binary forms, with or without
|
||||
# * modification, are permitted provided that the following conditions
|
||||
# * are met:
|
||||
# *
|
||||
# * . Redistributions of source code must retain the above copyright
|
||||
# * notice, this list of conditions and the following disclaimer.
|
||||
# * . Redistributions in binary form must reproduce the above copyright
|
||||
# * notice, this list of conditions and the following disclaimer in
|
||||
# * the documentation and/or other materials provided with the
|
||||
# * distribution.
|
||||
# * . Neither the name of the TaBE Project nor the names of its
|
||||
# * contributors may be used to endorse or promote products derived
|
||||
# * from this software without specific prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
# * OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# */
|
||||
#
|
||||
# /*
|
||||
# * Copyright (c) 1999 Computer Systems and Communication Lab,
|
||||
# * Institute of Information Science, Academia
|
||||
# * Sinica. All rights reserved.
|
||||
# *
|
||||
# * Redistribution and use in source and binary forms, with or without
|
||||
# * modification, are permitted provided that the following conditions
|
||||
# * are met:
|
||||
# *
|
||||
# * . Redistributions of source code must retain the above copyright
|
||||
# * notice, this list of conditions and the following disclaimer.
|
||||
# * . Redistributions in binary form must reproduce the above copyright
|
||||
# * notice, this list of conditions and the following disclaimer in
|
||||
# * the documentation and/or other materials provided with the
|
||||
# * distribution.
|
||||
# * . Neither the name of the Computer Systems and Communication Lab
|
||||
# * nor the names of its contributors may be used to endorse or
|
||||
# * promote products derived from this software without specific
|
||||
# * prior written permission.
|
||||
# *
|
||||
# * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
# * OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# */
|
||||
#
|
||||
# Copyright 1996 Chih-Hao Tsai @ Beckman Institute,
|
||||
# University of Illinois
|
||||
# c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4
|
||||
#
|
||||
# ---------------COPYING.libtabe-----END--------------------------------
|
||||
#
|
||||
#
|
||||
# ---------------COPYING.ipadic-----BEGIN-------------------------------
|
||||
#
|
||||
# Copyright 2000, 2001, 2002, 2003 Nara Institute of Science
|
||||
# and Technology. All Rights Reserved.
|
||||
#
|
||||
# Use, reproduction, and distribution of this software is permitted.
|
||||
# Any copy of this software, whether in its original form or modified,
|
||||
# must include both the above copyright notice and the following
|
||||
# paragraphs.
|
||||
#
|
||||
# Nara Institute of Science and Technology (NAIST),
|
||||
# the copyright holders, disclaims all warranties with regard to this
|
||||
# software, including all implied warranties of merchantability and
|
||||
# fitness, in no event shall NAIST be liable for
|
||||
# any special, indirect or consequential damages or any damages
|
||||
# whatsoever resulting from loss of use, data or profits, whether in an
|
||||
# action of contract, negligence or other tortuous action, arising out
|
||||
# of or in connection with the use or performance of this software.
|
||||
#
|
||||
# A large portion of the dictionary entries
|
||||
# originate from ICOT Free Software. The following conditions for ICOT
|
||||
# Free Software applies to the current dictionary as well.
|
||||
#
|
||||
# Each User may also freely distribute the Program, whether in its
|
||||
# original form or modified, to any third party or parties, PROVIDED
|
||||
# that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear
|
||||
# on, or be attached to, the Program, which is distributed substantially
|
||||
# in the same form as set out herein and that such intended
|
||||
# distribution, if actually made, will neither violate or otherwise
|
||||
# contravene any of the laws and regulations of the countries having
|
||||
# jurisdiction over the User or the intended distribution itself.
|
||||
#
|
||||
# NO WARRANTY
|
||||
#
|
||||
# The program was produced on an experimental basis in the course of the
|
||||
# research and development conducted during the project and is provided
|
||||
# to users as so produced on an experimental basis. Accordingly, the
|
||||
# program is provided without any warranty whatsoever, whether express,
|
||||
# implied, statutory or otherwise. The term "warranty" used herein
|
||||
# includes, but is not limited to, any warranty of the quality,
|
||||
# performance, merchantability and fitness for a particular purpose of
|
||||
# the program and the nonexistence of any infringement or violation of
|
||||
# any right of any third party.
|
||||
#
|
||||
# Each user of the program will agree and understand, and be deemed to
|
||||
# have agreed and understood, that there is no warranty whatsoever for
|
||||
# the program and, accordingly, the entire risk arising from or
|
||||
# otherwise connected with the program is assumed by the user.
|
||||
#
|
||||
# Therefore, neither ICOT, the copyright holder, or any other
|
||||
# organization that participated in or was otherwise related to the
|
||||
# development of the program and their respective officials, directors,
|
||||
# officers and other employees shall be held liable for any and all
|
||||
# damages, including, without limitation, general, special, incidental
|
||||
# and consequential damages, arising out of or otherwise in connection
|
||||
# with the use or inability to use the program or any product, material
|
||||
# or result produced or otherwise obtained by using the program,
|
||||
# regardless of whether they have been advised of, or otherwise had
|
||||
# knowledge of, the possibility of such damages at any time during the
|
||||
# project or thereafter. Each user will be deemed to have agreed to the
|
||||
# foregoing by his or her commencement of use of the program. The term
|
||||
# "use" as used herein includes, but is not limited to, the use,
|
||||
# modification, copying and distribution of the program and the
|
||||
# production of secondary products from the program.
|
||||
#
|
||||
# In the case where the program, whether in its original form or
|
||||
# modified, was distributed or delivered to or received by a user from
|
||||
# any person, organization or entity other than ICOT, unless it makes or
|
||||
# grants independently of ICOT any specific warranty to the user in
|
||||
# writing, such person, organization or entity, will also be exempted
|
||||
# from and not be held liable to the user for any such damages as noted
|
||||
# above as far as the program is concerned.
|
||||
#
|
||||
# ---------------COPYING.ipadic-----END----------------------------------
|
||||
|
||||
3. Lao Word Break Dictionary Data (laodict.txt)
|
||||
|
||||
# Copyright (c) 2013 International Business Machines Corporation
|
||||
# and others. All Rights Reserved.
|
||||
#
|
||||
# Project: https://github.com/veer66/lao-dictionary
|
||||
# Dictionary: https://github.com/veer66/lao-dictionary/blob/master/Lao-Dictionary.txt
|
||||
# License: https://github.com/veer66/lao-dictionary/blob/master/Lao-Dictionary-LICENSE.txt
|
||||
# (copied below)
|
||||
#
|
||||
# This file is derived from the above dictionary, with slight
|
||||
# modifications.
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
#
|
||||
# Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer. Redistributions in
|
||||
# binary form must reproduce the above copyright notice, this list of
|
||||
# conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
# OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
4. Burmese Word Break Dictionary Data (burmesedict.txt)
|
||||
|
||||
# Copyright (c) 2014 International Business Machines Corporation
|
||||
# and others. All Rights Reserved.
|
||||
#
|
||||
# This list is part of a project hosted at:
|
||||
# github.com/kanyawtech/myanmar-karen-word-lists
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
# Copyright (c) 2013, LeRoy Benjamin Sharon
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met: Redistributions of source code must retain the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer. Redistributions in binary form must reproduce the
|
||||
# above copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# Neither the name Myanmar Karen Word Lists, nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
||||
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
# SUCH DAMAGE.
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
5. Time Zone Database
|
||||
|
||||
ICU uses the public domain data and code derived from Time Zone
|
||||
Database for its time zone support. The ownership of the TZ database
|
||||
is explained in BCP 175: Procedure for Maintaining the Time Zone
|
||||
Database section 7.
|
||||
|
||||
# 7. Database Ownership
|
||||
#
|
||||
# The TZ database itself is not an IETF Contribution or an IETF
|
||||
# document. Rather it is a pre-existing and regularly updated work
|
||||
# that is in the public domain, and is intended to remain in the
|
||||
# public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do
|
||||
# not apply to the TZ Database or contributions that individuals make
|
||||
# to it. Should any claims be made and substantiated against the TZ
|
||||
# Database, the organization that is providing the IANA
|
||||
# Considerations defined in this RFC, under the memorandum of
|
||||
# understanding with the IETF, currently ICANN, may act in accordance
|
||||
# with all competent court orders. No ownership claims will be made
|
||||
# by ICANN or the IETF Trust on the database or the code. Any person
|
||||
# making a contribution to the database or code waives all rights to
|
||||
# future claims in that contribution or in the TZ Database.
|
||||
|
||||
6. Google double-conversion
|
||||
|
||||
Copyright 2006-2011, the V8 project authors. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -138,6 +138,7 @@ In order to build and run Enso you will need the following tools:
|
||||
|
||||
- [sbt](https://www.scala-sbt.org/) with the same version as specified in
|
||||
[`project/build.properties`](../project/build.properties).
|
||||
- [Maven](https://maven.apache.org/) with version at least 3.6.3.
|
||||
- [GraalVM](https://www.graalvm.org/) with the same version as described in the
|
||||
[`build.sbt`](../build.sbt) file, configured as your default JVM. GraalVM is
|
||||
distributed for different Java versions, so you need a GraalVM distribution
|
||||
|
@ -92,6 +92,13 @@ files are included by the CI build within the built artifacts.
|
||||
|
||||
### Engine Components
|
||||
|
||||
#### Standard Library
|
||||
|
||||
The third-party licenses for Java extensions of the standard library are
|
||||
gathered in the `third-party-licenses` directory in the `Base` library. The
|
||||
gathering process is automatic, triggered by the `package` goal of the
|
||||
associated Maven configuration file.
|
||||
|
||||
> The actionables for this section are:
|
||||
>
|
||||
> - The engine components as distributed as a JAR archive that everyone can
|
||||
|
@ -4,6 +4,7 @@ import java.io.{InputStream, OutputStream, PrintStream, PrintWriter, Writer}
|
||||
import java.util.Scanner
|
||||
|
||||
import org.enso.polyglot.debugger.{ReplExecutor, SessionManager}
|
||||
import org.jline.reader.impl.DefaultParser
|
||||
import org.jline.reader.{LineReader, LineReaderBuilder}
|
||||
import org.jline.terminal.{Terminal, TerminalBuilder}
|
||||
|
||||
@ -98,8 +99,10 @@ case class SimpleReplIO(in: InputStream, out: OutputStream) extends ReplIO {
|
||||
case class TerminalIO() extends ReplIO {
|
||||
private val terminal: Terminal =
|
||||
TerminalBuilder.builder().system(true).build()
|
||||
private val parser: DefaultParser = new DefaultParser()
|
||||
parser.setEscapeChars(null)
|
||||
private val lineReader: LineReader =
|
||||
LineReaderBuilder.builder().terminal(terminal).build()
|
||||
LineReaderBuilder.builder().parser(parser).terminal(terminal).build()
|
||||
|
||||
/**
|
||||
* Ask user for a line of input, using given prompt
|
||||
|
@ -1,11 +1,5 @@
|
||||
package org.enso.interpreter.bench;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import org.openjdk.jmh.results.RunResult;
|
||||
import org.openjdk.jmh.runner.BenchmarkList;
|
||||
import org.openjdk.jmh.runner.BenchmarkListEntry;
|
||||
@ -14,6 +8,12 @@ import org.openjdk.jmh.runner.RunnerException;
|
||||
import org.openjdk.jmh.runner.options.Options;
|
||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** Runner class for the benchmarks. Discovers, runs and reports benchmark results. */
|
||||
public class BenchmarksRunner {
|
||||
public static final File REPORT_FILE = new File("./bench-report.xml");
|
||||
|
@ -1,5 +1,7 @@
|
||||
package org.enso.interpreter.bench.benchmarks.semantic;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.enso.interpreter.bench.fixtures.semantic.RecursionFixtures;
|
||||
import org.enso.interpreter.test.DefaultInterpreterRunner;
|
||||
|
@ -17,11 +17,13 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.node.expression.debug.CaptureResultScopeNode;
|
||||
import org.enso.interpreter.node.expression.debug.EvalNode;
|
||||
import org.enso.interpreter.runtime.builtin.Builtins;
|
||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.scope.FramePointer;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
import org.enso.polyglot.debugger.DebugServerInfo;
|
||||
@ -47,28 +49,28 @@ public class ReplDebuggerInstrument extends TruffleInstrument {
|
||||
@Override
|
||||
protected void onCreate(Env env) {
|
||||
SourceSectionFilter filter =
|
||||
SourceSectionFilter.newBuilder().tagIs(DebuggerTags.AlwaysHalt.class)
|
||||
.build();
|
||||
SourceSectionFilter.newBuilder().tagIs(DebuggerTags.AlwaysHalt.class).build();
|
||||
this.env = env;
|
||||
|
||||
DebuggerMessageHandler handler = new DebuggerMessageHandler();
|
||||
try {
|
||||
MessageEndpoint client =
|
||||
env.startServer(URI.create(DebugServerInfo.URI), handler);
|
||||
MessageEndpoint client = env.startServer(URI.create(DebugServerInfo.URI), handler);
|
||||
if (client != null) {
|
||||
handler.setClient(client);
|
||||
Instrumenter instrumenter = env.getInstrumenter();
|
||||
instrumenter.attachExecutionEventFactory(filter, ctx ->
|
||||
new ReplExecutionEventNode(ctx, handler, env.getLogger(ReplExecutionEventNode.class)));
|
||||
instrumenter.attachExecutionEventFactory(
|
||||
filter,
|
||||
ctx ->
|
||||
new ReplExecutionEventNode(
|
||||
ctx, handler, env.getLogger(ReplExecutionEventNode.class)));
|
||||
} else {
|
||||
env.getLogger(ReplDebuggerInstrument.class)
|
||||
.warning("ReplDebuggerInstrument was initialized, " +
|
||||
"but no client connected");
|
||||
.warning("ReplDebuggerInstrument was initialized, " + "but no client connected");
|
||||
}
|
||||
} catch (MessageTransport.VetoException e) {
|
||||
env.getLogger(ReplDebuggerInstrument.class)
|
||||
.warning("ReplDebuggerInstrument was initialized, " +
|
||||
"but client connection has been vetoed");
|
||||
.warning(
|
||||
"ReplDebuggerInstrument was initialized, " + "but client connection has been vetoed");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@ -85,6 +87,7 @@ public class ReplDebuggerInstrument extends TruffleInstrument {
|
||||
/** The actual node that's installed as a probe on any node the instrument was launched for. */
|
||||
public static class ReplExecutionEventNode extends ExecutionEventNode {
|
||||
private @Child EvalNode evalNode = EvalNode.buildWithResultScopeCapture();
|
||||
private @Child ToJavaStringNode toJavaStringNode = ToJavaStringNode.build();
|
||||
|
||||
private ReplExecutionEventNodeState nodeState;
|
||||
|
||||
@ -92,7 +95,8 @@ public class ReplDebuggerInstrument extends TruffleInstrument {
|
||||
private DebuggerMessageHandler handler;
|
||||
private TruffleLogger logger;
|
||||
|
||||
private ReplExecutionEventNode(EventContext eventContext, DebuggerMessageHandler handler, TruffleLogger logger) {
|
||||
private ReplExecutionEventNode(
|
||||
EventContext eventContext, DebuggerMessageHandler handler, TruffleLogger logger) {
|
||||
this.eventContext = eventContext;
|
||||
this.handler = handler;
|
||||
this.logger = logger;
|
||||
@ -116,7 +120,8 @@ public class ReplDebuggerInstrument extends TruffleInstrument {
|
||||
* @return a map, where keys are variable names and values are current values of variables.
|
||||
*/
|
||||
public Map<String, Object> listBindings() {
|
||||
Map<String, FramePointer> flatScope = nodeState.getLastScope().getLocalScope().flattenBindings();
|
||||
Map<String, FramePointer> flatScope =
|
||||
nodeState.getLastScope().getLocalScope().flattenBindings();
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
for (Map.Entry<String, FramePointer> entry : flatScope.entrySet()) {
|
||||
result.put(entry.getKey(), getValue(nodeState.getLastScope().getFrame(), entry.getValue()));
|
||||
@ -128,20 +133,21 @@ public class ReplDebuggerInstrument extends TruffleInstrument {
|
||||
* Evaluates an arbitrary expression in the current execution context.
|
||||
*
|
||||
* @param expression the expression to evaluate
|
||||
* @return the result of evaluating the expression or an exception that
|
||||
* caused failure
|
||||
* @return the result of evaluating the expression or an exception that caused failure
|
||||
*/
|
||||
public Either<Exception, Object> evaluate(String expression) {
|
||||
ReplExecutionEventNodeState savedState = nodeState;
|
||||
try {
|
||||
Stateful result = evalNode.execute(nodeState.getLastScope(), nodeState.getLastState(), expression);
|
||||
Stateful result =
|
||||
evalNode.execute(
|
||||
nodeState.getLastScope(), nodeState.getLastState(), Text.create(expression));
|
||||
Object lastState = result.getState();
|
||||
CaptureResultScopeNode.WithCallerInfo payload =
|
||||
(CaptureResultScopeNode.WithCallerInfo) result.getValue();
|
||||
CallerInfo lastScope = payload.getCallerInfo();
|
||||
Object lastReturn = payload.getResult();
|
||||
nodeState = new ReplExecutionEventNodeState(lastReturn, lastState, lastScope);
|
||||
return new Right<>(lastReturn);
|
||||
return new Right<>(formatObject(lastReturn));
|
||||
} catch (Exception e) {
|
||||
nodeState = savedState;
|
||||
TruffleStackTrace.fillIn(e);
|
||||
@ -149,6 +155,14 @@ public class ReplDebuggerInstrument extends TruffleInstrument {
|
||||
}
|
||||
}
|
||||
|
||||
private Object formatObject(Object o) {
|
||||
if (o instanceof Text) {
|
||||
return toJavaStringNode.execute((Text) o);
|
||||
} else {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates this REPL session.
|
||||
*
|
||||
@ -202,8 +216,9 @@ public class ReplDebuggerInstrument extends TruffleInstrument {
|
||||
if (handler.hasClient()) {
|
||||
handler.startSession(this);
|
||||
} else {
|
||||
logger.warning("Debugger session starting, " +
|
||||
"but no client connected, will terminate the session immediately");
|
||||
logger.warning(
|
||||
"Debugger session starting, "
|
||||
+ "but no client connected, will terminate the session immediately");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
@ -211,9 +226,9 @@ public class ReplDebuggerInstrument extends TruffleInstrument {
|
||||
/**
|
||||
* State of the execution node.
|
||||
*
|
||||
* As the execution nodes are reused by Truffle, the nested nodes share
|
||||
* state. If execution of a nested node fails, to ensure consistent state of
|
||||
* the parent node, its state has to be restored.
|
||||
* <p>As the execution nodes are reused by Truffle, the nested nodes share state. If execution
|
||||
* of a nested node fails, to ensure consistent state of the parent node, its state has to be
|
||||
* restored.
|
||||
*/
|
||||
private static class ReplExecutionEventNodeState {
|
||||
private final Object lastReturn;
|
||||
@ -239,5 +254,4 @@ public class ReplDebuggerInstrument extends TruffleInstrument {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import org.enso.interpreter.Constants;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.callable.dispatch.IndirectInvokeFunctionNode;
|
||||
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
@ -66,8 +67,13 @@ public abstract class InteropApplicationNode extends Node {
|
||||
Object[] arguments,
|
||||
@CachedContext(Language.class) Context context,
|
||||
@Cached("arguments.length") int cachedArgsLength,
|
||||
@Cached("buildSorter(cachedArgsLength)") InvokeFunctionNode sorterNode) {
|
||||
return sorterNode.execute(function, null, state, arguments).getValue();
|
||||
@Cached("buildSorter(cachedArgsLength)") InvokeFunctionNode sorterNode,
|
||||
@Cached("build()") HostValueToEnsoNode hostValueToEnsoNode) {
|
||||
Object[] args = new Object[cachedArgsLength];
|
||||
for (int i = 0; i < cachedArgsLength; i++) {
|
||||
args[i] = hostValueToEnsoNode.execute(arguments[i]);
|
||||
}
|
||||
return sorterNode.execute(function, null, state, args).getValue();
|
||||
}
|
||||
|
||||
@Specialization(replaces = "callCached")
|
||||
@ -75,13 +81,18 @@ public abstract class InteropApplicationNode extends Node {
|
||||
Function function,
|
||||
Object state,
|
||||
Object[] arguments,
|
||||
@Cached IndirectInvokeFunctionNode indirectInvokeFunctionNode) {
|
||||
@Cached IndirectInvokeFunctionNode indirectInvokeFunctionNode,
|
||||
@Cached("build()") HostValueToEnsoNode hostValueToEnsoNode) {
|
||||
Object[] args = new Object[arguments.length];
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
args[i] = hostValueToEnsoNode.execute(arguments[i]);
|
||||
}
|
||||
return indirectInvokeFunctionNode
|
||||
.execute(
|
||||
function,
|
||||
null,
|
||||
state,
|
||||
arguments,
|
||||
args,
|
||||
buildSchema(arguments.length),
|
||||
InvokeCallableNode.DefaultsExecutionMode.EXECUTE,
|
||||
InvokeCallableNode.ArgumentsExecutionMode.PRE_EXECUTED,
|
||||
|
@ -6,6 +6,8 @@ import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import org.enso.interpreter.Language;
|
||||
@ -18,6 +20,7 @@ import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.Array;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.MethodDoesNotExistException;
|
||||
import org.enso.interpreter.runtime.error.RuntimeError;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
@ -153,7 +156,7 @@ public abstract class MethodResolverNode extends Node {
|
||||
@Specialization(guards = "cachedSymbol == symbol")
|
||||
Function resolveString(
|
||||
UnresolvedSymbol symbol,
|
||||
String self,
|
||||
Text self,
|
||||
@Cached(value = "symbol", allowUncached = true) UnresolvedSymbol cachedSymbol,
|
||||
@Cached(value = "resolveMethodOnString(cachedSymbol)", allowUncached = true)
|
||||
Function function) {
|
||||
@ -190,6 +193,19 @@ public abstract class MethodResolverNode extends Node {
|
||||
return function;
|
||||
}
|
||||
|
||||
@Specialization(
|
||||
guards = {"isPolyglotArrayMethod(cachedSymbol)", "arrays.hasArrayElements(array)"})
|
||||
Function resolvePolyglotArray(
|
||||
UnresolvedSymbol symbol,
|
||||
Object array,
|
||||
@CachedLibrary(limit = "3") InteropLibrary arrays,
|
||||
@Cached(value = "symbol", allowUncached = true) UnresolvedSymbol cachedSymbol,
|
||||
@CachedContext(Language.class) Context ctx,
|
||||
@Cached(value = "resolveMethodOnPolyglotArray(cachedSymbol, ctx)", allowUncached = true)
|
||||
Function function) {
|
||||
return function;
|
||||
}
|
||||
|
||||
@Specialization(guards = {"cachedSymbol == symbol", "ctx.getEnvironment().isHostObject(target)"})
|
||||
Function resolveHost(
|
||||
UnresolvedSymbol symbol,
|
||||
@ -262,7 +278,7 @@ public abstract class MethodResolverNode extends Node {
|
||||
|
||||
Function resolveMethodOnString(UnresolvedSymbol symbol) {
|
||||
return ensureMethodExists(
|
||||
symbol.resolveFor(getBuiltins().text(), getBuiltins().any()), "Text", symbol);
|
||||
symbol.resolveFor(getBuiltins().text().getText(), getBuiltins().any()), "Text", symbol);
|
||||
}
|
||||
|
||||
Function resolveMethodOnFunction(UnresolvedSymbol symbol) {
|
||||
@ -283,9 +299,23 @@ public abstract class MethodResolverNode extends Node {
|
||||
|
||||
Function buildHostResolver(UnresolvedSymbol symbol, Context context) {
|
||||
if (symbol.getName().equals("new")) {
|
||||
return context.getBuiltins().getConstructorDispatch();
|
||||
return context.getBuiltins().polyglot().getConstructorDispatch();
|
||||
} else if (symbol.getName().equals("to_text")) {
|
||||
return context.getBuiltins().polyglot().getPolyglotToTextFunction();
|
||||
} else {
|
||||
return context.getBuiltins().buildPolyglotMethodDispatch(symbol);
|
||||
return context.getBuiltins().polyglot().buildPolyglotMethodDispatch(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isPolyglotArrayMethod(UnresolvedSymbol symbol) {
|
||||
return symbol.getName().equals("at") || symbol.getName().equals("length");
|
||||
}
|
||||
|
||||
Function resolveMethodOnPolyglotArray(UnresolvedSymbol symbol, Context context) {
|
||||
if (symbol.getName().equals("length")) {
|
||||
return context.getBuiltins().polyglot().getPolyglotArrayLengthFunction();
|
||||
} else {
|
||||
return context.getBuiltins().polyglot().getPolyglotArrayAtFunction();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,13 @@ package org.enso.interpreter.node.expression.builtin.bool;
|
||||
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
|
||||
@BuiltinMethod(type = "Boolean", name = "to_text", description = "Boolean to text conversion.")
|
||||
public class ToTextNode extends Node {
|
||||
String execute(boolean _this) {
|
||||
return _this ? "True" : "False";
|
||||
Text t = Text.create("True");
|
||||
Text f = Text.create("False");
|
||||
Text execute(boolean _this) {
|
||||
return _this ? t : f;
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.dsl.MonadicState;
|
||||
import org.enso.interpreter.node.expression.debug.EvalNode;
|
||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
|
||||
/** Root node for the builtin Debug.eval function. */
|
||||
@ -21,7 +22,7 @@ public class DebugEvalNode extends Node {
|
||||
}
|
||||
|
||||
Stateful execute(
|
||||
CallerInfo callerInfo, @MonadicState Object state, Object _this, String expression) {
|
||||
CallerInfo callerInfo, @MonadicState Object state, Object _this, Text expression) {
|
||||
return evalNode.execute(callerInfo, state, expression);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.profiles.BranchProfile;
|
||||
import org.enso.interpreter.Constants;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
|
||||
@BuiltinMethod(
|
||||
@ -16,11 +18,12 @@ import org.enso.interpreter.runtime.error.PanicException;
|
||||
public class GetMemberNode extends Node {
|
||||
private @Child InteropLibrary library =
|
||||
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
|
||||
private @Child ToJavaStringNode toJavaStringNode = ToJavaStringNode.build();
|
||||
private final BranchProfile err = BranchProfile.create();
|
||||
|
||||
Object execute(Object _this, Object object, String member_name) {
|
||||
Object execute(Object _this, Object object, Text member_name) {
|
||||
try {
|
||||
return library.readMember(object, member_name);
|
||||
return library.readMember(object, toJavaStringNode.execute(member_name));
|
||||
} catch (UnsupportedMessageException | UnknownIdentifierException e) {
|
||||
err.enter();
|
||||
throw new PanicException(e.getMessage(), this);
|
||||
|
@ -5,7 +5,9 @@ import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.profiles.BranchProfile;
|
||||
import org.enso.interpreter.Constants;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.runtime.data.Array;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
|
||||
@BuiltinMethod(
|
||||
@ -15,11 +17,12 @@ import org.enso.interpreter.runtime.error.PanicException;
|
||||
public class InvokeNode extends Node {
|
||||
private @Child InteropLibrary library =
|
||||
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
|
||||
private @Child ToJavaStringNode toJavaStringNode = ToJavaStringNode.build();
|
||||
private final BranchProfile err = BranchProfile.create();
|
||||
|
||||
Object execute(Object _this, Object target, String name, Array arguments) {
|
||||
Object execute(Object _this, Object target, Text name, Array arguments) {
|
||||
try {
|
||||
return library.invokeMember(target, name, arguments.getItems());
|
||||
return library.invokeMember(target, toJavaStringNode.execute(name), arguments.getItems());
|
||||
} catch (UnsupportedMessageException
|
||||
| ArityException
|
||||
| UnsupportedTypeException
|
||||
|
@ -1,11 +1,14 @@
|
||||
package org.enso.interpreter.node.expression.builtin.interop.java;
|
||||
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@ -20,10 +23,16 @@ public abstract class AddToClassPathNode extends Node {
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Object doExecute(Object _this, String path, @CachedContext(Language.class) Context context) {
|
||||
context.getEnvironment().addToHostClassPath(context.getTruffleFile(new File(path)));
|
||||
Object doExecute(
|
||||
Object _this,
|
||||
Text path,
|
||||
@CachedContext(Language.class) Context context,
|
||||
@Cached("build()") ToJavaStringNode toJavaStringNode) {
|
||||
context
|
||||
.getEnvironment()
|
||||
.addToHostClassPath(context.getTruffleFile(new File(toJavaStringNode.execute(path))));
|
||||
return context.getBuiltins().unit();
|
||||
}
|
||||
|
||||
abstract Object execute(Object _this, String path);
|
||||
abstract Object execute(Object _this, Text path);
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
package org.enso.interpreter.node.expression.builtin.interop.java;
|
||||
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
|
||||
@BuiltinMethod(type = "Java", name = "lookup_class", description = "Looks up a Java symbol.")
|
||||
public abstract class LookupClassNode extends Node {
|
||||
@ -14,9 +17,13 @@ public abstract class LookupClassNode extends Node {
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Object doExecute(Object _this, String name, @CachedContext(Language.class) Context ctx) {
|
||||
return ctx.getEnvironment().lookupHostSymbol(name);
|
||||
Object doExecute(
|
||||
Object _this,
|
||||
Text name,
|
||||
@CachedContext(Language.class) Context ctx,
|
||||
@Cached("build()") ToJavaStringNode toJavaStringNode) {
|
||||
return ctx.getEnvironment().lookupHostSymbol(toJavaStringNode.execute(name));
|
||||
}
|
||||
|
||||
abstract Object execute(Object _this, String name);
|
||||
abstract Object execute(Object _this, Text name);
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
package org.enso.interpreter.node.expression.builtin.interop.syntax;
|
||||
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.interop.ArityException;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
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.nodes.Node;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import com.oracle.truffle.api.nodes.UnexpectedResultException;
|
||||
import com.oracle.truffle.api.profiles.BranchProfile;
|
||||
import org.enso.interpreter.Constants;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.BuiltinRootNode;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.callable.function.FunctionSchema.CallStrategy;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
import org.enso.interpreter.runtime.type.TypesGen;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Any",
|
||||
name = "<polyglot_array_length>",
|
||||
description = "Returns the length of a polyglot array.")
|
||||
public class ArrayLengthNode extends Node {
|
||||
private @Child InteropLibrary library =
|
||||
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
|
||||
private final BranchProfile err = BranchProfile.create();
|
||||
|
||||
public Object execute(Object _this) {
|
||||
try {
|
||||
return library.getArraySize(_this);
|
||||
} catch (UnsupportedMessageException e) {
|
||||
err.enter();
|
||||
throw new PanicException(e.getMessage(), this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.enso.interpreter.node.expression.builtin.interop.generic;
|
||||
package org.enso.interpreter.node.expression.builtin.interop.syntax;
|
||||
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
|
||||
@ -10,17 +10,18 @@ import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Polyglot",
|
||||
name = "get_array_element",
|
||||
description = "Gets an element by index from a polyglot array.")
|
||||
type = "Any",
|
||||
name = "<polyglot_array_at>",
|
||||
description = "Returns the element of a polyglot array at a given index.")
|
||||
public class GetArrayElementNode extends Node {
|
||||
private @Child InteropLibrary library =
|
||||
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
|
||||
private @Child HostValueToEnsoNode hostValueToEnsoNode = HostValueToEnsoNode.build();
|
||||
private final BranchProfile err = BranchProfile.create();
|
||||
|
||||
Object execute(Object _this, Object array, long index) {
|
||||
public Object execute(Object _this, long index) {
|
||||
try {
|
||||
return library.readArrayElement(array, index);
|
||||
return hostValueToEnsoNode.execute(library.readArrayElement(_this, index));
|
||||
} catch (UnsupportedMessageException | InvalidArrayIndexException e) {
|
||||
err.enter();
|
||||
throw new PanicException(e.getMessage(), this);
|
@ -1,15 +1,18 @@
|
||||
package org.enso.interpreter.node.expression.builtin.interop.syntax;
|
||||
|
||||
import com.oracle.truffle.api.dsl.Fallback;
|
||||
import com.oracle.truffle.api.dsl.GenerateUncached;
|
||||
import com.oracle.truffle.api.dsl.ReportPolymorphism;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
|
||||
/**
|
||||
* Converts a value returned by a polyglot call back to a value that can be further used within Enso
|
||||
* programs.
|
||||
*/
|
||||
@ReportPolymorphism
|
||||
@GenerateUncached
|
||||
public abstract class HostValueToEnsoNode extends Node {
|
||||
public static HostValueToEnsoNode build() {
|
||||
return HostValueToEnsoNodeGen.create();
|
||||
@ -48,6 +51,11 @@ public abstract class HostValueToEnsoNode extends Node {
|
||||
return i;
|
||||
}
|
||||
|
||||
@Specialization
|
||||
Text doString(String txt) {
|
||||
return Text.create(txt);
|
||||
}
|
||||
|
||||
@Fallback
|
||||
Object doOther(Object o) {
|
||||
return o;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.enso.interpreter.node.expression.builtin.interop.generic;
|
||||
package org.enso.interpreter.node.expression.builtin.interop.syntax;
|
||||
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||
@ -6,20 +6,23 @@ import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.profiles.BranchProfile;
|
||||
import org.enso.interpreter.Constants;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Polyglot",
|
||||
name = "get_array_size",
|
||||
description = "Gets the size of a polyglot array.")
|
||||
public class GetArraySizeNode extends Node {
|
||||
type = "Any",
|
||||
name = "<to_text>",
|
||||
description = "Returns human-readable representation of a polyglot object.")
|
||||
public class PolyglotToTextNode extends Node {
|
||||
private @Child InteropLibrary library =
|
||||
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
|
||||
private @Child InteropLibrary strings =
|
||||
InteropLibrary.getFactory().createDispatched(Constants.CacheSizes.BUILTIN_INTEROP_DISPATCH);
|
||||
private final BranchProfile err = BranchProfile.create();
|
||||
|
||||
Object execute(Object _this, Object array) {
|
||||
public Text execute(Object _this) {
|
||||
try {
|
||||
return library.getArraySize(array);
|
||||
return Text.create(strings.asString(library.toDisplayString(_this)));
|
||||
} catch (UnsupportedMessageException e) {
|
||||
err.enter();
|
||||
throw new PanicException(e.getMessage(), this);
|
@ -1,12 +1,25 @@
|
||||
package org.enso.interpreter.node.expression.builtin.io;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.dsl.MonadicState;
|
||||
import org.enso.interpreter.node.callable.InvokeCallableNode;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
import org.enso.interpreter.runtime.type.TypesGen;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "IO",
|
||||
@ -17,12 +30,53 @@ public abstract class PrintErrNode extends Node {
|
||||
return PrintErrNodeGen.create();
|
||||
}
|
||||
|
||||
abstract Object execute(Object _this, Object message);
|
||||
abstract Stateful execute(
|
||||
VirtualFrame frame, @MonadicState Object state, Object _this, Object message);
|
||||
|
||||
@Specialization
|
||||
@TruffleBoundary
|
||||
Object doPrint(Object self, Object message, @CachedContext(Language.class) Context ctx) {
|
||||
ctx.getErr().println(message);
|
||||
return ctx.getUnit().newInstance();
|
||||
Stateful doPrintText(
|
||||
VirtualFrame frame,
|
||||
Object state,
|
||||
Object self,
|
||||
Text message,
|
||||
@CachedContext(Language.class) Context ctx,
|
||||
@Cached("build()") ToJavaStringNode toJavaStringNode) {
|
||||
print(ctx.getErr(), toJavaStringNode.execute(message));
|
||||
return new Stateful(state, ctx.getUnit().newInstance());
|
||||
}
|
||||
|
||||
@Specialization(guards = "!isText(message)")
|
||||
Stateful doPrint(
|
||||
VirtualFrame frame,
|
||||
Object state,
|
||||
Object self,
|
||||
Object message,
|
||||
@CachedContext(Language.class) Context ctx,
|
||||
@Cached("buildSymbol(ctx)") UnresolvedSymbol symbol,
|
||||
@Cached("buildInvokeCallableNode()") InvokeCallableNode invokeCallableNode,
|
||||
@Cached("build()") ToJavaStringNode toJavaStringNode) {
|
||||
Stateful str = invokeCallableNode.execute(symbol, frame, state, new Object[] {message});
|
||||
print(ctx.getErr(), toJavaStringNode.execute((Text) str.getValue()));
|
||||
return new Stateful(str.getState(), ctx.getUnit().newInstance());
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private void print(PrintStream err, Object str) {
|
||||
err.println(str);
|
||||
}
|
||||
|
||||
boolean isText(Object o) {
|
||||
return TypesGen.isText(o);
|
||||
}
|
||||
|
||||
InvokeCallableNode buildInvokeCallableNode() {
|
||||
return InvokeCallableNode.build(
|
||||
new CallArgumentInfo[] {new CallArgumentInfo()},
|
||||
InvokeCallableNode.DefaultsExecutionMode.EXECUTE,
|
||||
InvokeCallableNode.ArgumentsExecutionMode.PRE_EXECUTED);
|
||||
}
|
||||
|
||||
UnresolvedSymbol buildSymbol(Context ctx) {
|
||||
return UnresolvedSymbol.build("to_text", ctx.getBuiltins().getScope());
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package org.enso.interpreter.node.expression.builtin.io;
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Fallback;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
@ -11,10 +12,13 @@ import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.dsl.MonadicState;
|
||||
import org.enso.interpreter.node.callable.InvokeCallableNode;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
import org.enso.interpreter.runtime.type.TypesGen;
|
||||
|
||||
@BuiltinMethod(type = "IO", name = "println", description = "Prints its argument to standard out.")
|
||||
public abstract class PrintlnNode extends Node {
|
||||
@ -28,18 +32,37 @@ public abstract class PrintlnNode extends Node {
|
||||
VirtualFrame frame, @MonadicState Object state, Object _this, Object message);
|
||||
|
||||
@Specialization
|
||||
Stateful doPrintText(
|
||||
VirtualFrame frame,
|
||||
Object state,
|
||||
Object self,
|
||||
Text message,
|
||||
@CachedContext(Language.class) Context ctx,
|
||||
@Cached("build()") ToJavaStringNode toJavaStringNode) {
|
||||
print(ctx.getOut(), toJavaStringNode.execute(message));
|
||||
return new Stateful(state, ctx.getUnit().newInstance());
|
||||
}
|
||||
|
||||
@Specialization(guards = "!isText(message)")
|
||||
Stateful doPrint(
|
||||
VirtualFrame frame,
|
||||
Object state,
|
||||
Object self,
|
||||
Object message,
|
||||
@CachedContext(Language.class) Context ctx,
|
||||
@Cached("buildSymbol(ctx)") UnresolvedSymbol symbol) {
|
||||
@Cached("buildSymbol(ctx)") UnresolvedSymbol symbol,
|
||||
@Cached("build()") ToJavaStringNode toJavaStringNode,
|
||||
@Cached("buildInvokeCallableNode()") InvokeCallableNode invokeCallableNode) {
|
||||
Stateful str = invokeCallableNode.execute(symbol, frame, state, new Object[] {message});
|
||||
print(ctx.getOut(), str.getValue());
|
||||
String strr = toJavaStringNode.execute((Text) str.getValue());
|
||||
print(ctx.getOut(), strr);
|
||||
return new Stateful(str.getState(), ctx.getUnit().newInstance());
|
||||
}
|
||||
|
||||
boolean isText(Object o) {
|
||||
return TypesGen.isText(o);
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
private void print(PrintStream out, Object str) {
|
||||
out.println(str);
|
||||
@ -49,6 +72,13 @@ public abstract class PrintlnNode extends Node {
|
||||
return UnresolvedSymbol.build("to_text", ctx.getBuiltins().getScope());
|
||||
}
|
||||
|
||||
InvokeCallableNode buildInvokeCallableNode() {
|
||||
return InvokeCallableNode.build(
|
||||
new CallArgumentInfo[] {new CallArgumentInfo()},
|
||||
InvokeCallableNode.DefaultsExecutionMode.EXECUTE,
|
||||
InvokeCallableNode.ArgumentsExecutionMode.PRE_EXECUTED);
|
||||
}
|
||||
|
||||
static PrintlnNode build() {
|
||||
return PrintlnNodeGen.create();
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import java.io.IOException;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
import org.enso.interpreter.runtime.error.RuntimeError;
|
||||
|
||||
@BuiltinMethod(type = "IO", name = "readln", description = "Reads a line from standard in.")
|
||||
@ -21,11 +23,11 @@ public abstract class ReadlnNode extends Node {
|
||||
|
||||
@Specialization
|
||||
@TruffleBoundary
|
||||
Object doRead(Object _this, @CachedContext(Language.class) Context ctx) {
|
||||
Text doRead(Object _this, @CachedContext(Language.class) Context ctx) {
|
||||
try {
|
||||
return ctx.getInReader().readLine();
|
||||
return Text.create(ctx.getInReader().readLine());
|
||||
} catch (IOException e) {
|
||||
return new RuntimeError("Empty input stream.");
|
||||
throw new PanicException("Empty input stream", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,17 @@
|
||||
package org.enso.interpreter.node.expression.builtin.system;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.CachedContext;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.io.TruffleProcessBuilder;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.data.Array;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
|
||||
import java.io.*;
|
||||
@ -25,9 +28,9 @@ public abstract class CreateProcessNode extends Node {
|
||||
|
||||
abstract Object execute(
|
||||
Object _this,
|
||||
String command,
|
||||
Text command,
|
||||
Array arguments,
|
||||
String input,
|
||||
Text input,
|
||||
boolean redirectIn,
|
||||
boolean redirectOut,
|
||||
boolean redirectErr);
|
||||
@ -36,21 +39,25 @@ public abstract class CreateProcessNode extends Node {
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
Object doCreate(
|
||||
Object _this,
|
||||
String command,
|
||||
Text command,
|
||||
Array arguments,
|
||||
String input,
|
||||
Text input,
|
||||
boolean redirectIn,
|
||||
boolean redirectOut,
|
||||
boolean redirectErr,
|
||||
@CachedContext(Language.class) Context ctx) {
|
||||
String[] cmd = new String[(int) arguments.getItems().length + 1];
|
||||
cmd[0] = command;
|
||||
System.arraycopy(arguments.getItems(), 0, cmd, 1, (int) arguments.getItems().length);
|
||||
@CachedContext(Language.class) Context ctx,
|
||||
@Cached("build()") ToJavaStringNode toJavaStringNode) {
|
||||
String[] cmd = new String[arguments.getItems().length + 1];
|
||||
cmd[0] = toJavaStringNode.execute(command);
|
||||
for (int i = 1; i <= arguments.getItems().length; i++) {
|
||||
cmd[i] = toJavaStringNode.execute((Text) arguments.getItems()[i - 1]);
|
||||
}
|
||||
TruffleProcessBuilder pb = ctx.getEnvironment().newProcessBuilder(cmd);
|
||||
|
||||
try {
|
||||
Process p = pb.start();
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(input.getBytes());
|
||||
ByteArrayInputStream in =
|
||||
new ByteArrayInputStream(toJavaStringNode.execute(input).getBytes());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream err = new ByteArrayOutputStream();
|
||||
|
||||
@ -106,8 +113,8 @@ public abstract class CreateProcessNode extends Node {
|
||||
}
|
||||
|
||||
long exitCode = p.exitValue();
|
||||
String returnOut = new String(out.toByteArray());
|
||||
String returnErr = new String(err.toByteArray());
|
||||
Text returnOut = Text.create(new String(out.toByteArray()));
|
||||
Text returnErr = Text.create(new String(err.toByteArray()));
|
||||
|
||||
return ctx.getBuiltins()
|
||||
.system()
|
||||
|
@ -3,6 +3,7 @@ package org.enso.interpreter.node.expression.builtin.system;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "System",
|
||||
@ -10,12 +11,12 @@ import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
description = "Get the type of operating system.")
|
||||
public final class OsNode extends Node {
|
||||
|
||||
private final String LINUX = "linux";
|
||||
private final String MACOS = "macos";
|
||||
private final String WINDOWS = "windows";
|
||||
private final String UNKNOWN = "unknown";
|
||||
private final Text LINUX = Text.create("linux");
|
||||
private final Text MACOS = Text.create("macos");
|
||||
private final Text WINDOWS = Text.create("windows");
|
||||
private final Text UNKNOWN = Text.create("unknown");
|
||||
|
||||
String execute(Object _this) {
|
||||
Text execute(Object _this) {
|
||||
if (SystemUtils.IS_OS_LINUX) return LINUX;
|
||||
if (SystemUtils.IS_OS_MAC_OSX) return MACOS;
|
||||
if (SystemUtils.IS_OS_WINDOWS) return WINDOWS;
|
||||
|
@ -1,13 +1,67 @@
|
||||
package org.enso.interpreter.node.expression.builtin.text;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Fallback;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.PanicException;
|
||||
|
||||
@BuiltinMethod(type = "Any", name = "to_text", description = "Generic text conversion.")
|
||||
public class AnyToTextNode extends Node {
|
||||
public abstract class AnyToTextNode extends Node {
|
||||
private static final int DISPATCH_CACHE = 3;
|
||||
private @Child InteropLibrary displays =
|
||||
InteropLibrary.getFactory().createDispatched(DISPATCH_CACHE);
|
||||
private @Child InteropLibrary strings =
|
||||
InteropLibrary.getFactory().createDispatched(DISPATCH_CACHE);
|
||||
|
||||
static AnyToTextNode build() {
|
||||
return AnyToTextNodeGen.create();
|
||||
}
|
||||
|
||||
abstract Text execute(Object _this);
|
||||
|
||||
@Specialization
|
||||
Text doAtom(Atom at) {
|
||||
if (at.getFields().length == 0) {
|
||||
return Text.create(at.getConstructor().getName());
|
||||
} else {
|
||||
return doComplexAtom(at, displays, strings);
|
||||
}
|
||||
}
|
||||
|
||||
@Fallback
|
||||
Text doOther(Object object) {
|
||||
try {
|
||||
return Text.create(strings.asString(displays.toDisplayString(object)));
|
||||
} catch (UnsupportedMessageException e) {
|
||||
return Text.create(object.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
String execute(Object _this) {
|
||||
return _this.toString();
|
||||
private Text doComplexAtom(Atom atom, InteropLibrary displays, InteropLibrary strings) {
|
||||
Text res = Text.create("(" + atom.getConstructor().getName() + " ");
|
||||
try {
|
||||
res = Text.create(res, strings.asString(displays.toDisplayString(atom.getFields()[0])));
|
||||
} catch (UnsupportedMessageException e) {
|
||||
res = Text.create(res, atom.getFields()[0].toString());
|
||||
}
|
||||
for (int i = 1; i < atom.getFields().length; i++) {
|
||||
res = Text.create(res, " ");
|
||||
try {
|
||||
res = Text.create(res, strings.asString(displays.toDisplayString(atom.getFields()[i])));
|
||||
} catch (UnsupportedMessageException e) {
|
||||
res = Text.create(res, atom.getFields()[i].toString());
|
||||
}
|
||||
}
|
||||
res = Text.create(res, ")");
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ package org.enso.interpreter.node.expression.builtin.text;
|
||||
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
|
||||
@BuiltinMethod(type = "Text", name = "+", description = "Text concatenation.")
|
||||
public class ConcatNode extends Node {
|
||||
String execute(String _this, String that) {
|
||||
return _this + that;
|
||||
Text execute(Text _this, Text that) {
|
||||
return Text.create(_this, that);
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,12 @@ import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.runtime.builtin.LanguageEntitySerializer;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
|
||||
@BuiltinMethod(type = "Any", name = "json_serialize", description = "Generic JSON serialization.")
|
||||
public class JsonSerializeNode extends Node {
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
String execute(Object _this) {
|
||||
return LanguageEntitySerializer.serialize(_this);
|
||||
Text execute(Object _this) {
|
||||
return Text.create(LanguageEntitySerializer.serialize(_this));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package org.enso.interpreter.node.expression.builtin.text;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
|
||||
@BuiltinMethod(
|
||||
type = "Prim_Text_Helpers",
|
||||
name = "optimize",
|
||||
description = "Forces flattening of a text value, for testing or purposes.")
|
||||
public class OptimizeNode extends Node {
|
||||
private @Child ToJavaStringNode toJavaStringNode = ToJavaStringNode.build();
|
||||
|
||||
Text execute(Object _this, Text text) {
|
||||
toJavaStringNode.execute(text);
|
||||
return text;
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package org.enso.interpreter.node.expression.builtin.text;
|
||||
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import org.enso.interpreter.dsl.BuiltinMethod;
|
||||
|
||||
@BuiltinMethod(type = "Text", name = "==", description = "Equality on text.")
|
||||
public class TextEqualsNode extends Node {
|
||||
boolean execute(String _this, String that) {
|
||||
return _this.equals(that);
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package org.enso.interpreter.node.expression.builtin.text.util;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.nodes.Node;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import org.enso.interpreter.runtime.data.text.ConcatRope;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
@NodeInfo(description = "Converts Enso Text to a Java String.")
|
||||
public class ToJavaStringNode extends Node {
|
||||
private static ToJavaStringNode UNCACHED = new ToJavaStringNode();
|
||||
|
||||
/**
|
||||
* Returns the uncached version of this node.
|
||||
*
|
||||
* @return the uncached version of this node.
|
||||
*/
|
||||
public static ToJavaStringNode getUncached() {
|
||||
return UNCACHED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of this node.
|
||||
*
|
||||
* @return a new instance of this node.
|
||||
*/
|
||||
public static ToJavaStringNode build() {
|
||||
return new ToJavaStringNode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the conversion of Enso Text to a Java String.
|
||||
*
|
||||
* @param text the text to convert.
|
||||
* @return the result of conversion.
|
||||
*/
|
||||
public String execute(Text text) {
|
||||
if (text.isFlat()) {
|
||||
return (String) text.getContents();
|
||||
} else {
|
||||
return inplaceFlatten(text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts text to a Java String. For use outside of Truffle Nodes.
|
||||
*
|
||||
* @param text the text to convert.
|
||||
* @return the result of conversion.
|
||||
*/
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public static String inplaceFlatten(Text text) {
|
||||
Lock lock = text.getLock();
|
||||
lock.lock();
|
||||
String result;
|
||||
try {
|
||||
if (text.isFlat()) {
|
||||
result = (String) text.getContents();
|
||||
} else {
|
||||
result = doFlatten(text);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String doFlatten(Text text) {
|
||||
Deque<Object> workStack = new ArrayDeque<>();
|
||||
StringBuilder bldr = new StringBuilder();
|
||||
workStack.push(text.getContents());
|
||||
while (!workStack.isEmpty()) {
|
||||
Object item = workStack.pop();
|
||||
if (item instanceof String) {
|
||||
bldr.append((String) item);
|
||||
} else {
|
||||
ConcatRope rope = (ConcatRope) item;
|
||||
workStack.push(rope.getRight());
|
||||
workStack.push(rope.getLeft());
|
||||
}
|
||||
}
|
||||
String res = bldr.toString();
|
||||
text.setContents(res);
|
||||
text.setFlat(true);
|
||||
return res;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package org.enso.interpreter.node.expression.debug;
|
||||
import com.oracle.truffle.api.RootCallTarget;
|
||||
import com.oracle.truffle.api.Truffle;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.ReportPolymorphism;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import org.enso.compiler.context.InlineContext;
|
||||
@ -12,15 +13,18 @@ import org.enso.interpreter.node.BaseNode;
|
||||
import org.enso.interpreter.node.ClosureRootNode;
|
||||
import org.enso.interpreter.node.ExpressionNode;
|
||||
import org.enso.interpreter.node.callable.thunk.ThunkExecutorNode;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||
import org.enso.interpreter.runtime.callable.argument.Thunk;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.scope.LocalScope;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
import org.enso.interpreter.runtime.state.Stateful;
|
||||
|
||||
/** Node running Enso expressions passed to it as strings. */
|
||||
@NodeInfo(shortName = "Eval", description = "Evaluates code passed to it as string")
|
||||
@ReportPolymorphism
|
||||
public abstract class EvalNode extends BaseNode {
|
||||
private final boolean shouldCaptureResultScope;
|
||||
|
||||
@ -54,7 +58,7 @@ public abstract class EvalNode extends BaseNode {
|
||||
* @param expression the string containing expression to evaluate
|
||||
* @return the result of evaluating {@code expression} in the {@code callerInfo} context
|
||||
*/
|
||||
public abstract Stateful execute(CallerInfo callerInfo, Object state, String expression);
|
||||
public abstract Stateful execute(CallerInfo callerInfo, Object state, Text expression);
|
||||
|
||||
RootCallTarget parseExpression(LocalScope scope, ModuleScope moduleScope, String expression) {
|
||||
LocalScope localScope = scope.createChild();
|
||||
@ -93,11 +97,13 @@ public abstract class EvalNode extends BaseNode {
|
||||
Stateful doCached(
|
||||
CallerInfo callerInfo,
|
||||
Object state,
|
||||
String expression,
|
||||
@Cached("expression") String cachedExpression,
|
||||
Text expression,
|
||||
@Cached("expression") Text cachedExpression,
|
||||
@Cached("build()") ToJavaStringNode toJavaStringNode,
|
||||
@Cached("toJavaStringNode.execute(expression)") String expressionStr,
|
||||
@Cached("callerInfo") CallerInfo cachedCallerInfo,
|
||||
@Cached(
|
||||
"parseExpression(callerInfo.getLocalScope(), callerInfo.getModuleScope(), expression)")
|
||||
"parseExpression(callerInfo.getLocalScope(), callerInfo.getModuleScope(), expressionStr)")
|
||||
RootCallTarget cachedCallTarget,
|
||||
@Cached("build()") ThunkExecutorNode thunkExecutorNode) {
|
||||
Thunk thunk = new Thunk(cachedCallTarget, callerInfo.getFrame());
|
||||
@ -108,10 +114,14 @@ public abstract class EvalNode extends BaseNode {
|
||||
Stateful doUncached(
|
||||
CallerInfo callerInfo,
|
||||
Object state,
|
||||
String expression,
|
||||
@Cached("build()") ThunkExecutorNode thunkExecutorNode) {
|
||||
Text expression,
|
||||
@Cached("build()") ThunkExecutorNode thunkExecutorNode,
|
||||
@Cached("build()") ToJavaStringNode toJavaStringNode) {
|
||||
RootCallTarget callTarget =
|
||||
parseExpression(callerInfo.getLocalScope(), callerInfo.getModuleScope(), expression);
|
||||
parseExpression(
|
||||
callerInfo.getLocalScope(),
|
||||
callerInfo.getModuleScope(),
|
||||
toJavaStringNode.execute(expression));
|
||||
Thunk thunk = new Thunk(callTarget, callerInfo.getFrame());
|
||||
return thunkExecutorNode.executeThunk(thunk, state, isTail());
|
||||
}
|
||||
|
@ -3,14 +3,15 @@ package org.enso.interpreter.node.expression.literal;
|
||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||
import org.enso.interpreter.node.ExpressionNode;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
|
||||
/** Node representing a constant String value. */
|
||||
@NodeInfo(shortName = "StringLiteral", description = "Constant string literal expression")
|
||||
public class TextLiteralNode extends ExpressionNode {
|
||||
private final String value;
|
||||
private final Text value;
|
||||
|
||||
private TextLiteralNode(String value) {
|
||||
this.value = value;
|
||||
this.value = Text.create(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -30,7 +31,7 @@ public class TextLiteralNode extends ExpressionNode {
|
||||
* @return the string value this node was created with
|
||||
*/
|
||||
@Override
|
||||
public Object executeGeneric(VirtualFrame frame) {
|
||||
public Text executeGeneric(VirtualFrame frame) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import org.enso.interpreter.runtime.callable.CallerInfo;
|
||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.Array;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.scope.LocalScope;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
import org.enso.interpreter.runtime.type.Types;
|
||||
@ -205,10 +206,7 @@ public class Module implements TruffleObject {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create scope if it does not exist.
|
||||
*
|
||||
*/
|
||||
/** Create scope if it does not exist. */
|
||||
public void ensureScopeExists() {
|
||||
if (scope == null) {
|
||||
scope = new ModuleScope(this);
|
||||
@ -387,7 +385,7 @@ public class Module implements TruffleObject {
|
||||
CallerInfo callerInfo = new CallerInfo(null, LocalScope.root(), scope);
|
||||
Object state = context.getBuiltins().unit().newInstance();
|
||||
return callOptimiserNode
|
||||
.executeDispatch(eval, callerInfo, state, new Object[] {debug, expr})
|
||||
.executeDispatch(eval, callerInfo, state, new Object[] {debug, Text.create(expr)})
|
||||
.getValue();
|
||||
}
|
||||
|
||||
|
@ -5,18 +5,27 @@ import com.oracle.truffle.api.Truffle;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.expression.builtin.debug.DebugBreakpointMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.debug.DebugEvalMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.error.*;
|
||||
import org.enso.interpreter.node.expression.builtin.error.CatchErrorMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.error.CatchPanicMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.error.ThrowErrorMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.error.ThrowPanicMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.function.ApplicationOperatorMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.function.ExplicitCallFunctionMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.generic.*;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.MethodDispatchNode;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.java.AddToClassPathMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.java.LookupClassMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.ConstructorDispatchNode;
|
||||
import org.enso.interpreter.node.expression.builtin.io.*;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.MethodDispatchNode;
|
||||
import org.enso.interpreter.node.expression.builtin.io.PrintErrMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.io.PrintlnMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.io.ReadlnMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.runtime.GCMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.runtime.NoInlineMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.state.*;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.java.*;
|
||||
import org.enso.interpreter.node.expression.builtin.text.*;
|
||||
import org.enso.interpreter.node.expression.builtin.state.GetStateMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.state.PutStateMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.state.RunStateMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.text.AnyToTextMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.text.JsonSerializeMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.thread.WithInterruptHandlerMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.unsafe.SetAtomFieldMethodGen;
|
||||
import org.enso.interpreter.runtime.Context;
|
||||
@ -47,16 +56,13 @@ public class Builtins {
|
||||
private final AtomConstructor any;
|
||||
private final Number number;
|
||||
private final AtomConstructor function;
|
||||
private final AtomConstructor text;
|
||||
private final AtomConstructor debug;
|
||||
private final Text text;
|
||||
private final Error error;
|
||||
private final Bool bool;
|
||||
private final System system;
|
||||
private final Array array;
|
||||
|
||||
private final RootCallTarget interopDispatchRoot;
|
||||
private final FunctionSchema interopDispatchSchema;
|
||||
private final Function newInstanceFunction;
|
||||
private final Polyglot polyglot;
|
||||
|
||||
/**
|
||||
* Creates an instance with builtin methods installed.
|
||||
@ -74,10 +80,11 @@ public class Builtins {
|
||||
error = new Error(language, scope);
|
||||
array = new Array(language, scope);
|
||||
function = new AtomConstructor("Function", scope).initializeFields();
|
||||
text = new AtomConstructor("Text", scope).initializeFields();
|
||||
text = new Text(language, scope);
|
||||
debug = new AtomConstructor("Debug", scope).initializeFields();
|
||||
system = new System(language, scope);
|
||||
number = new Number(language, scope);
|
||||
polyglot = new Polyglot(language, scope);
|
||||
|
||||
AtomConstructor nil = new AtomConstructor("Nil", scope).initializeFields();
|
||||
AtomConstructor cons =
|
||||
@ -98,7 +105,6 @@ public class Builtins {
|
||||
scope.registerConstructor(unit);
|
||||
scope.registerConstructor(any);
|
||||
scope.registerConstructor(function);
|
||||
scope.registerConstructor(text);
|
||||
|
||||
scope.registerConstructor(cons);
|
||||
scope.registerConstructor(nil);
|
||||
@ -114,8 +120,6 @@ public class Builtins {
|
||||
|
||||
scope.registerConstructor(unsafe);
|
||||
|
||||
createPolyglot(language);
|
||||
|
||||
scope.registerMethod(io, "println", PrintlnMethodGen.makeFunction(language));
|
||||
scope.registerMethod(io, "print_err", PrintErrMethodGen.makeFunction(language));
|
||||
scope.registerMethod(io, "readln", ReadlnMethodGen.makeFunction(language));
|
||||
@ -138,8 +142,6 @@ public class Builtins {
|
||||
scope.registerMethod(function, "call", ExplicitCallFunctionMethodGen.makeFunction(language));
|
||||
scope.registerMethod(function, "<|", ApplicationOperatorMethodGen.makeFunction(language));
|
||||
|
||||
scope.registerMethod(text, "+", ConcatMethodGen.makeFunction(language));
|
||||
scope.registerMethod(text, "==", TextEqualsMethodGen.makeFunction(language));
|
||||
scope.registerMethod(any, "to_text", AnyToTextMethodGen.makeFunction(language));
|
||||
scope.registerMethod(any, "json_serialize", JsonSerializeMethodGen.makeFunction(language));
|
||||
|
||||
@ -151,36 +153,9 @@ public class Builtins {
|
||||
|
||||
scope.registerMethod(unsafe, "set_atom_field", SetAtomFieldMethodGen.makeFunction(language));
|
||||
|
||||
interopDispatchRoot = Truffle.getRuntime().createCallTarget(MethodDispatchNode.build(language));
|
||||
interopDispatchSchema =
|
||||
new FunctionSchema(
|
||||
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
|
||||
FunctionSchema.CallerFrameAccess.NONE,
|
||||
new ArgumentDefinition[] {
|
||||
new ArgumentDefinition(1, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
|
||||
new ArgumentDefinition(2, "method_name", ArgumentDefinition.ExecutionMode.EXECUTE),
|
||||
new ArgumentDefinition(3, "arguments", ArgumentDefinition.ExecutionMode.EXECUTE)
|
||||
},
|
||||
new boolean[] {false, true, false},
|
||||
new CallArgumentInfo[0]);
|
||||
newInstanceFunction = ConstructorDispatchNode.makeFunction(language);
|
||||
|
||||
module.unsafeBuildIrStub();
|
||||
}
|
||||
|
||||
private void createPolyglot(Language language) {
|
||||
AtomConstructor polyglot = new AtomConstructor("Polyglot", scope).initializeFields();
|
||||
scope.registerConstructor(polyglot);
|
||||
scope.registerMethod(polyglot, "execute", ExecuteMethodGen.makeFunction(language));
|
||||
scope.registerMethod(polyglot, "invoke", InvokeMethodGen.makeFunction(language));
|
||||
scope.registerMethod(polyglot, "new", InstantiateMethodGen.makeFunction(language));
|
||||
scope.registerMethod(polyglot, "get_member", GetMemberMethodGen.makeFunction(language));
|
||||
scope.registerMethod(polyglot, "get_members", GetMembersMethodGen.makeFunction(language));
|
||||
scope.registerMethod(polyglot, "get_array_size", GetArraySizeMethodGen.makeFunction(language));
|
||||
scope.registerMethod(
|
||||
polyglot, "get_array_element", GetArrayElementMethodGen.makeFunction(language));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code Unit} atom constructor.
|
||||
*
|
||||
@ -191,11 +166,11 @@ public class Builtins {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code Text} atom constructor.
|
||||
* Returns the {@code Text} part of builtins.
|
||||
*
|
||||
* @return the {@code Text} atom constructor
|
||||
* @return the {@code Text} part of builtins.
|
||||
*/
|
||||
public AtomConstructor text() {
|
||||
public Text text() {
|
||||
return text;
|
||||
}
|
||||
|
||||
@ -255,6 +230,11 @@ public class Builtins {
|
||||
return array;
|
||||
}
|
||||
|
||||
/** @return the container for polyglot-related builtins. */
|
||||
public Polyglot polyglot() {
|
||||
return polyglot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the builtin module scope.
|
||||
*
|
||||
@ -267,20 +247,4 @@ public class Builtins {
|
||||
public Module getModule() {
|
||||
return module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a function dispatching to a polyglot method call.
|
||||
*
|
||||
* @param method the name and scope of the method this function will dispatch to.
|
||||
* @return a function calling {@code method} with given arguments.
|
||||
*/
|
||||
public Function buildPolyglotMethodDispatch(UnresolvedSymbol method) {
|
||||
Object[] preAppliedArr = new Object[] {null, method, null};
|
||||
return new Function(interopDispatchRoot, null, interopDispatchSchema, preAppliedArr, null);
|
||||
}
|
||||
|
||||
/** @return a function executing a constructor with given arguments. */
|
||||
public Function getConstructorDispatch() {
|
||||
return newInstanceFunction;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
package org.enso.interpreter.runtime.builtin;
|
||||
|
||||
import com.oracle.truffle.api.RootCallTarget;
|
||||
import com.oracle.truffle.api.Truffle;
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.generic.*;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.*;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.GetArrayElementMethodGen;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.callable.argument.ArgumentDefinition;
|
||||
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
|
||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.callable.function.FunctionSchema;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
|
||||
/** A container class for all Polyglot-related stdlib builtins. */
|
||||
public class Polyglot {
|
||||
|
||||
private final RootCallTarget interopDispatchRoot;
|
||||
private final FunctionSchema interopDispatchSchema;
|
||||
private final Function newInstanceFunction;
|
||||
private final Function polyglotArrayLengthFunction;
|
||||
private final Function polyglotArrayAtFunction;
|
||||
private final Function polyglotToTextFunction;
|
||||
|
||||
/**
|
||||
* Creates and registers all polyglot-related functions and types.
|
||||
*
|
||||
* @param language the current language instance.
|
||||
* @param scope the builtin scope.
|
||||
*/
|
||||
public Polyglot(Language language, ModuleScope scope) {
|
||||
|
||||
// Note [Syntactic Functions]
|
||||
interopDispatchRoot = Truffle.getRuntime().createCallTarget(MethodDispatchNode.build(language));
|
||||
interopDispatchSchema =
|
||||
new FunctionSchema(
|
||||
FunctionSchema.CallStrategy.ALWAYS_DIRECT,
|
||||
FunctionSchema.CallerFrameAccess.NONE,
|
||||
new ArgumentDefinition[] {
|
||||
new ArgumentDefinition(1, "this", ArgumentDefinition.ExecutionMode.EXECUTE),
|
||||
new ArgumentDefinition(2, "method_name", ArgumentDefinition.ExecutionMode.EXECUTE),
|
||||
new ArgumentDefinition(3, "arguments", ArgumentDefinition.ExecutionMode.EXECUTE)
|
||||
},
|
||||
new boolean[] {false, true, false},
|
||||
new CallArgumentInfo[0]);
|
||||
newInstanceFunction = ConstructorDispatchNode.makeFunction(language);
|
||||
polyglotArrayAtFunction = GetArrayElementMethodGen.makeFunction(language);
|
||||
polyglotArrayLengthFunction = ArrayLengthMethodGen.makeFunction(language);
|
||||
polyglotToTextFunction = PolyglotToTextMethodGen.makeFunction(language);
|
||||
|
||||
createPolyglot(language, scope);
|
||||
}
|
||||
|
||||
/* Note [Syntactic Functions]
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* Certain functions in this module (ones that are not being directly registered in the scope)
|
||||
* are not parts of the standard library. Instead, they are used by the method dispatch system
|
||||
* to call into functionality of polyglot objects. As such, they are represented as Enso-level
|
||||
* functions, but they are not directly accessible through the standard library.
|
||||
*/
|
||||
|
||||
private void createPolyglot(Language language, ModuleScope scope) {
|
||||
AtomConstructor polyglot = new AtomConstructor("Polyglot", scope).initializeFields();
|
||||
scope.registerConstructor(polyglot);
|
||||
scope.registerMethod(polyglot, "execute", ExecuteMethodGen.makeFunction(language));
|
||||
scope.registerMethod(polyglot, "invoke", InvokeMethodGen.makeFunction(language));
|
||||
scope.registerMethod(polyglot, "new", InstantiateMethodGen.makeFunction(language));
|
||||
scope.registerMethod(polyglot, "get_member", GetMemberMethodGen.makeFunction(language));
|
||||
scope.registerMethod(polyglot, "get_members", GetMembersMethodGen.makeFunction(language));
|
||||
}
|
||||
|
||||
/*
|
||||
* Builds a function dispatching to a polyglot method call.
|
||||
*
|
||||
* @param method the name and scope of the method this function will dispatch to.
|
||||
* @return a function calling {@code method} with given arguments.
|
||||
*/
|
||||
public Function buildPolyglotMethodDispatch(UnresolvedSymbol method) {
|
||||
Object[] preAppliedArr = new Object[] {null, method, null};
|
||||
return new Function(interopDispatchRoot, null, interopDispatchSchema, preAppliedArr, null);
|
||||
}
|
||||
|
||||
/** @return a function taking a polyglot array and returning its length. */
|
||||
public Function getPolyglotArrayLengthFunction() {
|
||||
return polyglotArrayLengthFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a function taking a polyglot array and an index and accessing the item at the given
|
||||
* index.
|
||||
*/
|
||||
public Function getPolyglotArrayAtFunction() {
|
||||
return polyglotArrayAtFunction;
|
||||
}
|
||||
|
||||
/** @return a function taking a polyglot object and displaying it as a human-readable string. */
|
||||
public Function getPolyglotToTextFunction() {
|
||||
return polyglotToTextFunction;
|
||||
}
|
||||
|
||||
/** @return a function executing a constructor with given arguments. */
|
||||
public Function getConstructorDispatch() {
|
||||
return newInstanceFunction;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.enso.interpreter.runtime.builtin;
|
||||
|
||||
import org.enso.interpreter.Language;
|
||||
import org.enso.interpreter.node.expression.builtin.text.ConcatMethodGen;
|
||||
import org.enso.interpreter.node.expression.builtin.text.OptimizeMethodGen;
|
||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
|
||||
/** A container class for all Text-related stdlib builtins. */
|
||||
public class Text {
|
||||
private final AtomConstructor text;
|
||||
|
||||
/**
|
||||
* Creates and registers all the text constructors and methods.
|
||||
*
|
||||
* @param language the current language instance.
|
||||
* @param scope the scope to register constructors and methods in.
|
||||
*/
|
||||
public Text(Language language, ModuleScope scope) {
|
||||
text = new AtomConstructor("Text", scope).initializeFields();
|
||||
scope.registerConstructor(text);
|
||||
AtomConstructor primTextHelpers =
|
||||
new AtomConstructor("Prim_Text_Helper", scope).initializeFields();
|
||||
scope.registerConstructor(primTextHelpers);
|
||||
|
||||
scope.registerMethod(text, "+", ConcatMethodGen.makeFunction(language));
|
||||
scope.registerMethod(primTextHelpers, "optimize", OptimizeMethodGen.makeFunction(language));
|
||||
}
|
||||
|
||||
/** @return the Text atom constructor. */
|
||||
public AtomConstructor getText() {
|
||||
return text;
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import com.oracle.truffle.api.library.ExportLibrary;
|
||||
import com.oracle.truffle.api.library.ExportMessage;
|
||||
import org.enso.interpreter.Constants;
|
||||
import org.enso.interpreter.node.callable.MethodResolverNode;
|
||||
import org.enso.interpreter.node.expression.builtin.interop.syntax.HostValueToEnsoNode;
|
||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.scope.ModuleScope;
|
||||
@ -99,11 +100,16 @@ public class UnresolvedSymbol implements TruffleObject {
|
||||
UnresolvedSymbol symbol,
|
||||
Object[] arguments,
|
||||
@Cached MethodResolverNode methodResolverNode,
|
||||
@Cached HostValueToEnsoNode hostValueToEnsoNode,
|
||||
@CachedLibrary(limit = "BUILTIN_INTEROP_DISPATCH") InteropLibrary library)
|
||||
throws ArityException, UnsupportedTypeException, UnsupportedMessageException {
|
||||
Object[] args = new Object[arguments.length];
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
args[i] = hostValueToEnsoNode.execute(arguments[i]);
|
||||
}
|
||||
if (arguments.length == 0) throw ArityException.create(1, 0);
|
||||
Function function = methodResolverNode.execute(symbol, arguments[0]);
|
||||
return library.execute(function, arguments);
|
||||
Function function = methodResolverNode.execute(symbol, args[0]);
|
||||
return library.execute(function, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,23 @@ package org.enso.interpreter.runtime.callable.atom;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives;
|
||||
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.TruffleObject;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.interop.*;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import com.oracle.truffle.api.library.ExportLibrary;
|
||||
import com.oracle.truffle.api.library.ExportMessage;
|
||||
import com.oracle.truffle.api.nodes.UnexpectedResultException;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
import org.enso.interpreter.runtime.callable.UnresolvedSymbol;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.Array;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.type.TypesGen;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** A runtime representation of an Atom in Enso. */
|
||||
@ -84,14 +95,65 @@ public class Atom implements TruffleObject {
|
||||
return toString(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a human-readable string representation of this atom.
|
||||
*
|
||||
* @param allowSideEffects whether or not to allow side effects in displaying the string
|
||||
* @return a string representation of this atom
|
||||
*/
|
||||
@ExportMessage
|
||||
public Object toDisplayString(boolean allowSideEffects) {
|
||||
return this.toString();
|
||||
public boolean hasMembers() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public Array getMembers(boolean includeInternal) {
|
||||
Map<String, Function> members = constructor.getDefinitionScope().getMethods().get(constructor);
|
||||
if (members == null) {
|
||||
return new Array(0);
|
||||
}
|
||||
Object[] mems = members.keySet().toArray();
|
||||
return new Array(mems);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
@CompilerDirectives.TruffleBoundary
|
||||
public boolean isMemberInvocable(String member) {
|
||||
Map<String, ?> members = constructor.getDefinitionScope().getMethods().get(constructor);
|
||||
return members != null && members.containsKey(member);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
static class InvokeMember {
|
||||
static UnresolvedSymbol buildSym(AtomConstructor cons, String name) {
|
||||
return UnresolvedSymbol.build(name, cons.getDefinitionScope());
|
||||
}
|
||||
|
||||
@Specialization(
|
||||
guards = {"receiver.getConstructor() == cachedConstructor", "member.equals(cachedMember)"})
|
||||
static Object doCached(
|
||||
Atom receiver,
|
||||
String member,
|
||||
Object[] arguments,
|
||||
@Cached(value = "receiver.getConstructor()", allowUncached = true)
|
||||
AtomConstructor cachedConstructor,
|
||||
@Cached(value = "member", allowUncached = true) String cachedMember,
|
||||
@Cached(value = "buildSym(cachedConstructor, cachedMember)", allowUncached = true)
|
||||
UnresolvedSymbol cachedSym,
|
||||
@CachedLibrary("cachedSym") InteropLibrary symbols)
|
||||
throws UnsupportedMessageException, ArityException, UnsupportedTypeException {
|
||||
Object[] args = new Object[arguments.length + 1];
|
||||
args[0] = receiver;
|
||||
System.arraycopy(arguments, 0, args, 1, arguments.length);
|
||||
return symbols.execute(cachedSym, args);
|
||||
}
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
Text toDisplayString(boolean allowSideEffects, @CachedLibrary("this") InteropLibrary atoms) {
|
||||
try {
|
||||
return TypesGen.expectText(atoms.invokeMember(this, "to_text"));
|
||||
} catch (UnsupportedMessageException
|
||||
| ArityException
|
||||
| UnknownIdentifierException
|
||||
| UnsupportedTypeException
|
||||
| UnexpectedResultException e) {
|
||||
return Text.create(this.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
package org.enso.interpreter.runtime.data.text;
|
||||
|
||||
/** Represents a concatenation of two text values. */
|
||||
public class ConcatRope {
|
||||
private final Object left;
|
||||
private final Object right;
|
||||
|
||||
/**
|
||||
* Creates a new rope concatenating the arguments.
|
||||
*
|
||||
* @param left the left operand
|
||||
* @param right the right operand
|
||||
*/
|
||||
public ConcatRope(Object left, Object right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
/** @return the left operand of this concatenation. */
|
||||
public Object getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
/** @return the right operand of this concatenation. */
|
||||
public Object getRight() {
|
||||
return right;
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package org.enso.interpreter.runtime.data.text;
|
||||
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
import com.oracle.truffle.api.interop.TruffleObject;
|
||||
import com.oracle.truffle.api.library.ExportLibrary;
|
||||
import com.oracle.truffle.api.library.ExportMessage;
|
||||
import org.enso.interpreter.node.expression.builtin.text.util.ToJavaStringNode;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/** The main runtime type for Enso's Text. */
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
public class Text implements TruffleObject {
|
||||
private volatile Object contents;
|
||||
private volatile boolean isFlat;
|
||||
private final Lock lock = new ReentrantLock();
|
||||
|
||||
private Text(String string) {
|
||||
this.contents = string;
|
||||
this.isFlat = true;
|
||||
}
|
||||
|
||||
private Text(ConcatRope contents) {
|
||||
this.contents = contents;
|
||||
this.isFlat = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a string in an instance of Text.
|
||||
*
|
||||
* @param string the string to wrap.
|
||||
* @return a Text corresponding to the original string.
|
||||
*/
|
||||
public static Text create(String string) {
|
||||
return new Text(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Text by concatenating two other texts.
|
||||
*
|
||||
* @param t1 the left operand.
|
||||
* @param t2 the right operand.
|
||||
* @return a Text representing concatenation of t1 and t2.
|
||||
*/
|
||||
public static Text create(Text t1, Text t2) {
|
||||
return new Text(new ConcatRope(t1.contents, t2.contents));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Text by concatenating a text and a string.
|
||||
*
|
||||
* @param t1 the left operand.
|
||||
* @param t2 the right operand.
|
||||
* @return a Text representing concatenation of t1 and t2.
|
||||
*/
|
||||
public static Text create(Text t1, String t2) {
|
||||
return new Text(new ConcatRope(t1.contents, t2));
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
boolean isString() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
String asString(@Cached("build()") @Cached.Shared("strings") ToJavaStringNode toJavaStringNode) {
|
||||
return toJavaStringNode.execute(this);
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
String toDisplayString(
|
||||
boolean allowSideEffects,
|
||||
@Cached("build()") @Cached.Shared("strings") ToJavaStringNode toJavaStringNode) {
|
||||
String str = toJavaStringNode.execute(this);
|
||||
// TODO This should be more extensible
|
||||
String replaced =
|
||||
str.replace("'", "\\'")
|
||||
.replace("\n", "\\n")
|
||||
.replace("\t", "\\t")
|
||||
.replace("\u0007", "\\a")
|
||||
.replace("\u0008", "\\b")
|
||||
.replace("\u000c", "\\f")
|
||||
.replace("\r", "\\r")
|
||||
.replace("\u000B", "\\v")
|
||||
.replace("\u001B", "\\e");
|
||||
return "'" + replaced + "'";
|
||||
}
|
||||
|
||||
/** @return true if this text wraps a string literal and does not require any optimization. */
|
||||
public boolean isFlat() {
|
||||
return isFlat;
|
||||
}
|
||||
|
||||
/** @param flat the new value of the isFlat flag. */
|
||||
public void setFlat(boolean flat) {
|
||||
isFlat = flat;
|
||||
}
|
||||
|
||||
/** @return the contents of this text. */
|
||||
public Object getContents() {
|
||||
return contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the contents of this text.
|
||||
*
|
||||
* @param contents the new contents.
|
||||
*/
|
||||
public void setContents(Object contents) {
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
/** @return the lock required for modification of this text. */
|
||||
public Lock getLock() {
|
||||
return lock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isFlat) {
|
||||
return (String) this.contents;
|
||||
} else {
|
||||
return ToJavaStringNode.inplaceFlatten(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,14 @@
|
||||
package org.enso.interpreter.runtime.error;
|
||||
|
||||
import com.oracle.truffle.api.interop.TruffleObject;
|
||||
import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
||||
import com.oracle.truffle.api.library.CachedLibrary;
|
||||
import com.oracle.truffle.api.library.ExportLibrary;
|
||||
import com.oracle.truffle.api.library.ExportMessage;
|
||||
import com.oracle.truffle.api.interop.InteropLibrary;
|
||||
|
||||
/** A runtime object representing an arbitrary, user-created error. */
|
||||
@ExportLibrary(InteropLibrary.class)
|
||||
public class RuntimeError implements TruffleObject {
|
||||
private final Object payload;
|
||||
|
||||
@ -33,4 +39,16 @@ public class RuntimeError implements TruffleObject {
|
||||
public String toString() {
|
||||
return "Error:" + getPayload().toString();
|
||||
}
|
||||
|
||||
@ExportMessage
|
||||
public String toDisplayString(
|
||||
boolean allowSideEffects,
|
||||
@CachedLibrary(limit = "3") InteropLibrary displays,
|
||||
@CachedLibrary(limit = "3") InteropLibrary strings) {
|
||||
try {
|
||||
return "(Error: " + strings.asString(displays.toDisplayString(payload)) + ")";
|
||||
} catch (UnsupportedMessageException e) {
|
||||
return "Error";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import org.enso.interpreter.runtime.callable.atom.Atom;
|
||||
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
|
||||
import org.enso.interpreter.runtime.callable.function.Function;
|
||||
import org.enso.interpreter.runtime.data.Array;
|
||||
import org.enso.interpreter.runtime.data.text.Text;
|
||||
import org.enso.interpreter.runtime.error.RuntimeError;
|
||||
import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
|
||||
@ -28,7 +29,7 @@ import org.enso.interpreter.runtime.number.EnsoBigInteger;
|
||||
long.class,
|
||||
boolean.class,
|
||||
double.class,
|
||||
String.class,
|
||||
Text.class,
|
||||
Function.class,
|
||||
Atom.class,
|
||||
AtomConstructor.class,
|
||||
@ -109,7 +110,7 @@ public class Types {
|
||||
return "Number";
|
||||
} else if (TypesGen.isBoolean(value)) {
|
||||
return "Boolean";
|
||||
} else if (TypesGen.isString(value)) {
|
||||
} else if (TypesGen.isText(value)) {
|
||||
return "Text";
|
||||
} else if (TypesGen.isFunction(value)) {
|
||||
return "Function";
|
||||
|
@ -1,5 +1,7 @@
|
||||
package org.enso.compiler.codegen
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
import cats.Foldable
|
||||
import cats.implicits._
|
||||
import org.enso.compiler.core.IR
|
||||
@ -7,8 +9,17 @@ import org.enso.compiler.core.IR.Name.MethodReference
|
||||
import org.enso.compiler.core.IR._
|
||||
import org.enso.compiler.exception.UnhandledEntity
|
||||
import org.enso.syntax.text.AST
|
||||
import org.enso.syntax.text.Shape.{
|
||||
SegmentEscape,
|
||||
SegmentExpr,
|
||||
SegmentPlain,
|
||||
SegmentRawEscape
|
||||
}
|
||||
import org.enso.syntax.text.ast.text.Escape
|
||||
import org.enso.syntax.text.ast.text.Escape.Unicode
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.util.control.Breaks.{break, breakable}
|
||||
|
||||
/**
|
||||
* This file contains the functionality that translates from the parser's
|
||||
@ -480,16 +491,22 @@ object AstToIr {
|
||||
.mkString("\n")
|
||||
|
||||
Literal.Text(fullString, getIdentifiedLocation(literal))
|
||||
case AST.Literal.Text.Block.Fmt(_, _, _) =>
|
||||
Error.Syntax(
|
||||
literal,
|
||||
Error.Syntax.UnsupportedSyntax("format strings")
|
||||
)
|
||||
case AST.Literal.Text.Line.Fmt(_) =>
|
||||
Error.Syntax(
|
||||
literal,
|
||||
Error.Syntax.UnsupportedSyntax("format strings")
|
||||
)
|
||||
case AST.Literal.Text.Block.Fmt(lines, _, _) =>
|
||||
val ls = lines.map(l => parseFmtSegments(literal, l.text))
|
||||
val err = ls.collectFirst { case Left(e) => e }
|
||||
err match {
|
||||
case Some(err) => err
|
||||
case None =>
|
||||
val str = ls.collect { case Right(str) => str }.mkString("\n")
|
||||
IR.Literal.Text(str, getIdentifiedLocation(literal))
|
||||
}
|
||||
case AST.Literal.Text.Line.Fmt(segments) =>
|
||||
parseFmtSegments(literal, segments) match {
|
||||
case Left(err) => err
|
||||
case Right(str) =>
|
||||
IR.Literal.Text(str, getIdentifiedLocation(literal))
|
||||
}
|
||||
|
||||
case _ =>
|
||||
throw new UnhandledEntity(literal.shape, "translateLiteral")
|
||||
}
|
||||
@ -497,6 +514,70 @@ object AstToIr {
|
||||
}
|
||||
}
|
||||
|
||||
private def parseFmtSegments(
|
||||
literal: AST,
|
||||
segments: Seq[AST.Literal.Text.Segment[AST]]
|
||||
): Either[IR.Error, String] = {
|
||||
val bldr = new StringBuilder
|
||||
var err: Option[IR.Error] = None
|
||||
breakable {
|
||||
segments.foreach {
|
||||
case SegmentEscape(code) =>
|
||||
code match {
|
||||
case Escape.Number(_) =>
|
||||
err = Some(
|
||||
Error.Syntax(
|
||||
literal,
|
||||
Error.Syntax.UnsupportedSyntax("escaped numbers")
|
||||
)
|
||||
)
|
||||
break()
|
||||
case unicode: Escape.Unicode =>
|
||||
unicode match {
|
||||
case Unicode.InvalidUnicode(unicode) =>
|
||||
err = Some(
|
||||
Error.Syntax(
|
||||
literal,
|
||||
Error.Syntax.InvalidEscapeSequence(unicode.repr)
|
||||
)
|
||||
)
|
||||
break()
|
||||
case Unicode._U16(digits) =>
|
||||
val buffer = ByteBuffer.allocate(2)
|
||||
buffer.putChar(
|
||||
Integer.parseInt(digits, 16).asInstanceOf[Char]
|
||||
)
|
||||
val str = new String(buffer.array(), "UTF-16")
|
||||
bldr.addAll(str)
|
||||
case Unicode._U32(digits) =>
|
||||
val buffer = ByteBuffer.allocate(4)
|
||||
buffer.putInt(Integer.parseInt(digits, 16))
|
||||
val str = new String(buffer.array(), "UTF-32")
|
||||
bldr.addAll(str)
|
||||
case Unicode._U21(digits) =>
|
||||
val buffer = ByteBuffer.allocate(4)
|
||||
buffer.putInt(Integer.parseInt(digits, 16))
|
||||
val str = new String(buffer.array(), "UTF-32")
|
||||
bldr.addAll(str)
|
||||
}
|
||||
case e: Escape.Character => bldr.addOne(e.code)
|
||||
case e: Escape.Control => bldr.addAll(e.repr)
|
||||
}
|
||||
case SegmentPlain(text) => bldr.addAll(text)
|
||||
case SegmentExpr(_) =>
|
||||
err = Some(
|
||||
Error.Syntax(
|
||||
literal,
|
||||
Error.Syntax.UnsupportedSyntax("interpolated expressions")
|
||||
)
|
||||
)
|
||||
break()
|
||||
case SegmentRawEscape(e) => bldr.addAll(e.repr)
|
||||
}
|
||||
}
|
||||
err.map(Left(_)).getOrElse(Right(bldr.toString))
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a sequence literal into its [[IR]] counterpart.
|
||||
* @param literal the literal to translate
|
||||
|
@ -65,6 +65,7 @@ import org.enso.interpreter.runtime.callable.function.{
|
||||
FunctionSchema,
|
||||
Function => RuntimeFunction
|
||||
}
|
||||
import org.enso.interpreter.runtime.data.text.Text
|
||||
import org.enso.interpreter.runtime.error.DuplicateArgumentNameException
|
||||
import org.enso.interpreter.runtime.scope.{LocalScope, ModuleScope}
|
||||
import org.enso.interpreter.{Constants, Language}
|
||||
@ -533,8 +534,10 @@ class IrToTruffle(
|
||||
.error()
|
||||
.syntaxError()
|
||||
.newInstance(
|
||||
Text.create(
|
||||
"Type operators are not currently supported at runtime."
|
||||
)
|
||||
)
|
||||
),
|
||||
value.location
|
||||
)
|
||||
@ -573,7 +576,7 @@ class IrToTruffle(
|
||||
val error = context.getBuiltins
|
||||
.error()
|
||||
.compileError()
|
||||
.newInstance(message)
|
||||
.newInstance(Text.create(message))
|
||||
|
||||
setLocation(ErrorNode.build(error), caseExpr.location)
|
||||
}
|
||||
@ -884,19 +887,40 @@ class IrToTruffle(
|
||||
case Error.InvalidIR(_, _, _) =>
|
||||
throw new CompilerError("Unexpected Invalid IR during codegen.")
|
||||
case err: Error.Syntax =>
|
||||
context.getBuiltins.error().syntaxError().newInstance(err.message)
|
||||
context.getBuiltins
|
||||
.error()
|
||||
.syntaxError()
|
||||
.newInstance(Text.create(err.message))
|
||||
case err: Error.Redefined.Binding =>
|
||||
context.getBuiltins.error().compileError().newInstance(err.message)
|
||||
context.getBuiltins
|
||||
.error()
|
||||
.compileError()
|
||||
.newInstance(Text.create(err.message))
|
||||
case err: Error.Redefined.Method =>
|
||||
context.getBuiltins.error().compileError().newInstance(err.message)
|
||||
context.getBuiltins
|
||||
.error()
|
||||
.compileError()
|
||||
.newInstance(Text.create(err.message))
|
||||
case err: Error.Redefined.Atom =>
|
||||
context.getBuiltins.error().compileError().newInstance(err.message)
|
||||
context.getBuiltins
|
||||
.error()
|
||||
.compileError()
|
||||
.newInstance(Text.create(err.message))
|
||||
case err: Error.Redefined.ThisArg =>
|
||||
context.getBuiltins.error().compileError().newInstance(err.message)
|
||||
context.getBuiltins
|
||||
.error()
|
||||
.compileError()
|
||||
.newInstance(Text.create(err.message))
|
||||
case err: Error.Unexpected.TypeSignature =>
|
||||
context.getBuiltins.error().compileError().newInstance(err.message)
|
||||
context.getBuiltins
|
||||
.error()
|
||||
.compileError()
|
||||
.newInstance(Text.create(err.message))
|
||||
case err: Error.Resolution =>
|
||||
context.getBuiltins.error().compileError().newInstance(err.message)
|
||||
context.getBuiltins
|
||||
.error()
|
||||
.compileError()
|
||||
.newInstance(Text.create(err.message))
|
||||
case _: Error.Pattern =>
|
||||
throw new CompilerError(
|
||||
"Impossible here, should be handled in the pattern match."
|
||||
@ -1064,8 +1088,10 @@ class IrToTruffle(
|
||||
.error()
|
||||
.syntaxError()
|
||||
.newInstance(
|
||||
Text.create(
|
||||
"Typeset literals are not yet supported at runtime."
|
||||
)
|
||||
)
|
||||
),
|
||||
application.location
|
||||
)
|
||||
|
@ -5570,6 +5570,10 @@ object IR {
|
||||
def explanation: String
|
||||
}
|
||||
|
||||
case class InvalidEscapeSequence(lit: String) extends Reason {
|
||||
override def explanation: String = s"Invalid escape sequence $lit."
|
||||
}
|
||||
|
||||
case object InvalidBaseInDecimalLiteral extends Reason {
|
||||
override def explanation: String =
|
||||
"Cannot change base of the fractional part of a number literal."
|
||||
|
@ -99,7 +99,7 @@ case object VectorLiterals extends IRPass {
|
||||
case seq: IR.Application.Literal.Sequence =>
|
||||
val trans = seq.mapExpressions(doExpression(_, vec))
|
||||
IR.Application.Prefix(
|
||||
vec,
|
||||
vec.duplicate(),
|
||||
List(IR.CallArgument.Specified(None, trans, None, None)),
|
||||
false,
|
||||
None
|
||||
|
@ -24,6 +24,7 @@ import org.enso.interpreter.instrument.{
|
||||
Visualisation
|
||||
}
|
||||
import org.enso.interpreter.node.callable.FunctionCallInstrumentationNode.FunctionCall
|
||||
import org.enso.interpreter.runtime.data.text.Text
|
||||
import org.enso.interpreter.service.error.ServiceException
|
||||
import org.enso.polyglot.runtime.Runtime.Api
|
||||
import org.enso.polyglot.runtime.Runtime.Api.ContextId
|
||||
@ -301,6 +302,7 @@ trait ProgramExecutionSupport {
|
||||
.leftMap(_.getMessage)
|
||||
.flatMap {
|
||||
case text: String => Right(text.getBytes("UTF-8"))
|
||||
case text: Text => Right(text.toString.getBytes("UTF-8"))
|
||||
case bytes: Array[Byte] => Right(bytes)
|
||||
case other =>
|
||||
Left(s"Cannot encode ${other.getClass} to byte array")
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.enso.interpreter.runtime.builtin
|
||||
|
||||
import com.oracle.truffle.api.interop.InteropLibrary
|
||||
import io.circe.Json
|
||||
import org.enso.interpreter.runtime.callable.atom.{Atom, AtomConstructor}
|
||||
|
||||
@ -7,6 +8,7 @@ import org.enso.interpreter.runtime.callable.atom.{Atom, AtomConstructor}
|
||||
* Helper for JSON-serializing runtime entities of the language.
|
||||
*/
|
||||
object LanguageEntitySerializer {
|
||||
private val interopLibrary: InteropLibrary = InteropLibrary.getUncached()
|
||||
|
||||
/**
|
||||
* Serializes a language entity into a JSON string. Returns null JSON for
|
||||
@ -20,7 +22,6 @@ object LanguageEntitySerializer {
|
||||
|
||||
private def toJson(obj: Any): Json = obj match {
|
||||
case l: Long => Json.fromLong(l)
|
||||
case s: String => Json.fromString(s)
|
||||
case cons: AtomConstructor =>
|
||||
Json.obj("type" -> Json.fromString(cons.getName), "fields" -> Json.arr())
|
||||
case atom: Atom =>
|
||||
@ -28,6 +29,11 @@ object LanguageEntitySerializer {
|
||||
"type" -> Json.fromString(atom.getConstructor.getName),
|
||||
"fields" -> Json.arr(atom.getFields.map(toJson).toIndexedSeq: _*)
|
||||
)
|
||||
case _ => Json.Null
|
||||
case _ =>
|
||||
if (interopLibrary.isString(obj)) {
|
||||
Json.fromString(interopLibrary.asString(obj))
|
||||
} else {
|
||||
Json.Null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class CompileDiagnosticsTest extends InterpreterTest {
|
||||
| x = Panic.recover @
|
||||
| x.catch to_text
|
||||
|""".stripMargin
|
||||
eval(code) shouldEqual "Syntax_Error Unrecognized token."
|
||||
eval(code) shouldEqual "(Syntax_Error 'Unrecognized token.')"
|
||||
}
|
||||
|
||||
"surface redefinition errors in the language" in {
|
||||
@ -42,7 +42,7 @@ class CompileDiagnosticsTest extends InterpreterTest {
|
||||
|
|
||||
|main = Panic.recover here.foo . catch to_text
|
||||
|""".stripMargin
|
||||
eval(code) shouldEqual "Compile_Error Variable x is being redefined."
|
||||
eval(code) shouldEqual "(Compile_Error 'Variable x is being redefined.')"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class ErrorsTest extends InterpreterTest {
|
||||
|""".stripMargin
|
||||
|
||||
noException shouldBe thrownBy(eval(code))
|
||||
consumeOut shouldEqual List("Error:MyError")
|
||||
consumeOut shouldEqual List("(Error: MyError)")
|
||||
}
|
||||
|
||||
"propagate through pattern matches" in {
|
||||
@ -64,7 +64,7 @@ class ErrorsTest extends InterpreterTest {
|
||||
| IO.println matched
|
||||
|""".stripMargin
|
||||
noException shouldBe thrownBy(eval(code))
|
||||
consumeOut shouldEqual List("Error:MyError")
|
||||
consumeOut shouldEqual List("(Error: MyError)")
|
||||
}
|
||||
|
||||
"propagate through specialized pattern matches" in {
|
||||
@ -83,7 +83,7 @@ class ErrorsTest extends InterpreterTest {
|
||||
| IO.println (f brokenVal)
|
||||
|""".stripMargin
|
||||
noException shouldBe thrownBy(eval(code))
|
||||
consumeOut shouldEqual List("1", "Error:MyError")
|
||||
consumeOut shouldEqual List("1", "(Error: MyError)")
|
||||
}
|
||||
|
||||
"be catchable by a user-provided special handling function" in {
|
||||
@ -108,7 +108,7 @@ class ErrorsTest extends InterpreterTest {
|
||||
| IO.println (unitErr.catch MyCons)
|
||||
|""".stripMargin
|
||||
eval(code)
|
||||
consumeOut shouldEqual List("MyCons Unit")
|
||||
consumeOut shouldEqual List("(MyCons Unit)")
|
||||
}
|
||||
|
||||
"accept a method handle in catch function" in {
|
||||
@ -126,7 +126,7 @@ class ErrorsTest extends InterpreterTest {
|
||||
| IO.println(myErr.catch recover)
|
||||
|""".stripMargin
|
||||
eval(code)
|
||||
consumeOut shouldEqual List("MyRecovered 20")
|
||||
consumeOut shouldEqual List("(MyRecovered 20)")
|
||||
}
|
||||
|
||||
"make the catch method an identity for non-error values" in {
|
||||
|
@ -46,7 +46,7 @@ class EvalTest extends InterpreterTest {
|
||||
| IO.println (MyType x)
|
||||
|""".stripMargin
|
||||
eval(code)
|
||||
consumeOut shouldEqual List("MyType 10")
|
||||
consumeOut shouldEqual List("(MyType 10)")
|
||||
}
|
||||
|
||||
"return a value usable in the caller scope" in {
|
||||
|
@ -74,7 +74,7 @@ class InteropTest extends InterpreterTest {
|
||||
val code = "main = to_text"
|
||||
val symbol = eval(code)
|
||||
symbol.call(1) shouldEqual "1"
|
||||
symbol.execute("Foo") shouldEqual "Foo"
|
||||
symbol.execute("Foo") shouldEqual "'Foo'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ class NamedArgumentsTest extends InterpreterTest {
|
||||
|main = Cons2 5
|
||||
|""".stripMargin
|
||||
|
||||
eval(code).toString shouldEqual "Cons2 5 Nil2"
|
||||
eval(code).toString shouldEqual "(Cons2 5 Nil2)"
|
||||
}
|
||||
|
||||
"work with constructors" in {
|
||||
|
@ -42,10 +42,10 @@ class PolyglotTest extends InterpreterTest {
|
||||
| class = Java.lookup_class "org.enso.example.TestClass"
|
||||
| instance = Polyglot.new class Array.empty
|
||||
| members = Polyglot.get_members instance
|
||||
| IO.println (Polyglot.get_array_size members)
|
||||
| IO.println (Polyglot.get_array_element members 0)
|
||||
| IO.println (Polyglot.get_array_element members 1)
|
||||
| IO.println (Polyglot.get_array_element members 2)
|
||||
| IO.println members.length
|
||||
| IO.println (members.at 0)
|
||||
| IO.println (members.at 1)
|
||||
| IO.println (members.at 2)
|
||||
|""".stripMargin
|
||||
eval(code)
|
||||
val count :: methods = consumeOut
|
||||
|
@ -1,12 +1,12 @@
|
||||
package org.enso.interpreter.test.semantic
|
||||
|
||||
import org.enso.interpreter.test.{InterpreterTest, InterpreterContext}
|
||||
import org.enso.interpreter.test.{InterpreterContext, InterpreterTest}
|
||||
|
||||
class TextTest extends InterpreterTest {
|
||||
override def subject = "Text Library"
|
||||
|
||||
override def specify(
|
||||
implicit interpreterContext: InterpreterContext
|
||||
override def specify(implicit
|
||||
interpreterContext: InterpreterContext
|
||||
): Unit = {
|
||||
|
||||
"support text creation with single-line literals" in {
|
||||
@ -40,12 +40,12 @@ class TextTest extends InterpreterTest {
|
||||
|type My_Type a
|
||||
|
|
||||
|main =
|
||||
| IO.println 5.to_text
|
||||
| IO.println (My_Type (My_Type 10)).to_text
|
||||
| IO.println "123".to_text
|
||||
| IO.println 5
|
||||
| IO.println (My_Type (My_Type 10))
|
||||
| IO.println "123"
|
||||
|""".stripMargin
|
||||
eval(code)
|
||||
consumeOut shouldEqual List("5", "My_Type (My_Type 10)", "123")
|
||||
consumeOut shouldEqual List("5", "(My_Type (My_Type 10))", "123")
|
||||
}
|
||||
|
||||
"support text creation with raw block literals" in {
|
||||
@ -77,17 +77,14 @@ class TextTest extends InterpreterTest {
|
||||
}
|
||||
|
||||
"support printing to standard error" in {
|
||||
val errString = "\"My error string\""
|
||||
val resultStr = errString.drop(1).dropRight(1)
|
||||
|
||||
val code =
|
||||
s"""from Builtins import all
|
||||
|
|
||||
|main = IO.print_err $errString
|
||||
|main = IO.print_err "My error string"
|
||||
|""".stripMargin
|
||||
|
||||
eval(code)
|
||||
consumeErr shouldEqual List(resultStr)
|
||||
consumeErr shouldEqual List("My error string")
|
||||
}
|
||||
|
||||
"support reading from standard input" in {
|
||||
|
@ -128,45 +128,47 @@ object Escape {
|
||||
}
|
||||
|
||||
// Reference: https://en.wikipedia.org/wiki/String_literal
|
||||
sealed trait Character extends Escape
|
||||
sealed trait Character extends Escape {
|
||||
def code: Char
|
||||
}
|
||||
object Character {
|
||||
case object a extends Character {
|
||||
val code: Int = '\u0007'
|
||||
override val code: Char = '\u0007'
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object b extends Character {
|
||||
val code: Int = '\u0008'
|
||||
override val code: Char = '\u0008'
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object f extends Character {
|
||||
val code: Int = '\u000C'
|
||||
override val code: Char = '\u000C'
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object n extends Character {
|
||||
val code: Int = '\n'
|
||||
override val code: Char = '\n'
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object r extends Character {
|
||||
val code: Int = '\r'
|
||||
override val code: Char = '\r'
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object t extends Character {
|
||||
val code: Int = '\u0009'
|
||||
override val code: Char = '\u0009'
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object v extends Character {
|
||||
val code: Int = '\u000B'
|
||||
override val code: Char = '\u000B'
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object e extends Character {
|
||||
val code: Int = '\u001B'
|
||||
override val code: Char = '\u001B'
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
@ -229,32 +231,32 @@ object Escape {
|
||||
override val repr = name
|
||||
}
|
||||
case object LF extends Control {
|
||||
val code: Int = 0x0A
|
||||
val code: Int = 0x0a
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object VT extends Control {
|
||||
val code: Int = 0x0B
|
||||
val code: Int = 0x0b
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object FF extends Control {
|
||||
val code: Int = 0x0C
|
||||
val code: Int = 0x0c
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object CR extends Control {
|
||||
val code: Int = 0x0D
|
||||
val code: Int = 0x0d
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object SO extends Control {
|
||||
val code: Int = 0x0E
|
||||
val code: Int = 0x0e
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object SI extends Control {
|
||||
val code: Int = 0x0F
|
||||
val code: Int = 0x0f
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
@ -309,37 +311,37 @@ object Escape {
|
||||
override val repr = name
|
||||
}
|
||||
case object SUB extends Control {
|
||||
val code: Int = 0x1A
|
||||
val code: Int = 0x1a
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object ESC extends Control {
|
||||
val code: Int = 0x1B
|
||||
val code: Int = 0x1b
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object FS extends Control {
|
||||
val code: Int = 0x1C
|
||||
val code: Int = 0x1c
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object GS extends Control {
|
||||
val code: Int = 0x1D
|
||||
val code: Int = 0x1d
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object RS extends Control {
|
||||
val code: Int = 0x1E
|
||||
val code: Int = 0x1e
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object US extends Control {
|
||||
val code: Int = 0x1F
|
||||
val code: Int = 0x1f
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
case object DEL extends Control {
|
||||
val code: Int = 0x7F
|
||||
val code: Int = 0x7f
|
||||
def name: String = toString
|
||||
override val repr = name
|
||||
}
|
||||
|
@ -12,7 +12,8 @@ import scala.annotation.tailrec
|
||||
case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
import ParserDef2._
|
||||
|
||||
final def unwrap[T](opt: Option[T]): T = opt match {
|
||||
final def unwrap[T](opt: Option[T]): T =
|
||||
opt match {
|
||||
case None => throw new Error("Internal Error")
|
||||
case Some(t) => t
|
||||
}
|
||||
@ -42,7 +43,8 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
//// Result ////
|
||||
////////////////
|
||||
|
||||
override def getResult() = result.current.flatMap {
|
||||
override def getResult() =
|
||||
result.current.flatMap {
|
||||
case AST.Module.any(mod) => Some(mod)
|
||||
case _ => None
|
||||
}
|
||||
@ -52,13 +54,15 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
var current: Option[AST] = None
|
||||
var stack: List[Option[AST]] = Nil
|
||||
|
||||
def push(): Unit = logger.trace {
|
||||
def push(): Unit =
|
||||
logger.trace {
|
||||
logger.log(s"Pushed: $current")
|
||||
stack +:= current
|
||||
current = None
|
||||
}
|
||||
|
||||
def pop(): Unit = logger.trace {
|
||||
def pop(): Unit =
|
||||
logger.trace {
|
||||
current = stack.head
|
||||
stack = stack.tail
|
||||
logger.log(s"New result: ${current.map(_.show()).getOrElse("None")}")
|
||||
@ -67,7 +71,8 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
def app(fn: String => AST): Unit =
|
||||
app(fn(currentMatch))
|
||||
|
||||
def app(ast: AST): Unit = logger.trace {
|
||||
def app(ast: AST): Unit =
|
||||
logger.trace {
|
||||
current = Some(current match {
|
||||
case None => ast
|
||||
case Some(r) => AST.App.Prefix(r, off.use(), ast)
|
||||
@ -76,7 +81,8 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
|
||||
def last(): Option[AST] = {
|
||||
@tailrec
|
||||
def go(ast: AST): AST = ast match {
|
||||
def go(ast: AST): AST =
|
||||
ast match {
|
||||
case AST.App.Prefix.any(t) => go(t.arg)
|
||||
case t => t
|
||||
}
|
||||
@ -92,18 +98,21 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
var current: Int = 0
|
||||
var stack: List[Int] = Nil
|
||||
|
||||
def push(): Unit = logger.trace {
|
||||
def push(): Unit =
|
||||
logger.trace {
|
||||
stack +:= current
|
||||
current = 0
|
||||
}
|
||||
|
||||
def pop(): Unit = logger.trace {
|
||||
def pop(): Unit =
|
||||
logger.trace {
|
||||
current = stack.head
|
||||
stack = stack.tail
|
||||
logger.log(s"New offset: $current")
|
||||
}
|
||||
|
||||
def use(): Int = logger.trace {
|
||||
def use(): Int =
|
||||
logger.trace {
|
||||
val offset = current
|
||||
current = 0
|
||||
offset
|
||||
@ -111,7 +120,8 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
|
||||
def on(): Unit = on(0)
|
||||
|
||||
def on(shift: Int): Unit = logger.trace {
|
||||
def on(shift: Int): Unit =
|
||||
logger.trace {
|
||||
val diff = currentMatch.length + shift
|
||||
current += diff
|
||||
logger.log(s"lastOffset + $diff = $current")
|
||||
@ -126,33 +136,39 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
|
||||
var current: Option[AST.Ident] = None
|
||||
|
||||
def on(cons: String => AST.Ident): Unit = logger.trace_ {
|
||||
def on(cons: String => AST.Ident): Unit =
|
||||
logger.trace_ {
|
||||
on(cons(currentMatch))
|
||||
}
|
||||
|
||||
def on(ast: AST.Ident): Unit = logger.trace {
|
||||
def on(ast: AST.Ident): Unit =
|
||||
logger.trace {
|
||||
current = Some(ast)
|
||||
state.begin(SFX_CHECK)
|
||||
}
|
||||
|
||||
def submit(): Unit = logger.trace {
|
||||
def submit(): Unit =
|
||||
logger.trace {
|
||||
result.app(unwrap(current))
|
||||
current = None
|
||||
}
|
||||
|
||||
def onErrSfx(): Unit = logger.trace {
|
||||
def onErrSfx(): Unit =
|
||||
logger.trace {
|
||||
val ast = AST.Ident.InvalidSuffix(unwrap(current), currentMatch)
|
||||
result.app(ast)
|
||||
current = None
|
||||
state.end()
|
||||
}
|
||||
|
||||
def onNoErrSfx(): Unit = logger.trace {
|
||||
def onNoErrSfx(): Unit =
|
||||
logger.trace {
|
||||
submit()
|
||||
state.end()
|
||||
}
|
||||
|
||||
def finalizer(): Unit = logger.trace {
|
||||
def finalizer(): Unit =
|
||||
logger.trace {
|
||||
if (current.isDefined) submit()
|
||||
}
|
||||
|
||||
@ -177,30 +193,36 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
//////////////////
|
||||
|
||||
final object opr {
|
||||
def on(cons: String => AST.Ident): Unit = logger.trace {
|
||||
def on(cons: String => AST.Ident): Unit =
|
||||
logger.trace {
|
||||
on(cons(currentMatch))
|
||||
}
|
||||
|
||||
def onGrp(cons: String => AST.Ident): Unit = logger.trace {
|
||||
def onGrp(cons: String => AST.Ident): Unit =
|
||||
logger.trace {
|
||||
ident.current = Some(cons(currentMatch))
|
||||
ident.onNoErrSfx()
|
||||
}
|
||||
|
||||
def onNoMod(cons: String => AST.Ident): Unit = logger.trace {
|
||||
def onNoMod(cons: String => AST.Ident): Unit =
|
||||
logger.trace {
|
||||
onNoMod(cons(currentMatch))
|
||||
}
|
||||
|
||||
def on(ast: AST.Ident): Unit = logger.trace {
|
||||
def on(ast: AST.Ident): Unit =
|
||||
logger.trace {
|
||||
ident.current = Some(ast)
|
||||
state.begin(MOD_CHECK)
|
||||
}
|
||||
|
||||
def onNoMod(ast: AST.Ident): Unit = logger.trace {
|
||||
def onNoMod(ast: AST.Ident): Unit =
|
||||
logger.trace {
|
||||
ident.current = Some(ast)
|
||||
state.begin(SFX_CHECK)
|
||||
}
|
||||
|
||||
def onMod(): Unit = logger.trace {
|
||||
def onMod(): Unit =
|
||||
logger.trace {
|
||||
val opr = AST.Mod(unwrap(ident.current).asInstanceOf[AST.Opr].name)
|
||||
ident.current = Some(opr)
|
||||
}
|
||||
@ -236,36 +258,42 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
var part1: String = ""
|
||||
var part2: String = ""
|
||||
|
||||
def reset(): Unit = logger.trace {
|
||||
def reset(): Unit =
|
||||
logger.trace {
|
||||
part1 = ""
|
||||
part2 = ""
|
||||
}
|
||||
|
||||
def submit(): Unit = logger.trace {
|
||||
def submit(): Unit =
|
||||
logger.trace {
|
||||
val base = if (part1 == "") None else Some(part1)
|
||||
result.app(AST.Number(base, part2))
|
||||
reset()
|
||||
}
|
||||
|
||||
def onDanglingBase(): Unit = logger.trace {
|
||||
def onDanglingBase(): Unit =
|
||||
logger.trace {
|
||||
state.end()
|
||||
result.app(AST.Number.DanglingBase(part2))
|
||||
reset()
|
||||
}
|
||||
|
||||
def onDecimal(): Unit = logger.trace {
|
||||
def onDecimal(): Unit =
|
||||
logger.trace {
|
||||
part2 = currentMatch
|
||||
state.begin(PHASE2)
|
||||
}
|
||||
|
||||
def onExplicitBase(): Unit = logger.trace {
|
||||
def onExplicitBase(): Unit =
|
||||
logger.trace {
|
||||
state.end()
|
||||
part1 = part2
|
||||
part2 = currentMatch.substring(1)
|
||||
submit()
|
||||
}
|
||||
|
||||
def onNoExplicitBase(): Unit = logger.trace {
|
||||
def onNoExplicitBase(): Unit =
|
||||
logger.trace {
|
||||
state.end()
|
||||
submit()
|
||||
}
|
||||
@ -301,27 +329,32 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
var stack: List[TextState] = Nil
|
||||
var text: TextState = _
|
||||
|
||||
def push(): Unit = logger.trace {
|
||||
def push(): Unit =
|
||||
logger.trace {
|
||||
stack +:= text
|
||||
}
|
||||
|
||||
def pop(): Unit = logger.trace {
|
||||
def pop(): Unit =
|
||||
logger.trace {
|
||||
text = stack.head
|
||||
stack = stack.tail
|
||||
}
|
||||
|
||||
def onInvalidQuote(): Unit = logger.trace {
|
||||
def onInvalidQuote(): Unit =
|
||||
logger.trace {
|
||||
result.app(AST.Text.InvalidQuote(currentMatch))
|
||||
}
|
||||
|
||||
def onInlineBlock(): Unit = logger.trace {
|
||||
def onInlineBlock(): Unit =
|
||||
logger.trace {
|
||||
result.app(AST.Text.InlineBlock(currentMatch))
|
||||
}
|
||||
|
||||
def finish(
|
||||
raw: List[Line[Segment.Raw]] => AST,
|
||||
fmt: List[Line[Segment.Fmt]] => AST
|
||||
): Unit = logger.trace {
|
||||
): Unit =
|
||||
logger.trace {
|
||||
submitLine()
|
||||
val isFMT = state.current.parent.contains(FMT)
|
||||
val body = text.lines.reverse
|
||||
@ -333,30 +366,39 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
result.app(t)
|
||||
}
|
||||
|
||||
def submit(segment: Segment.Fmt): Unit = logger.trace {
|
||||
def submit(segment: Segment.Fmt): Unit =
|
||||
logger.trace {
|
||||
text.lineBuilder +:= segment
|
||||
}
|
||||
|
||||
def submit(): Unit = logger.trace {
|
||||
finish(t => AST.Text.Raw(t.head.text: _*), t => AST.Text(t.head.text: _*))
|
||||
def submit(): Unit =
|
||||
logger.trace {
|
||||
finish(
|
||||
t => AST.Text.Raw(t.head.text: _*),
|
||||
t => AST.Text(t.head.text: _*)
|
||||
)
|
||||
}
|
||||
|
||||
def submitMissingQuote(): Unit = logger.trace {
|
||||
def submitMissingQuote(): Unit =
|
||||
logger.trace {
|
||||
rewind()
|
||||
submitUnclosed()
|
||||
}
|
||||
|
||||
def submitInvalidQuote(): Unit = logger.trace {
|
||||
def submitInvalidQuote(): Unit =
|
||||
logger.trace {
|
||||
submitUnclosed()
|
||||
onInvalidQuote()
|
||||
}
|
||||
|
||||
def submitUnclosed(): Unit = logger.trace {
|
||||
def submitUnclosed(): Unit =
|
||||
logger.trace {
|
||||
val Text = AST.Text.Unclosed
|
||||
finish(t => Text.Raw(t.head.text: _*), t => Text(t.head.text: _*))
|
||||
}
|
||||
|
||||
def onEndOfBlock(): Unit = logger.trace {
|
||||
def onEndOfBlock(): Unit =
|
||||
logger.trace {
|
||||
if (text.lineBuilder.isEmpty)
|
||||
block.emptyLines = text.emptyLines ++ block.emptyLines
|
||||
val (s, o) = (text.spaces, text.offset)
|
||||
@ -365,13 +407,15 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
rewind()
|
||||
}
|
||||
|
||||
def onBegin(grp: State): Unit = logger.trace {
|
||||
def onBegin(grp: State): Unit =
|
||||
logger.trace {
|
||||
push()
|
||||
state.begin(grp)
|
||||
text = new TextState(0, 0, Nil, Nil, Nil)
|
||||
}
|
||||
|
||||
def onBeginBlock(grp: State): Unit = logger.trace {
|
||||
def onBeginBlock(grp: State): Unit =
|
||||
logger.trace {
|
||||
val offset = if (state.current == block.FIRSTCHAR) {
|
||||
state.end()
|
||||
block.current.offset
|
||||
@ -392,7 +436,8 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
}
|
||||
}
|
||||
|
||||
def submitPlainSegment(): Unit = logger.trace {
|
||||
def submitPlainSegment(): Unit =
|
||||
logger.trace {
|
||||
text.lineBuilder = text.lineBuilder match {
|
||||
case Shape.SegmentPlain(t) :: _ =>
|
||||
Segment.Plain(t + currentMatch) :: text.lineBuilder.tail
|
||||
@ -400,57 +445,75 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
}
|
||||
}
|
||||
|
||||
def onEscape(code: Segment.Escape): Unit = logger.trace {
|
||||
def onEscape(code: Segment.Escape): Unit =
|
||||
logger.trace {
|
||||
submit(Shape.SegmentEscape(code))
|
||||
}
|
||||
|
||||
def onEscape(code: Segment.RawEscape): Unit = logger.trace {
|
||||
def onEscape(code: Segment.RawEscape): Unit =
|
||||
logger.trace {
|
||||
submit(Shape.SegmentRawEscape(code))
|
||||
}
|
||||
|
||||
def onEscapeU16(): Unit = logger.trace {
|
||||
def onEscapeU21(): Unit =
|
||||
logger.trace {
|
||||
val code = currentMatch.drop(3).dropRight(1)
|
||||
onEscape(Segment.Escape.Unicode.U21(code))
|
||||
}
|
||||
|
||||
def onEscapeU16(): Unit =
|
||||
logger.trace {
|
||||
val code = currentMatch.drop(2)
|
||||
onEscape(Segment.Escape.Unicode.U16(code))
|
||||
}
|
||||
|
||||
def onEscapeU32(): Unit = logger.trace {
|
||||
def onEscapeU32(): Unit =
|
||||
logger.trace {
|
||||
val code = currentMatch.drop(2)
|
||||
onEscape(Segment.Escape.Unicode.U32(code))
|
||||
}
|
||||
|
||||
def onEscapeInt(): Unit = logger.trace {
|
||||
def onEscapeInt(): Unit =
|
||||
logger.trace {
|
||||
val int = currentMatch.drop(1).toInt
|
||||
onEscape(Segment.Escape.Number(int))
|
||||
}
|
||||
|
||||
def onEscapeInvalid(): Unit = logger.trace {
|
||||
def onEscapeInvalid(): Unit =
|
||||
logger.trace {
|
||||
val chr = currentMatch.charAt(1)
|
||||
onEscape(Segment.Escape.Invalid(chr))
|
||||
}
|
||||
|
||||
def onEscapeUnfinished(): Unit = logger.trace {
|
||||
def onEscapeUnfinished(): Unit =
|
||||
logger.trace {
|
||||
onEscape(Segment.Escape.Unfinished)
|
||||
}
|
||||
|
||||
def onEscapeSlash(): Unit = logger.trace {
|
||||
def onEscapeSlash(): Unit =
|
||||
logger.trace {
|
||||
onEscape(Segment.Escape.Slash)
|
||||
}
|
||||
|
||||
def onEscapeQuote(): Unit = logger.trace {
|
||||
def onEscapeQuote(): Unit =
|
||||
logger.trace {
|
||||
onEscape(Segment.Escape.Quote)
|
||||
}
|
||||
|
||||
def onEscapeRawQuote(): Unit = logger.trace {
|
||||
def onEscapeRawQuote(): Unit =
|
||||
logger.trace {
|
||||
onEscape(Segment.Escape.RawQuote)
|
||||
}
|
||||
|
||||
def onInterpolateBegin(): Unit = logger.trace {
|
||||
def onInterpolateBegin(): Unit =
|
||||
logger.trace {
|
||||
result.push()
|
||||
off.push()
|
||||
state.begin(INTERPOLATE)
|
||||
}
|
||||
|
||||
def onInterpolateEnd(): Unit = logger.trace {
|
||||
def onInterpolateEnd(): Unit =
|
||||
logger.trace {
|
||||
if (state.isInside(INTERPOLATE)) {
|
||||
state.endTill(INTERPOLATE)
|
||||
submit(Segment.Expr(result.current))
|
||||
@ -462,8 +525,11 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
}
|
||||
}
|
||||
|
||||
def submitLine(): Unit = logger.trace {
|
||||
if (state.current == FMT_LINE || state.current == RAW_LINE || text.lineBuilder.nonEmpty) {
|
||||
def submitLine(): Unit =
|
||||
logger.trace {
|
||||
if (
|
||||
state.current == FMT_LINE || state.current == RAW_LINE || text.lineBuilder.nonEmpty
|
||||
) {
|
||||
val Line = Shape.TextBlockLine
|
||||
text.lines +:= Line(text.emptyLines.reverse, text.lineBuilder.reverse)
|
||||
text.lineBuilder = Nil
|
||||
@ -471,12 +537,14 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
}
|
||||
}
|
||||
|
||||
def onEndOfLine(): Unit = logger.trace {
|
||||
def onEndOfLine(): Unit =
|
||||
logger.trace {
|
||||
state.begin(NEWLINE)
|
||||
submitLine()
|
||||
}
|
||||
|
||||
def onNewLine(): Unit = logger.trace {
|
||||
def onNewLine(): Unit =
|
||||
logger.trace {
|
||||
state.end()
|
||||
if (text.offset == OFFSET_OF_FIRST_LINE_FOUND)
|
||||
text.offset = currentMatch.length
|
||||
@ -488,11 +556,13 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
text.lineBuilder +:= Segment.Plain(" " * leadingSpaces)
|
||||
}
|
||||
|
||||
def onEmptyLine(): Unit = logger.trace {
|
||||
def onEmptyLine(): Unit =
|
||||
logger.trace {
|
||||
text.emptyLines :+= currentMatch.length - 1
|
||||
}
|
||||
|
||||
def onEOFNewLine(): Unit = logger.trace {
|
||||
def onEOFNewLine(): Unit =
|
||||
logger.trace {
|
||||
state.end()
|
||||
onEndOfBlock()
|
||||
state.begin(block.NEWLINE)
|
||||
@ -504,9 +574,11 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
val fmtBlock = "'''" >> space.opt >> (eof | newline)
|
||||
val rawBlock = "\"\"\"" >> space.opt >> (eof | newline)
|
||||
val fmtChar = noneOf("'`\\\n")
|
||||
val escapeChar = noneOf("'\\\"`\\\\\\n\\r{}")
|
||||
val escape_int = "\\" >> num.decimal
|
||||
val escape_u16 = "\\u" >> repeat(fmtChar, 0, 4)
|
||||
val escape_u32 = "\\U" >> repeat(fmtChar, 0, 8)
|
||||
val escape_u21 = "\\u{" >> repeat(escapeChar, 0, 8) >> "}"
|
||||
val escape_u16 = "\\u" >> repeat(escapeChar, 0, 4)
|
||||
val escape_u32 = "\\U" >> repeat(escapeChar, 0, 8)
|
||||
val fmtSeg = fmtChar.many1
|
||||
val rawSeg = noneOf("\"\n\\").many1
|
||||
val fmtBSeg = noneOf("\n\\`").many1
|
||||
@ -570,6 +642,7 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
text.FMT || s"\\$code" run s"text.onEscape($ctrl)"
|
||||
}
|
||||
|
||||
text.FMT || text.escape_u21 || text.onEscapeU21()
|
||||
text.FMT || text.escape_u16 || text.onEscapeU16()
|
||||
text.FMT || text.escape_u32 || text.onEscapeU32()
|
||||
text.FMT || text.escape_int || text.onEscapeInt()
|
||||
@ -611,12 +684,14 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
emptyLines = Nil
|
||||
}
|
||||
|
||||
def pop(): Unit = logger.trace {
|
||||
def pop(): Unit =
|
||||
logger.trace {
|
||||
current = stack.head
|
||||
stack = stack.tail
|
||||
}
|
||||
|
||||
def build(): AST.Block = logger.trace {
|
||||
def build(): AST.Block =
|
||||
logger.trace {
|
||||
submitLine()
|
||||
AST.Block(
|
||||
current.isOrphan,
|
||||
@ -628,13 +703,15 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
)
|
||||
}
|
||||
|
||||
def submit(): Unit = logger.trace {
|
||||
def submit(): Unit =
|
||||
logger.trace {
|
||||
val block = build()
|
||||
result.pop()
|
||||
off.pop()
|
||||
pop()
|
||||
val block2: AST.Block = result.last() match {
|
||||
case Some(AST.Opr.any(_)) => block.replaceType(AST.Block.Discontinuous)
|
||||
case Some(AST.Opr.any(_)) =>
|
||||
block.replaceType(AST.Block.Discontinuous)
|
||||
case _ => block
|
||||
}
|
||||
result.app(block2)
|
||||
@ -642,7 +719,8 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
logger.endGroup()
|
||||
}
|
||||
|
||||
def submitModule(): Unit = logger.trace {
|
||||
def submitModule(): Unit =
|
||||
logger.trace {
|
||||
val body = current.firstLine match {
|
||||
case None => current.lines.reverse
|
||||
case Some(line) => line.toOptional +: current.lines.reverse
|
||||
@ -654,7 +732,8 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
logger.endGroup()
|
||||
}
|
||||
|
||||
def submitLine(): Unit = logger.trace {
|
||||
def submitLine(): Unit =
|
||||
logger.trace {
|
||||
result.current match {
|
||||
case None =>
|
||||
case Some(r) =>
|
||||
@ -671,12 +750,14 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
result.current = None
|
||||
}
|
||||
|
||||
def onEmptyLine(): Unit = logger.trace {
|
||||
def onEmptyLine(): Unit =
|
||||
logger.trace {
|
||||
off.on(-1)
|
||||
emptyLines +:= off.use()
|
||||
}
|
||||
|
||||
def onModuleBegin(): Unit = logger.trace {
|
||||
def onModuleBegin(): Unit =
|
||||
logger.trace {
|
||||
current.emptyLines = emptyLines.reverse
|
||||
emptyLines = Nil
|
||||
rewind()
|
||||
@ -685,14 +766,16 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
state.begin(NEWLINE)
|
||||
}
|
||||
|
||||
def onBegin(newIndent: Int): Unit = logger.trace {
|
||||
def onBegin(newIndent: Int): Unit =
|
||||
logger.trace {
|
||||
val isOrphan = result.current.isEmpty
|
||||
result.push()
|
||||
push(newIndent, isOrphan)
|
||||
logger.beginGroup()
|
||||
}
|
||||
|
||||
def onEOFLine(): Unit = logger.trace {
|
||||
def onEOFLine(): Unit =
|
||||
logger.trace {
|
||||
state.end()
|
||||
submitLine()
|
||||
off.on()
|
||||
@ -701,12 +784,14 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
onEOF()
|
||||
}
|
||||
|
||||
def onEndLine(): Unit = logger.trace {
|
||||
def onEndLine(): Unit =
|
||||
logger.trace {
|
||||
off.push()
|
||||
state.begin(NEWLINE)
|
||||
}
|
||||
|
||||
def onNewLine(): Unit = logger.trace {
|
||||
def onNewLine(): Unit =
|
||||
logger.trace {
|
||||
state.end()
|
||||
off.on()
|
||||
if (off.current == current.offset)
|
||||
@ -718,7 +803,8 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
state.begin(FIRSTCHAR)
|
||||
}
|
||||
|
||||
def onEnd(newIndent: Int): Unit = logger.trace {
|
||||
def onEnd(newIndent: Int): Unit =
|
||||
logger.trace {
|
||||
while (newIndent < current.offset) submit()
|
||||
if (newIndent > current.offset) {
|
||||
logger.log("Block with invalid indentation")
|
||||
@ -747,11 +833,13 @@ case class ParserDef() extends flexer.Parser[AST.Module] {
|
||||
/// Defaults ///
|
||||
////////////////
|
||||
|
||||
final def onUnrecognized(): Unit = logger.trace {
|
||||
final def onUnrecognized(): Unit =
|
||||
logger.trace {
|
||||
result.app(AST.Invalid.Unrecognized(_))
|
||||
}
|
||||
|
||||
final def onEOF(): Unit = logger.trace {
|
||||
final def onEOF(): Unit =
|
||||
logger.trace {
|
||||
ident.finalizer()
|
||||
off.push()
|
||||
block.submitLine()
|
||||
|
106
std-bits/pom.xml
Normal file
106
std-bits/pom.xml
Normal file
@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.enso</groupId>
|
||||
<artifactId>base</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>base</name>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.ibm.icu</groupId>
|
||||
<artifactId>icu4j</artifactId>
|
||||
<version>67.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.3.1</version>
|
||||
<configuration>
|
||||
<outputDirectory>
|
||||
${project.build.directory}/../../distribution/std-lib/Base/polyglot/java
|
||||
</outputDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-third-party-licenses</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>download-licenses</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<licensesOutputDirectory>
|
||||
${project.build.directory}/../../distribution/std-lib/Base/third-party-licenses
|
||||
</licensesOutputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>add-third-party-licenses-list</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>add-third-party</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>
|
||||
${project.build.directory}/../../distribution/std-lib/Base/third-party-licenses
|
||||
</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.10</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>com.ibm.icu</groupId>
|
||||
<artifactId>icu4j</artifactId>
|
||||
<version>67.1</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<destFileName>icu4j.jar</destFileName>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
<outputDirectory>
|
||||
${project.build.directory}/../../distribution/std-lib/Base/polyglot/java
|
||||
</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
87
std-bits/src/main/java/org/enso/base/Text_Utils.java
Normal file
87
std-bits/src/main/java/org/enso/base/Text_Utils.java
Normal file
@ -0,0 +1,87 @@
|
||||
package org.enso.base;
|
||||
|
||||
import com.ibm.icu.text.Normalizer2;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** Utils for standard library operations on Text. */
|
||||
public class Text_Utils {
|
||||
/**
|
||||
* Creates a substring of the given string, indexing using the Java standard (UTF-16) indexing
|
||||
* mechanism.
|
||||
*
|
||||
* @param string the string to substring
|
||||
* @param from starting index
|
||||
* @param to index one past the end of the desired substring
|
||||
* @return a suitable substring
|
||||
*/
|
||||
public static String substring(String string, int from, int to) {
|
||||
return string.substring(from, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string into an array of UTF-8 bytes.
|
||||
*
|
||||
* @param str the string to convert
|
||||
* @return the UTF-8 representation of the string.
|
||||
*/
|
||||
public static byte[] get_bytes(String str) {
|
||||
return str.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string into an array of Unicode codepoints.
|
||||
*
|
||||
* @param str the string to convert
|
||||
* @return the codepoints of the original string.
|
||||
*/
|
||||
public static int[] get_codepoints(String str) {
|
||||
return str.codePoints().toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the string on each occurrence of {@code sep}, returning the resulting substrings in an
|
||||
* array.
|
||||
*
|
||||
* @param str the string to split
|
||||
* @param sep the separator string
|
||||
* @return array of substrings of {@code str} contained between occurences of {@code sep}
|
||||
*/
|
||||
public static String[] split_at(String str, String sep) {
|
||||
return str.split(Pattern.quote(sep));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether two strings are equal up to Unicode canonicalization.
|
||||
*
|
||||
* @param str1 the first string
|
||||
* @param str2 the second string
|
||||
* @return the result of comparison
|
||||
*/
|
||||
public static boolean equals(String str1, String str2) {
|
||||
return Normalizer2.getNFDInstance()
|
||||
.normalize(str1)
|
||||
.equals(Normalizer2.getNFDInstance().normalize(str2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of codepoints into a string.
|
||||
*
|
||||
* @param codepoints the codepoints to convert
|
||||
* @return the resulting string
|
||||
*/
|
||||
public static String from_codepoints(int[] codepoints) {
|
||||
return new String(codepoints, 0, codepoints.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of UTF-8 bytes into a string.
|
||||
*
|
||||
* @param bytes the bytes to convert
|
||||
* @return the resulting string
|
||||
*/
|
||||
public static String from_utf_8(byte[] bytes) {
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
@ -19,6 +19,12 @@ sum_tco_decimal = sum_to ->
|
||||
res = summator 0.0 0.0
|
||||
res
|
||||
|
||||
sum_tco_eval = sumTo ->
|
||||
summator = acc -> current ->
|
||||
if current == 0 then acc else Debug.eval "summator (acc + current) (current - 1)"
|
||||
|
||||
res = summator 0 sumTo
|
||||
res
|
||||
|
||||
sum_tco_java = sum_to ->
|
||||
summator = acc -> current ->
|
||||
@ -49,11 +55,13 @@ sum_state = sum_to ->
|
||||
main =
|
||||
hundred_mil = 100000000
|
||||
IO.println "Measuring Sum TCO Decimal"
|
||||
Bench_Utils.measure (here.sum_tco_decimal hundred_mil) "sum_tco" 100 10
|
||||
Bench_Utils.measure (here.sum_tco_decimal hundred_mil) "sum_tco_float" 100 10
|
||||
IO.println "Measuring SumTCO"
|
||||
Bench_Utils.measure (here.sum_tco hundred_mil) "sum_tco" 100 10
|
||||
IO.println "Measuring SumTCO Java"
|
||||
Bench_Utils.measure (here.sum_tco_java hundred_mil) "sum_tco" 100 10
|
||||
Bench_Utils.measure (here.sum_tco_java hundred_mil) "sum_tco_java" 100 10
|
||||
IO.println "Measuring SumTCO Eval"
|
||||
Bench_Utils.measure (here.sum_tco_eval hundred_mil) "sum_tco_eval" 100 10
|
||||
IO.println "Measuring State"
|
||||
Bench_Utils.measure (here.sum_state hundred_mil) "sum_state" 100 10
|
||||
IO.println "Measuring Co-State"
|
||||
|
21
test/Benchmarks/src/Text.enso
Normal file
21
test/Benchmarks/src/Text.enso
Normal file
@ -0,0 +1,21 @@
|
||||
from Base import all
|
||||
from Builtins import Prim_Text_Helper
|
||||
import Base.Bench_Utils
|
||||
|
||||
polyglot java import java.lang.StringBuilder
|
||||
|
||||
build_long n =
|
||||
res = 1.upto n . fold "" acc-> n-> acc + n.to_text
|
||||
Prim_Text_Helper.optimize res
|
||||
res
|
||||
|
||||
build_long_bldr n =
|
||||
bldr = new StringBuilder [].to_array
|
||||
1.upto n . each n-> bldr.append [n]
|
||||
res = bldr.toString []
|
||||
res
|
||||
|
||||
main =
|
||||
Bench_Utils.measure (here.build_long_bldr 1000000) "string append bldr" 100 10
|
||||
Bench_Utils.measure (here.build_long 1000000) "string append" 100 10
|
||||
IO.println "Bye"
|
@ -4,11 +4,22 @@ import Base.Test
|
||||
polyglot java import java.lang.Long
|
||||
polyglot java import java.lang.Integer
|
||||
polyglot java import java.lang.Float
|
||||
polyglot java import java.lang.String
|
||||
polyglot java import java.util.ArrayList
|
||||
|
||||
spec = describe "Java FFI" <|
|
||||
it "should call methods imported from Java" <|
|
||||
Long.sum [1, 2] . should_equal 3
|
||||
|
||||
## TODO
|
||||
https://github.com/enso-org/enso/issues/1163
|
||||
it "should call constructors imported from Java" pending=True <|
|
||||
list = ArrayList.new []
|
||||
list.add 432
|
||||
list.get [0] . should_equal 432
|
||||
it "should auto-convert numeric types across the polyglot boundary" <|
|
||||
(Float.valueOf ["123.3"] + 5).should_equal 128.3 epsilon=0.0001
|
||||
(Integer.sum [1, 2] + 3) . should_equal 6
|
||||
it "should auto-convert strings across the polyglot boundary" <|
|
||||
(String.format ["%s bar %s", "baz", "quux"] + " foo").should_equal "baz bar quux foo"
|
||||
|
||||
|
@ -8,6 +8,7 @@ import Test.Process_Spec
|
||||
import Test.Java_Interop.Spec as Java_Spec
|
||||
import Test.Vector.Spec as Vector_Spec
|
||||
import Test.Numbers.Spec as Numbers_Spec
|
||||
import Test.Text.Spec as Text_Spec
|
||||
|
||||
main = Test.Suite.runMain <|
|
||||
List_Spec.spec
|
||||
@ -19,3 +20,4 @@ main = Test.Suite.runMain <|
|
||||
Java_Spec.spec
|
||||
Vector_Spec.spec
|
||||
Numbers_Spec.spec
|
||||
Text_Spec.spec
|
||||
|
42
test/Test/src/Text/Spec.enso
Normal file
42
test/Test/src/Text/Spec.enso
Normal file
@ -0,0 +1,42 @@
|
||||
from Base import all
|
||||
import Base.Test
|
||||
|
||||
type Auto a
|
||||
|
||||
type Manual b
|
||||
|
||||
Manual.to_text = "[[[MyREP " + this.b.to_text + "]]]"
|
||||
|
||||
spec = describe "Text" <|
|
||||
kshi = '\u0915\u094D\u0937\u093F'
|
||||
kshi_utf_8 = [-32, -92, -107, -32, -91, -115, -32, -92, -73, -32, -92, -65]
|
||||
facepalm = '\u{1F926}\u{1F3FC}\u200D\u2642\uFE0F'
|
||||
facepalm_codes = [129318, 127996, 8205, 9794, 65039]
|
||||
accent_1 = '\u00E9'
|
||||
accent_2 = '\u0065\u{301}'
|
||||
it "should compare strings using utf normalization" <|
|
||||
"abc".equals "def" . should_be_false
|
||||
accent_1 . should_equal accent_2
|
||||
it "should split the text into grapheme clusters" <|
|
||||
str = kshi + facepalm + accent_1 + accent_2
|
||||
str.characters . should_equal [kshi, facepalm, accent_1, accent_2]
|
||||
it "should split the text on arbitrary sequence" <|
|
||||
"foo, bar, baz" . split_at ", " . should_equal ["foo", "bar", "baz"]
|
||||
it "should dump utf-8 bytes to a vector" <|
|
||||
kshi.utf_8.should_equal kshi_utf_8
|
||||
it "should convert an array of bytes to text" <|
|
||||
Text.from_utf_8 kshi_utf_8 . should_equal kshi
|
||||
it "should dump utf codepoints to a vector" <|
|
||||
facepalm.codepoints.should_equal facepalm_codes
|
||||
it "should convert an array of codepoints to text" <|
|
||||
Text.from_codepoints facepalm_codes . should_equal facepalm
|
||||
it "should convert any type to text automatically and using provided methods" <|
|
||||
t = Auto (Manual 123) . to_text
|
||||
t.should_equal "(Auto [[[MyREP 123]]])"
|
||||
it "should escape special characters when debug-printing text" <|
|
||||
text_1 = '''
|
||||
foo
|
||||
bar\r\tbaz
|
||||
text_1.to_text.should_equal "'foo\\nbar\\r\\tbaz'"
|
||||
text_2 = '\n\t\a\b\f\r\v\e\''
|
||||
text_2.to_text.should_equal "'\\n\\t\\a\\b\\f\\r\\v\\e\\''"
|
@ -19,4 +19,8 @@ spec = describe "Vectors" <|
|
||||
mapped = vec.map x-> x * x
|
||||
vec.to_text.should_equal "[1, 2, 3, 4]"
|
||||
mapped.to_text.should_equal "[1, 4, 9, 16]"
|
||||
it "should define equality" <|
|
||||
[1,2,3].equals [1,2] . should_be_false
|
||||
[1,2,3].equals [1,2,3] . should_be_true
|
||||
[1,2,3].equals [3,4,5] . should_be_false
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user