Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 125 additions & 21 deletions tools/lib/ponylang/pony_compiler/pony_compiler/pass.pony
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,131 @@ type PassId is (
PassASM | PassObj | PassAll
)

primitive PassParse fun apply(): I32 => 0
primitive PassSyntax fun apply(): I32 => 1
primitive PassSugar fun apply(): I32 => 2
primitive PassScope fun apply(): I32 => 3
primitive PassImport fun apply(): I32 => 4
primitive PassNameResolution fun apply(): I32 => 5
primitive PassFlatten fun apply(): I32 => 6
primitive PassTraits fun apply(): I32 => 7
primitive PassRefer fun apply(): I32 => 8
primitive PassExpr fun apply(): I32 => 9
primitive PassCompleteness fun apply(): I32 => 10
primitive PassVerify fun apply(): I32 => 11
primitive PassFinaliser fun apply(): I32 => 12
primitive PassSerialiser fun apply(): I32 => 13
primitive PassReach fun apply(): I32 => 14
primitive PassPaint fun apply(): I32 => 15
primitive PassLLVMIR fun apply(): I32 => 16
primitive PassBitcode fun apply(): I32 => 17
primitive PassASM fun apply(): I32 => 18
primitive PassObj fun apply(): I32 => 19
primitive PassAll fun apply(): I32 => 20
primitive PassParse is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 0
fun string(): String iso^ => recover String .> append("parse") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassSyntax is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 1
fun string(): String iso^ => recover String .> append("syntax") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassSugar is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 2
fun string(): String iso^ => recover String .> append("sugar") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassScope is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 3
fun string(): String iso^ => recover String .> append("scope") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassImport is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 4
fun string(): String iso^ => recover String .> append("import") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassNameResolution is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 5
fun string(): String iso^ => recover String .> append("name resolution") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassFlatten is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 6
fun string(): String iso^ => recover String .> append("flatten") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassTraits is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 7
fun string(): String iso^ => recover String .> append("traits") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassRefer is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 8
fun string(): String iso^ => recover String .> append("refer") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassExpr is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 9
fun string(): String iso^ => recover String .> append("expr") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassCompleteness is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 10
fun string(): String iso^ => recover String .> append("completeness") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassVerify is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 11
fun string(): String iso^ => recover String .> append("verify") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassFinaliser is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 12
fun string(): String iso^ => recover String .> append("finaliser") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassSerialiser is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 13
fun string(): String iso^ => recover String .> append("serialiser") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassReach is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 14
fun string(): String iso^ => recover String .> append("reach") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassPaint is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 15
fun string(): String iso^ => recover String .> append("paint") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassLLVMIR is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 16
fun string(): String iso^ => recover String .> append("LLVM IR") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassBitcode is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 17
fun string(): String iso^ => recover String .> append("bitcode") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassASM is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 18
fun string(): String iso^ => recover String .> append("asm") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassObj is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 19
fun string(): String iso^ => recover String .> append("obj") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive PassAll is (Equatable[PassId] & Comparable[PassId])
fun apply(): I32 => 20
fun string(): String iso^ => recover String .> append("all") end
fun eq(that: box->PassId): Bool => this.apply() == that.apply()
fun lt(that: box->PassId): Bool => this.apply().lt(that.apply())

primitive _StrList
"""STUB"""
Expand Down
100 changes: 76 additions & 24 deletions tools/pony-lsp/compiler_notify.pony
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use "pony_compiler"
use "term"
use "cli"
use "files"
use "collections"
use "term"

use "pony_compiler"

