Skip to content

Commit

Permalink
(compiler) Make compiled mode be the default and drop interpreted mode
Browse files Browse the repository at this point in the history
This is the biggest change for a while. Because
#406 is moving along
nicely, we are now ready to:

* Flip the switch, i.e. _make compiled mode the default_ for Perlang.
* Remove the PerlangInterpreter class in its entirety. This may be
  reimplemented in one form or another, once we have the LLVM-emitting
  backend in place, but not as a tree-walking interpreter.

This probably means we'll drop Windows (and perhaps macOS) support for a
while. Please don't despair; this is not intended to be permanent. While
we depend on a specific Clang version for compiling Perlang code, it
simply gets easier to not have to support too many platforms. Once we
have started emitting C++ code from Perlang, in an idempotent way (being
able to disable all timestamping etc in the file header), we could see
how hard it would be to get this Perlang-to-C++-transpiled code
compiling on macOS and Windows too.
  • Loading branch information
perlun committed Apr 25, 2024
1 parent 783c5df commit e124496
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 2,875 deletions.
14 changes: 5 additions & 9 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@ jobs:
strategy:
matrix:
runner:
- windows-2022
# Windows and maOS disabled as of https://github.com/perlang-org/perlang/pull/465. We are planning to
# reintroduce Windows and macOS support in the future, but for now, we are focusing on Linux for simplicity.
# Once we have a compiler which is C# and C++ (transpiled from Perlang), we should be able to build the
# compiler for these platforms, but getting rid of the "Linux-onliness" of the compiler really depends on
# moving to an LLVM-based backend, so we don't need to shell-execute clang++-14 to compile the C++ code.
- ubuntu-22.04
- macos-11
execution_mode:
- interpreted
include:
# Run in interpreted mode on all runners, but additionally also in compiled mode on Ubuntu
- runner: ubuntu-22.04
execution_mode: compiled

