We reject any filepath that contains a `\` character;
all Pkl code must use `/` as the path separator.
So, we don't need to normalize `%5c` as a path sep on Windows.
This changes type argument syntax to "standard" style, and away from turbofish.
The motivation here is that turbofish-style type arguments are hard to read, and developers who are not already deeply knowledgeable about Pkl might struggle to understand such code.
In most languages, the grammar for "method call with type args" don't introduce any additional symbols between the identifier and the type argument list (e.g. C++, TypeScript, C#, Scala, Go).
This adds changes such that URIs like `file:///path/to/%2E%2E/bar.txt`
are considered path traversal sequences.
These URIs are treated as dot segments, and normalized prior to calling
into security checks.
For package URIs, the same treatment is applied to the
URI fragment.
jar-file URIs are special-cased and normalized as well.
Additionally, `%2f` is treated as `/` for file, jar-file and asset path segments.
However, these are left alone for other URIs (RFC-3986 treats `%2e` as identical to `.`, but `%2f` as distinct from `/`)..
* VmObject.getRootFirstObject() is a recursive call, which sometimes
fails with "too deep inlining"
* Incorrect loop condition profile usage in some places
* Need to mark `checkedReturnTypeNode` final so that GraalVM knows
that it is PE constant
Motivation:
- VmObjectLike.iterateMemberValues() is an internal iterator whose loop body is a Java lambda.
It suffers from the following limitations:
- `continue` and `break` cannot be used.
- `return` becomes an (awkward) replacement for `continue` and `break`.
It cannot be used to return from the enclosing method.
- Mutating variables requires hoisting them (MutableBoolean, etc.).
- Node.execute() calls are very slow because they are behind a Truffle boundary.
- Callers of iterateMemberValues() do not specify what and how they want to iterate.
This obscures the iteration code and makes it difficult (often impossible) to optimize.
Changes:
- Add interface VmObjectCursor, an external iterator that iterates over VmObject members.
Its design is inspired by org.graalvm.collections.MapCursor.
- Add VmObjectCursor implementations specialized for different members, VmObject subclasses, and cursor options.
- Replace VmObjectLike.iterateMemberValues() with the following methods that return VmObjectCursor:
- properties()
- properties(CursorOption)
- elements()
- elements(CursorOption)
- entries()
- entries(CursorOption)
- members
- members(CursorOption)
- Replace all usages of iterateMemberValues() with one of the above methods.
Before: object.iterateMembersValues((key, member, value) -> { if (member.isProp()) {...} });
After : for (var cursor = object.properties(); cursor.advance(); ) {...}
Result:
- Iteration code is much simpler and clearer.
- Iteration code that calls Node.execute() is much faster because it is no longer behind a Truffle boundary.
- Other iteration code is potentially faster and can be better optimized in the future.
Co-authored-by: translatenix <119817707+translatenix@users.noreply.github.com>
Co-authored-by: Jen Basch <jbasch94@gmail.com>
This introduces a way to run CPU profiling.
The profiler produces output in pprof format.
CLI users can enable CPU profiling via command line flags.
Profiling is otherwise not offered as an API.
Co-authored-by: Jen Basch <jbasch94@gmail.com>
Co-authored-by: Islon Scherer <islonscherer@gmail.com>
This changes it to render the qualified name instead of the simple name.
* Module classes render the module name
* Classes within module render the module name and the class name joined by `#`
* Rendering of members of `pkl:base` does not change
For example:
* `new k8s.core.v1.Service {}` instead of `new ModuleClass {}`.
* `new k8s.core.v1.Service#ServiceSpec {}` instead of `new ServiceSpec {}`
* `new pkl.Project {}` instead of `new ModuleClass {}`
This affects the following:
* `toString()`
* `trace()`
* Error messages
* REPL
Currently the module cache directory in CLI commands (and thus in Gradle tasks, since they use CLI commands under the hood) is only used for the "primary" task. For example, for an eval command, the module cache directory will be used for the evaluation of the target module.
However, most commands also work with projects, and for projects the `PklProject` file must be evaluated. This is done via `Project.loadFromPath`, which internally builds an evaluator with the default module cache path. Therefore, all evaluations of project manifests always use default cache path instead of whatever is configured through the CLI option/Gradle task property. This, in turn, may result in unexpected behavior: in general, the user would expect that if they specify the cache directory, it will be used for all evaluations (e.g. when they pre-populate the cache and expect evaluations to work offline).
The same is true for settings evaluation, although for settings it is significantly less important since settings scripts can't have remote dependencies.
This PR propagates cache path into the project evaluator (as well as the settings evaluator, for consistency). This will result in the user-specified cache directory being used for `PklProject` evaluations as well.
Patterns that originate from the language runtime will add
`Pattern.UNICODE_CHARACTER_CLASS | Pattern.UNICODE_CASE` as implicit
regex flags, so we need to do the same on the binary decoding side.
* Compute a derived regex expression with `\z` anchor
* Ensure derived regex can't be messed up with comments (in extended mode) or quote start
Follow up to #1880
This adds logic to UnresolvedTypeNode to create a `UnionOfStringLiterals`
type node if a member is a typealias who is a string or a string literal union.
Also, this fixes an issue where marking a duplicate string literal with the
default marker throws an index out of bounds exception.
This makes various improvements to help truffle do partial
evaluation of code related to typechecking.
* Split `UnionTypeNode` into `UnionTypeNodeExploded` and
`UnionTypeNodeLooped` to avoid gigantic graphs. This especially helps
in the case of typealiases, because they are inlined into their usage
sites.
* Move constraint-failure exception construction in
`TypeConstraintNode` behind `@TruffleBoundary` helper methods
instead of `transferToInterpreterAndInvalidate`, since building the
exception is a rare, off-hot-path operation.
* Move `ClassNode`'s one-time class-initialization logic behind a
`@TruffleBoundary` method (`initClass`), store `VmLanguage` as a
field instead of recomputing it via `VmLanguage.get(this)`, and use
`transferToInterpreterAndInvalidate` since class init never needs to
re-run on the compiled path.
* Pass `VmLanguage` explicitly into `TypeTestNode` and `ClassNode`
(via `AstBuilder`) rather than resolving it with
`VmLanguage.get(this)` on a hot path.
* Fix various issues where the partial evaluator determines that a frame
should have been materialized but was not.
* Pre-initialize call targets in `ObjectMember.setMemberNode()` and
`FunctionLiteralNode` so the first invocation doesn't trigger a
compilation invalidation.
* Fix truffle node tree issues (don't mark `@RootNode` as child,
deepCopy instead of passing an already adopted node).
* Remove unnecessary interpreter transfers when throwing type mismatch exceptions
This changes the `join` method in `List`/`Set`/`Listing` to
call the overridden `toString()` method.
This is a breaking change, but is considered a bugfix.
Fix this printed warning during java compilation:
"Note: Some input files use unchecked or unsafe operations. Recompile with -Xlint:unchecked for details"
* Add `-Xlint:unchecked` as a javac flag
* Fix the various warnings
This changes the logic for inferring `new {}` expressions in method
arguments to using regular frame slots, instead of auxiliary slots.
Overall, this is a performance improvement: no looking up auxiliary slot
numbers, which makes this code much more PE friendly.
* At parse time, get or create a frame slot that holds the method
* Introduce `ArgInfo` record (preserve primitive int) over using `Pair`
* Remove unneeded `isImplicitNewExpr` method; this is not needed because
we can just keep track of the method slot on the frame descriptor
builder.
This changes code so that the in-language `toString()` doesn't use
Java's `Object.toString()`.
Additionally, the existing `toString()` implementation is switched over
to using `VmValueRenderer`, which does not force (leaves `?` in place of
unforced values).
This helps improve ergonomics when working on the language (can enable
automatically calling `toString()` on debug values).
Additionally, external tools might call toString(); for example,
Truffle's compiler sometimes will stringify node fields (e.g.
when -Dengine.CompilationFailureAction=Throw) is set.
* In GeneratorWhenNode, need to move individual iterations into their
own methods so that the @ExplodeLoop sees a constant number of
iterations whenever that method is called.
* In the other nodes, the lambda passed to
`forceAndIterateMemberValues` needs to capture the materialized frame,
not the virtual frame.
YamlEmitter only routed a string into YamlEscaper when it held a
character below 0x20, so 0x7F, the C1 block, U+2028 and U+2029 went out
as plain scalars. They are not `c-printable` (YAML 1.2 spec 5.1), and
NEL, LS and PS are line breaks in YAML 1.1, so the rendered document is
either rejected or silently split by a reader.
The escapes added in #1165 for 0x85, 0xA0, U+2028, and U+2029 could only
fire when some other character happened to open that gate. Share one
predicate between the two sites that decide, and give 0x7F-0x9F the
8-bit escape they lack.