using System; using System.Text; using Upsilon.BaseTypes; using Upsilon.BaseTypes.Number; using Upsilon.Binder; using Type = Upsilon.BaseTypes.Type; namespace UpsilonCompiler { public class Transpiler { public string TranspilerToCSharp(BoundScript script) { var s = script.Statement; return Transpile(s); } private string Transpile(BoundNode e) { switch (e.Kind) { case BoundKind.BoundScript: throw new ArgumentOutOfRangeException(); case BoundKind.BoundLiteralExpression: return TranspileLiteralExpression((BoundLiteralExpression) e); case BoundKind.BoundBinaryExpression: return TranspileBinaryExpression((BoundBinaryExpression) e); case BoundKind.BoundUnaryExpression: case BoundKind.VariableExpression: case BoundKind.BoundAssignmentStatement: throw new ArgumentOutOfRangeException(); case BoundKind.BoundExpressionStatement: return Transpile(((BoundExpressionStatement)e).Expression); case BoundKind.BoundBlockStatement: return TranspileBlockStatement((BoundBlockStatement) e); case BoundKind.BoundIfStatement: return TranspileIfStatement((BoundIfStatement) e); case BoundKind.BoundElseStatement: default: throw new ArgumentOutOfRangeException(e.Kind.ToString()); } } private string TranspileBlockStatement(BoundBlockStatement s) { var sb = new StringBuilder(); foreach (var sStatement in s.Statements) { var compile = Transpile(sStatement); sb.Append(compile); sb.Append(";\n"); } return sb.ToString(); } private static string TranspileLiteralExpression(BoundLiteralExpression e) { switch (e.Type) { case Type.Nil: return "null"; case Type.Boolean: return ((LuaBoolean)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 TranspileBinaryExpression(BoundBinaryExpression e) { var sb = new StringBuilder(); sb.Append("("); var compiledLeft = Transpile(e.LeftExpression); var compiledRight = Transpile(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 TranspileIfStatement(BoundIfStatement s, bool isElseIf = false) { var sb = new StringBuilder(); var openToken = isElseIf ? "else if(" : "if("; sb.Append(openToken); var compiledCondition = Transpile(s.Condition); sb.Append(compiledCondition); sb.Append("){\n"); var compiledBlock = Transpile(s.Block); sb.Append(compiledBlock); sb.Append("}"); return sb.ToString(); } } }