steps:
- uses: actions/checkout@v1
Expand All @@ -39,5 +36,4 @@ jobs:
- name: Run test suite
run: dotnet test --configuration Release --verbosity minimal
env:
PERLANG_EXPERIMENTAL_COMPILATION: ${{ matrix.execution_mode == 'compiled' && 'true' || 'false' }}
PERLANG_ROOT: ${{ github.workspace }}
14 changes: 14 additions & 0 deletions Perlang.sln
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "release-notes", "release-no
release-notes\v0.5.0.md = release-notes\v0.5.0.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{74DEE88F-82F6-49CB-A019-E527D293E0B4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{0220A61B-85BE-4076-9FDA-0467E6971F40}"
ProjectSection(SolutionItems) = preProject
.github\workflows\perlang-install.yml = .github\workflows\perlang-install.yml
.github\workflows\publish-release-packages.yml = .github\workflows\publish-release-packages.yml
.github\workflows\publish-snapshot-packages.yml = .github\workflows\publish-snapshot-packages.yml
.github\workflows\publish-website.yml = .github\workflows\publish-website.yml
.github\workflows\test.yml = .github\workflows\test.yml
.github\workflows\website.yml = .github\workflows\website.yml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -99,5 +111,7 @@ Global
{E9D632CB-E520-4868-9E64-A4A70ACD713C} = {F13F8E4E-5231-4321-9722-1BFCC08E5BB5}
{7E7CF7BF-F792-49C9-BB16-67FE856D8D51} = {B924E83B-6AFE-4ABF-B79D-444F92582892}
{3223DBA6-64AE-41B5-8864-6FDD232FCE7F} = {47B4A37F-6999-4510-9815-418E03D7B39E}
{74DEE88F-82F6-49CB-A019-E527D293E0B4} = {47B4A37F-6999-4510-9815-418E03D7B39E}
{0220A61B-85BE-4076-9FDA-0467E6971F40} = {74DEE88F-82F6-49CB-A019-E527D293E0B4}
EndGlobalSection
EndGlobal
2 changes: 2 additions & 0 deletions release-notes/v0.5.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- Remove `using namespace` in generated C++ code [[#458][458]]
- Add partial inline C++ support [[#462][462]]
- Detect method being redefined [[#464][464]]
- Make compiled mode be the default and drop interpreted mode [[#465][465]]

### Changed
#### Data types
Expand Down Expand Up @@ -49,3 +50,4 @@
[462]: https://github.com/perlang-org/perlang/pull/462
[463]: https://github.com/perlang-org/perlang/pull/463
[464]: https://github.com/perlang-org/perlang/pull/464
[465]: https://github.com/perlang-org/perlang/pull/465
12 changes: 9 additions & 3 deletions src/Perlang.Common/PerlangMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ namespace Perlang;

public static class PerlangMode
{
public static bool ExperimentalCompilation
public static bool ExperimentalCompilation => !ExperimentalInterpretation;

private static bool ExperimentalInterpretation
{
get
{
string environmentVariable = Environment.GetEnvironmentVariable("PERLANG_EXPERIMENTAL_COMPILATION");
// This used to be an environment variable PERLANG_EXPERIMENTAL_COMPILATION. Now that compilation is enabled
// by default, we have flipped the flag to instead be PERLANG_EXPERIMENTAL_INTERPRETATION. The interpreter
// part (which will in fact emit native code via an LLVM backend) is not yet implemented, but we're keeping
// the infrastructure in place to make room for it until if/when it gets implemented.
string environmentVariable = Environment.GetEnvironmentVariable("PERLANG_EXPERIMENTAL_INTERPRETATION");

// The environment variable takes precedence, if set
if (Boolean.TryParse(environmentVariable, out bool flag))
Expand All @@ -19,7 +25,7 @@ public static bool ExperimentalCompilation

string homeDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);

return File.Exists(Path.Combine(homeDirectory, ".perlang_experimental_compilation"));
return File.Exists(Path.Combine(homeDirectory, ".perlang_experimental_interpretation"));
}
}
}
41 changes: 4 additions & 37 deletions src/Perlang.ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
using System.Text;
using System.Threading.Tasks;
using Perlang.Compiler;
using Perlang.Internal;
using Perlang.Interpreter;
using Perlang.Interpreter.Compiler;
using Perlang.Interpreter.NameResolution;
Expand Down Expand Up @@ -56,7 +55,6 @@ internal enum ExitCodes
INVALID_ARGUMENT = 67
}

private readonly PerlangInterpreter interpreter;
private readonly PerlangCompiler compiler;

/// <summary>
Expand All @@ -81,11 +79,6 @@ internal enum ExitCodes

private readonly HashSet<WarningType> disabledWarningsAsErrors;

/// <summary>
/// A flag which determines if (highly experimental) compilation to machine code is enabled or not.
/// </summary>
private readonly bool experimentalCompilation;

private bool hadError;
private bool hadRuntimeError;

Expand Down Expand Up @@ -267,20 +260,11 @@ public static int Main(string[] args)
this.standardOutputHandler = standardOutputHandler;
this.standardErrorHandler = standardOutputHandler;
this.disabledWarningsAsErrors = (disabledWarningsAsErrors ?? Enumerable.Empty<WarningType>()).ToHashSet();
this.experimentalCompilation = experimentalCompilation;

// Convenience fields while we are migrating away from CLR strings to Perlang strings.
this.standardOutputHandlerFromClrString = s => this.standardOutputHandler(Lang.String.from(s));
this.standardErrorHandlerFromClrString = s => this.standardErrorHandler(Lang.String.from(s));

interpreter = new PerlangInterpreter(
runtimeErrorHandler ?? RuntimeError,
this.standardOutputHandler,
null,
arguments ?? new List<string>(),
replMode: replMode
);

compiler = new PerlangCompiler(
runtimeErrorHandler ?? RuntimeError,
this.standardOutputHandler
Expand All @@ -298,14 +282,7 @@ private int RunFile(string path)
var bytes = File.ReadAllBytes(path);
string source = Encoding.UTF8.GetString(bytes);

if (experimentalCompilation)
{
CompileAndRun(source, path, CompilerWarning);
}
else
{
Run(source, CompilerWarning);
}
CompileAndRun(source, path, CompilerWarning);

// Indicate an error in the exit code.
if (hadError)
Expand Down Expand Up @@ -350,18 +327,6 @@ private int CompileAndAssembleFile(string path)
return (int)ExitCodes.SUCCESS;
}

internal int Run(string source, CompilerWarningHandler compilerWarningHandler)
{
object? result = interpreter.Eval(source, ScanError, ParseError, NameResolutionError, ValidationError, ValidationError, compilerWarningHandler);

if (result != null && result != VoidObject.Void)
{
standardOutputHandler(Utils.Stringify(result));
}

return (int)ExitCodes.SUCCESS;
}

private void CompileAndRun(string source, string path, CompilerWarningHandler compilerWarningHandler)
{
compiler.CompileAndRun(source, path, CompilerFlags.None, ScanError, ParseError, NameResolutionError, ValidationError, ValidationError, compilerWarningHandler);
Expand All @@ -374,7 +339,9 @@ private void CompileAndAssemble(string source, string path, CompilerWarningHandl

private void ParseAndPrint(string source)
{
string? result = interpreter.Parse(source, ScanError, ParseError);
// TODO: Implement this in PerlangCompiler. Should definitely be doable, and could be taken in a nice little
// TODO: isolated PR of its own.
string? result = compiler.Parse(source, ScanError, ParseError);

if (result == null)
{
Expand Down
9 changes: 7 additions & 2 deletions src/Perlang.Interpreter/Compiler/PerlangCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ private static bool CompilationCacheDisabled
}
}

internal IBindingHandler BindingHandler { get; }

private readonly Action<RuntimeError> runtimeErrorHandler;
private readonly Action<Lang.String> standardOutputHandler;
private readonly PerlangEnvironment globals = new();
Expand All @@ -97,8 +99,6 @@ private static bool CompilationCacheDisabled
private readonly ImmutableDictionary<string, Type> nativeClasses;
private readonly IDictionary<string, Method> methods;

private IBindingHandler BindingHandler { get; }

private StringBuilder currentMethod;

private int indentationLevel = 1;
Expand Down Expand Up @@ -1562,4 +1562,9 @@ private record Method(string Name, IImmutableList<Parameter> Parameters, string
)
);
}

public string? Parse(string source, Action<ScanError> scanError, Action<ParseError> parseError)
{
throw new NotImplementedException();
}
}

0 comments on commit e124496

Please sign in to comment.