diff --git a/Upsilon.sln b/Upsilon.sln index a1d6b1d..3e3d066 100644 --- a/Upsilon.sln +++ b/Upsilon.sln @@ -6,6 +6,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yc", "Yc\Yc.csproj", "{EF23 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UpsilonTests", "UpsilonTests\UpsilonTests.csproj", "{5CB3C59D-96A1-419E-803B-DE4A7DF806FD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UpsilonCompiler", "UpsilonCompiler\UpsilonCompiler.csproj", "{BC98BE8D-D3F5-46CC-9873-51F19D8E05C1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,5 +26,9 @@ Global {5CB3C59D-96A1-419E-803B-DE4A7DF806FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {5CB3C59D-96A1-419E-803B-DE4A7DF806FD}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CB3C59D-96A1-419E-803B-DE4A7DF806FD}.Release|Any CPU.Build.0 = Release|Any CPU + {BC98BE8D-D3F5-46CC-9873-51F19D8E05C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC98BE8D-D3F5-46CC-9873-51F19D8E05C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC98BE8D-D3F5-46CC-9873-51F19D8E05C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC98BE8D-D3F5-46CC-9873-51F19D8E05C1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Upsilon/Evaluator/Script.cs b/Upsilon/Evaluator/Script.cs index 5fb6334..11e36f4 100644 --- a/Upsilon/Evaluator/Script.cs +++ b/Upsilon/Evaluator/Script.cs @@ -24,16 +24,19 @@ namespace Upsilon.Evaluator Evaluator = new Evaluator(this, Diagnostics, variables); } + public BoundScript Bind() + { + return Binder.BindScript(_parsed); + } + public object Evaluate() { - var bound = Binder.BindScript(_parsed); - return Evaluator.Evaluate(bound); + return Evaluator.Evaluate(Bind()); } public T Evaluate() { - var bound = Binder.BindScript(_parsed); - return (T)Evaluator.Evaluate(bound); + return (T)Evaluator.Evaluate(Bind()); } } } \ No newline at end of file diff --git a/UpsilonCompiler/Compiler.cs b/UpsilonCompiler/Compiler.cs new file mode 100644 index 0000000..7d61ca8 --- /dev/null +++ b/UpsilonCompiler/Compiler.cs @@ -0,0 +1,127 @@ +using System; +using System.Text; +using Upsilon.BaseTypes.Number; +using Upsilon.Binder; +using System.Collections.Immutable; +using Type = Upsilon.BaseTypes.Type; + +namespace UpsilonCompiler +{ + public class Compiler + { + public string CompileToCSharp(BoundScript script) + { + var s = script.Statement; + return Compile(s); + } + + private string Compile(BoundNode e) + { + switch (e.Kind) + { + case BoundKind.BoundScript: + throw new ArgumentOutOfRangeException(); + case BoundKind.BoundLiteralExpression: + return CompileLiteralExpression((BoundLiteralExpression) e); + case BoundKind.BoundBinaryExpression: + return CompileBinaryExpression((BoundBinaryExpression) e); + case BoundKind.BoundUnaryExpression: + case BoundKind.VariableExpression: + case BoundKind.BoundAssignmentStatement: + throw new ArgumentOutOfRangeException(); + case BoundKind.BoundExpressionStatement: + return Compile(((BoundExpressionStatement)e).Expression); + case BoundKind.BoundBlockStatement: + return CompileBlockStatement((BoundBlockStatement) e); + case BoundKind.BoundIfStatement: + return CompileIfStatement((BoundIfStatement) e); + case BoundKind.BoundElseStatement: + default: + throw new ArgumentOutOfRangeException(e.Kind.ToString()); + } + } + + private string CompileBlockStatement(BoundBlockStatement s) + { + var sb = new StringBuilder(); + foreach (var sStatement in s.Statements) + { + var compile = Compile(sStatement); + sb.Append(compile); + sb.Append(";\n"); + } + return sb.ToString(); + } + + private string CompileLiteralExpression(BoundLiteralExpression e) + { + switch (e.Type) + { + case Type.Nil: + return "null"; + case Type.Boolean: + return ((bool)e.Value) ? "true" : "false"; + case Type.Number: + return ((Number) e.Value).ToString(); + case Type.String: + case Type.Function: + case Type.UserData: + case Type.Thread: + case Type.Table: + default: + throw new ArgumentOutOfRangeException(); + } + } + + private string CompileBinaryExpression(BoundBinaryExpression e) + { + var sb = new StringBuilder(); + sb.Append("("); + var compiledLeft = Compile(e.LeftExpression); + var compiledRight = Compile(e.RightExpression); + sb.Append(compiledLeft); + switch (e.Operator.Kind) + { + case BoundBinaryOperator.OperatorKind.Addition: + sb.Append("+"); + break; + case BoundBinaryOperator.OperatorKind.Subtraction: + sb.Append("-"); + break; + case BoundBinaryOperator.OperatorKind.Multiplication: + sb.Append("*"); + break; + case BoundBinaryOperator.OperatorKind.Division: + sb.Append("/"); + break; + case BoundBinaryOperator.OperatorKind.Equality: + sb.Append("=="); + break; + case BoundBinaryOperator.OperatorKind.Inequality: + sb.Append("!="); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + sb.Append(compiledRight); + sb.Append(")"); + return sb.ToString(); + } + + private string CompileIfStatement(BoundIfStatement s, bool isElseIf = false) + { + var sb = new StringBuilder(); + var openToken = isElseIf ? "else if(" : "if("; + sb.Append(openToken); + var compiledCondition = Compile(s.Condition); + sb.Append(compiledCondition); + sb.Append("){\n"); + var compiledBlock = Compile(s.Block); + sb.Append(compiledBlock); + sb.Append("}"); + return sb.ToString(); + } + } + +} \ No newline at end of file diff --git a/UpsilonCompiler/UpsilonCompiler.csproj b/UpsilonCompiler/UpsilonCompiler.csproj new file mode 100644 index 0000000..21b7f78 --- /dev/null +++ b/UpsilonCompiler/UpsilonCompiler.csproj @@ -0,0 +1,17 @@ + + + + netstandard2.0 + UpsilonCompiler + + + + + + + + ..\..\..\..\..\usr\share\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Collections.Immutable.dll + + + + diff --git a/Yc/Program.cs b/Yc/Program.cs index 8c38ab9..4d65d73 100644 --- a/Yc/Program.cs +++ b/Yc/Program.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Upsilon; using Upsilon.Binder; using Upsilon.Evaluator; +using UpsilonCompiler; namespace Yc { @@ -34,6 +35,10 @@ namespace Yc continue; } + var compiler = new Compiler(); + var compiled = compiler.CompileToCSharp(parsed.Bind()); + Console.WriteLine(compiled); + /* var evaluate = parsed.Evaluate(); if (parsed.Diagnostics.Messages.Count > 0) { @@ -50,7 +55,7 @@ namespace Yc Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine(evaluate); Console.ResetColor(); - } + }*/ } } diff --git a/Yc/Yc.csproj b/Yc/Yc.csproj index 17d46f1..c51c094 100644 --- a/Yc/Yc.csproj +++ b/Yc/Yc.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,6 +6,7 @@ +