-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNode.cs
More file actions
139 lines (120 loc) · 5.31 KB
/
Node.cs
File metadata and controls
139 lines (120 loc) · 5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using Samples.Utilities;
namespace Samples.TinyC;
public abstract record Node
{
public static Node Empty() => new BlockNode([]);
public static Node Number(int value) => new NumberNode(value);
public static Node Variable(string name) => new VariableNode(name);
public static Node If(Node test, Node ifTrue, Node ifFalse) => new IfNode(test, Wrap(ifTrue), Wrap(ifFalse));
public static Node Ternary(Node test, Node ifTrue, Node ifFalse) => new TernaryNode(test, ifTrue, ifFalse);
public static Node WhileLoop(Node test, Node body) => new WhileLoopNode(test, Wrap(body));
public static Node DoWhileLoop(Node test, Node body) => new DoWhileLoopNode(test, Wrap(body));
public static Node Unary(char op, Node operand) => new UnaryNode(op, operand);
public static Node Binary(string op, Node left, Node right) => new BinaryNode(op, left, right);
public static Node Assign(Node variable, Node value) => Binary("=", variable, value);
public static Node Block(IReadOnlyList<Node> statements) => new BlockNode(statements);
private static Node Wrap(Node statement) => statement is BlockNode ? statement : new BlockNode([statement]);
public sealed override string ToString()
{
var sb = new IndentedStringBuilder();
Print(this, sb);
return sb.ToString();
static void Print(Node node, IndentedStringBuilder sb)
{
switch (node)
{
case VariableNode(Name: var name):
sb.Append(name);
break;
case NumberNode(Value: var number):
sb.Append(number);
break;
case IfNode c:
sb.Append("if (");
Print(c.Test, sb);
sb.Append(')');
sb.AppendLine();
Print(c.IfTrue, sb);
if (c.IfFalse is BlockNode { Statements: [IfNode ifElse] })
{
sb.Append("else ");
Print(ifElse, sb);
}
else if (c.IfFalse is not BlockNode([]))
{
sb.Append("else");
sb.AppendLine();
Print(c.IfFalse, sb);
}
break;
case TernaryNode c:
Print(c.Test, sb);
sb.IncrementIndent();
sb
.AppendLine()
.Append("? ");
Print(c.IfTrue, sb);
sb
.AppendLine()
.Append(": ");
Print(c.IfFalse, sb);
sb.DecrementIndent();
break;
case WhileLoopNode w:
sb.Append("while (");
Print(w.Test, sb);
sb.Append(')');
sb.AppendLine();
Print(w.Body, sb);
break;
case DoWhileLoopNode d:
sb.AppendLine("do");
Print(d.Body, sb);
sb.Append("while (");
Print(d.Test, sb);
sb.AppendLine(");");
break;
case UnaryNode u:
sb.Append(u.Operator);
sb.Append('(');
Print(u.Operand, sb);
sb.Append(')');
break;
case BinaryNode(Operator: "=", var variable, var expr):
Print(variable, sb);
sb.Append(" = (");
Print(expr, sb);
sb.Append(')');
break;
case BinaryNode b:
sb.Append('(');
Print(b.Left, sb);
sb.Append($" {b.Operator} ");
Print(b.Right, sb);
sb.Append(')');
break;
case BlockNode block:
sb.AppendLine("{");
sb.IncrementIndent();
foreach (var stmt in block.Statements)
{
Print(stmt, sb);
if (stmt is NumberNode or VariableNode or UnaryNode or BinaryNode)
sb.AppendLine(";");
}
sb.DecrementIndent();
sb.AppendLine("}");
break;
}
}
}
public sealed record VariableNode(string Name) : Node;
public sealed record NumberNode(int Value) : Node;
public sealed record IfNode(Node Test, Node IfTrue, Node IfFalse) : Node;
public sealed record TernaryNode(Node Test, Node IfTrue, Node IfFalse) : Node;
public sealed record WhileLoopNode(Node Test, Node Body) : Node;
public sealed record DoWhileLoopNode(Node Test, Node Body) : Node;
public sealed record UnaryNode(char Operator, Node Operand) : Node;
public sealed record BinaryNode(string Operator, Node Left, Node Right) : Node;
public sealed record BlockNode(IReadOnlyList<Node> Statements) : Node;
}