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(); } } }