use @get_compiler_exe_directory[Bool](
output_path: Pointer[U8] tag,
Expand All @@ -11,9 +13,10 @@ use @ponyint_pool_free_size[None](size: USize, p: Pointer[U8] tag)

actor PonyCompiler is LspCompiler
"""
Actor wrapping the pony_compiler `Compiler`
primitive to serialize compilation requests
(libponyc is not fully thread-safe).
Actor wrapping the pony_compiler `CompileSession`
to serialize compilation requests.

Compilation will notify the caller for each requested pass.

Determines the ponyc standard library location
automatically by finding the executable directory
Expand Down Expand Up @@ -113,10 +116,23 @@ actor PonyCompiler is LspCompiler
be compile(
package: FilePath,
paths: Array[String val] val,
notify: CompilerNotify tag)
notify: CompilerNotify tag,
notify_passes: Array[PassId] val = [PassFinaliser])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trait definition of this behavior doesn't include the default value. Is that a problem?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so.

=>
"""
Compile a package with the given paths.

Notify `notify` for every pass provided in `notify_passes`. The default is
to only notify once for the result of the finaliser pass.

If an error happens while compiling up to the next pass, the `notify` will
be notified about the errors and no more notifications will arrive.

Compilation is done when either the `result` param of
`CompilerNotify.on_compile_result()` is an Array of errors or if the `pass`
is the last one in the `notify_passes`.

If `notify_passes` is empty, `notify` will never be called.
"""
if not this._got_settings then
// enqueue compilation and dont execute it yet
Expand All @@ -136,17 +152,45 @@ actor PonyCompiler is LspCompiler
tmp.append(paths)
tmp
end
let result =
Compiler.compile(
package,
package_paths
where
user_flags = this._defines,
release = false,
verbosity = VerbosityQuiet,
limit = PassFinaliser)
let run_id = _run_id_gen = _run_id_gen + 1
notify.done_compiling(package, result, run_id)
let sorted_passes = Sort[Array[PassId], PassId](notify_passes.clone())
try
let first_pass = sorted_passes.shift()?
let run_id = _run_id_gen = _run_id_gen + 1
let session =
CompileSession.create(
package,
package_paths
where
user_flags = this._defines,
release = false,
verbosity = VerbosityQuiet,
limit = first_pass)
try
let program = session.program() as Program val
notify.on_compile_result(package, run_id, first_pass, program)
for pass in sorted_passes.values() do
if session.continue_to(pass) then
// compilation success up until pass
let result =
try
session.program() as Program val
else
session.errors()
end
notify.on_compile_result(package, run_id, pass, result)
else
// compile error
notify.on_compile_result(package, run_id, pass, session.errors())
// don't continue upon errors
break
end
end
else
// compile error up until first pass
notify.on_compile_result(package, run_id, first_pass, session.errors())
end
session.dispose()
end

trait tag LspCompiler
"""
Expand All @@ -164,20 +208,28 @@ trait tag LspCompiler
be compile(
package: FilePath,
paths: Array[String val] val,
notify: CompilerNotify tag)
notify: CompilerNotify tag,
notify_passes: Array[PassId] val)
"""
Compile the given package.
Compile the given package and call the `notify` with the compilation result
after the provided passes in `notify_passes`.
"""

interface CompilerNotify
"""
Notify which is called by the compiler when it is done.
Notify which is called by the compiler when it is done with a requested pass.
"""

be done_compiling(
be on_compile_result(
package: FilePath,
result: (Program val | Array[Error val] val),
run: USize)
compile_run: USize,
pass: PassId,
result: (Program val | Array[Error val] val)
)
"""
Called when compilation completes.
Called when a compilation result after the provided pass is available.

Do not keep the Program or any part of it around without copying,
if further passes are executed.
The underlying AST might be modified and parts of it replaced and deleted.
"""
3 changes: 1 addition & 2 deletions tools/pony-lsp/language_server.pony
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,7 @@ actor LanguageServer is (Notifier & RequestSender)
"[" + n.method + "] No workspace found for '" +
n.json().string() + "'")
end
| Methods.workspace().did_change_configuration()
=>
| Methods.workspace().did_change_configuration() =>
try
let settings =
JsonPathParser.compile("$.settings")?.query_one(n.params) as JsonValue
Expand Down
4 changes: 3 additions & 1 deletion tools/pony-lsp/test/message_handler.pony
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use ".."
use "pony_test"
use "pony_compiler"
use "files"

actor TestCompiler is LspCompiler
Expand Down Expand Up @@ -40,7 +41,8 @@ actor TestCompiler is LspCompiler
be compile(
package: FilePath,
paths: Array[String val] val,
notify: CompilerNotify tag)
notify: CompilerNotify tag,
notify_passes: Array[PassId] val)
=>
"""
Most efficient compiler ever.
Expand Down
12 changes: 6 additions & 6 deletions tools/pony-lsp/workspace/state.pony
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,6 @@ class PackageState
end
end

fun ref add_diagnostic(run_id: USize, diagnostic: Diagnostic) =>
if run_id >= this._compiler_run_id then
this._compiler_run_id = run_id
// TODO:
end

fun dispose() =>
for doc_state in this.documents.values() do
doc_state.dispose()
Expand Down Expand Up @@ -133,6 +127,10 @@ class DocumentState
compiler_run_id = 0

fun ref update(run_id: USize, module': Module val) =>
"""
Update the state of this document from the successful compilation from run
`run_id` with the given `module'`.
"""
if run_id >= this.compiler_run_id then
this.compiler_run_id = run_id
// clear out diagnostics
Expand All @@ -144,6 +142,8 @@ class DocumentState
FromCompilerRun[Array[DocumentSymbol]]
.create(run_id, DocumentSymbols.from_module(module', this._channel))
this._hash.update(run_id, module'.hash())
// compilation was successful, clear out document diagnostics
this._diagnostics.update(run_id, [])
end

fun ref add_diagnostic(run_id: USize, diagnostic: Diagnostic) =>
Expand Down
Loading
Loading