Skip to content

Commit fa8a29b

Browse files
committed
Fixed issue Wouterdek#28
1 parent a2745df commit fa8a29b

17 files changed

+145
-40
lines changed

ExampleCodeGenApp/ExampleCodeGenApp.csproj

+3-1
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,15 @@
130130
<SubType>Designer</SubType>
131131
</ApplicationDefinition>
132132
<Compile Include="Model\Compiler\CompilerContext.cs" />
133+
<Compile Include="Model\Compiler\Error\CompilerException.cs" />
134+
<Compile Include="Model\Compiler\Error\VariableOutOfScopeException.cs" />
133135
<Compile Include="Model\ForLoop.cs" />
134136
<Compile Include="Model\FunctionCall.cs" />
135137
<Compile Include="Model\Compiler\ITypedExpression.cs" />
136138
<Compile Include="Model\InlineVariableDefinition.cs" />
137139
<Compile Include="Model\IntLiteral.cs" />
138140
<Compile Include="Model\Compiler\IStatement.cs" />
139-
<Compile Include="Model\IVariableDefinition.cs" />
141+
<Compile Include="Model\ITypedVariableDefinition.cs" />
140142
<Compile Include="Model\StatementSequence.cs" />
141143
<Compile Include="Model\StringLiteral.cs" />
142144
<Compile Include="Model\LocalVariableDefinition.cs" />

ExampleCodeGenApp/Model/Compiler/CompilerContext.cs

+28-6
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,50 @@
66

77
namespace ExampleCodeGenApp.Model.Compiler
88
{
9+
public class ScopeDefinition
10+
{
11+
public string Identifier { get; }
12+
13+
public List<IVariableDefinition> Variables { get; } = new List<IVariableDefinition>();
14+
15+
public ScopeDefinition(string identifier)
16+
{
17+
Identifier = identifier;
18+
}
19+
}
20+
921
public class CompilerContext
1022
{
11-
public Stack<List<string>> VariablesScopesStack { get; } = new Stack<List<string>>();
23+
public Stack<ScopeDefinition> VariablesScopesStack { get; } = new Stack<ScopeDefinition>();
1224

1325
public string FindFreeVariableName()
1426
{
15-
return "v" + VariablesScopesStack.SelectMany(l => l).Count();
27+
return "v" + VariablesScopesStack.SelectMany(s => s.Variables).Count();
1628
}
1729

18-
public void AddVariableToCurrentScope(string variableName)
30+
public void AddVariableToCurrentScope(IVariableDefinition variable)
1931
{
20-
VariablesScopesStack.Peek().Add(variableName);
32+
VariablesScopesStack.Peek().Variables.Add(variable);
2133
}
2234

23-
public void EnterNewScope()
35+
public void EnterNewScope(string scopeIdentifier)
2436
{
25-
VariablesScopesStack.Push(new List<string>());
37+
VariablesScopesStack.Push(new ScopeDefinition(scopeIdentifier));
2638
}
2739

2840
public void LeaveScope()
2941
{
3042
VariablesScopesStack.Pop();
3143
}
44+
45+
public bool IsInScope(IVariableDefinition variable)
46+
{
47+
if (variable == null)
48+
{
49+
return false;
50+
}
51+
52+
return VariablesScopesStack.Any(s => s.Variables.Contains(variable));
53+
}
3254
}
3355
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace ExampleCodeGenApp.Model.Compiler.Error
8+
{
9+
public class CompilerException : Exception
10+
{
11+
public CompilerException(string msg) : base(msg)
12+
{ }
13+
14+
public CompilerException(string msg, Exception inner) : base(msg, inner)
15+
{ }
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace ExampleCodeGenApp.Model.Compiler.Error
8+
{
9+
public class VariableOutOfScopeException : CompilerException
10+
{
11+
public string VariableName { get; }
12+
13+
public VariableOutOfScopeException(string variableName)
14+
: base($"The variable '{variableName}' was referenced outside its scope.")
15+
{
16+
VariableName = variableName;
17+
}
18+
}
19+
}

ExampleCodeGenApp/Model/Compiler/ITypedExpression.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace ExampleCodeGenApp.Model.Compiler
88
{
99
public interface IExpression
1010
{
11-
string Compile();
11+
string Compile(CompilerContext context);
1212
}
1313

1414
public interface ITypedExpression<T> : IExpression

ExampleCodeGenApp/Model/ForLoop.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ public class ForLoop : IStatement
1919

2020
public string Compile(CompilerContext context)
2121
{
22-
context.EnterNewScope();
22+
context.EnterNewScope("For loop");
2323

2424
CurrentIndex.Value = LowerBound;
25-
string code = $"for {CurrentIndex.Compile(context)}, {UpperBound.Compile()} do\n" +
25+
string code = $"for {CurrentIndex.Compile(context)}, {UpperBound.Compile(context)} do\n" +
2626
LoopBody.Compile(context) + "\n" +
2727
$"end\n" +
2828
LoopEnd.Compile(context) + "\n";

ExampleCodeGenApp/Model/FunctionCall.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class FunctionCall : IStatement
1414

1515
public string Compile(CompilerContext context)
1616
{
17-
return $"{FunctionName}({String.Join(", ", Parameters.Select(p => p.Compile()))})\n";
17+
return $"{FunctionName}({String.Join(", ", Parameters.Select(p => p.Compile(context)))})\n";
1818
}
1919
}
2020
}

ExampleCodeGenApp/Model/IVariableDefinition.cs renamed to ExampleCodeGenApp/Model/ITypedVariableDefinition.cs

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77

88
namespace ExampleCodeGenApp.Model
99
{
10-
interface IVariableDefinition<T> : IStatement
10+
public interface IVariableDefinition : IStatement
1111
{
1212
string VariableName { get; }
1313
}
14+
15+
public interface ITypedVariableDefinition<T> : IVariableDefinition
16+
{
17+
}
1418
}

ExampleCodeGenApp/Model/InlineVariableDefinition.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@
77

88
namespace ExampleCodeGenApp.Model
99
{
10-
public class InlineVariableDefinition<T> : IVariableDefinition<T>
10+
public class InlineVariableDefinition<T> : ITypedVariableDefinition<T>
1111
{
1212
public string VariableName { get; private set; }
1313
public ITypedExpression<T> Value { get; set; }
1414

1515
public string Compile(CompilerContext context)
1616
{
1717
VariableName = context.FindFreeVariableName();
18-
context.AddVariableToCurrentScope(VariableName);
19-
return $"{VariableName} = {Value.Compile()}";
18+
context.AddVariableToCurrentScope(this);
19+
return $"{VariableName} = {Value.Compile(context)}";
2020
}
2121
}
2222
}

ExampleCodeGenApp/Model/IntLiteral.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class IntLiteral : ITypedExpression<int>
1111
{
1212
public int Value { get; set; }
1313

14-
public string Compile()
14+
public string Compile(CompilerContext context)
1515
{
1616
return Value.ToString();
1717
}

ExampleCodeGenApp/Model/LocalVariableDefinition.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77

88
namespace ExampleCodeGenApp.Model
99
{
10-
public class LocalVariableDefinition<T> : IVariableDefinition<T>
10+
public class LocalVariableDefinition<T> : ITypedVariableDefinition<T>
1111
{
1212
public string VariableName { get; private set; }
1313
public string Value { get; set; }
1414

1515
public string Compile(CompilerContext context)
1616
{
1717
VariableName = context.FindFreeVariableName();
18-
context.AddVariableToCurrentScope(VariableName);
18+
context.AddVariableToCurrentScope(this);
1919
return $"local {VariableName} = {Value}\n";
2020
}
2121
}

ExampleCodeGenApp/Model/StringLiteral.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class StringLiteral : ITypedExpression<string>
1111
{
1212
public string Value { get; set; }
1313

14-
public string Compile()
14+
public string Compile(CompilerContext ctx)
1515
{
1616
return $"\"{Value}\"";
1717
}

ExampleCodeGenApp/Model/VariableReference.cs

+7-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44
using System.Text;
55
using System.Threading.Tasks;
66
using ExampleCodeGenApp.Model.Compiler;
7+
using ExampleCodeGenApp.Model.Compiler.Error;
78

89
namespace ExampleCodeGenApp.Model
910
{
1011
public class VariableReference<T> : ITypedExpression<T>
1112
{
12-
public LocalVariableDefinition<T> LocalVariable { get; set; }
13+
public ITypedVariableDefinition<T> LocalVariable { get; set; }
1314

14-
public string Compile()
15+
public string Compile(CompilerContext context)
1516
{
17+
if (!context.IsInScope(LocalVariable))
18+
{
19+
throw new VariableOutOfScopeException(LocalVariable.VariableName);
20+
}
1621
return LocalVariable.VariableName;
1722
}
1823
}

ExampleCodeGenApp/ViewModels/CodePreviewViewModel.cs

+27-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Text;
66
using System.Threading.Tasks;
77
using ExampleCodeGenApp.Model.Compiler;
8+
using ExampleCodeGenApp.Model.Compiler.Error;
89
using ReactiveUI;
910

1011
namespace ExampleCodeGenApp.ViewModels
@@ -20,14 +21,39 @@ public IStatement Code
2021
private IStatement _code;
2122
#endregion
2223

24+
#region CompilerError
25+
public string CompilerError
26+
{
27+
get => _compilerError;
28+
set => this.RaiseAndSetIfChanged(ref _compilerError, value);
29+
}
30+
private string _compilerError;
31+
#endregion
32+
2333
#region CompiledCode
2434
private readonly ObservableAsPropertyHelper<string> _compiledCode;
2535
public string CompiledCode => _compiledCode.Value;
2636
#endregion
2737

2838
public CodePreviewViewModel()
2939
{
30-
this.WhenAnyValue(vm => vm.Code).Where(c => c != null).Select(c => c.Compile(new CompilerContext()))
40+
this.WhenAnyValue(vm => vm.Code).Where(c => c != null)
41+
.Select(c =>
42+
{
43+
CompilerError = "";
44+
CompilerContext ctx = new CompilerContext();
45+
46+
try
47+
{
48+
return c.Compile(ctx);
49+
}
50+
catch (CompilerException e)
51+
{
52+
string trace = string.Join("\n", ctx.VariablesScopesStack.Select(s => s.Identifier));
53+
CompilerError = e.Message + "\nProblem is near:\n"+ trace;
54+
return "";
55+
}
56+
})
3157
.ToProperty(this, vm => vm.CompiledCode, out _compiledCode);
3258
}
3359
}

ExampleCodeGenApp/ViewModels/Nodes/ForLoopNode.cs

+15-12
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ static ForLoopNode()
3030
public ValueNodeInputViewModel<ITypedExpression<int>> FirstIndex { get; }
3131
public ValueNodeInputViewModel<ITypedExpression<int>> LastIndex { get; }
3232

33-
public ValueNodeOutputViewModel<VariableReference<int>> CurrentIndex { get; }
33+
public ValueNodeOutputViewModel<ITypedExpression<int>> CurrentIndex { get; }
3434

3535
public ForLoopNode() : base(NodeType.FlowControl)
3636
{
@@ -60,11 +60,7 @@ public ForLoopNode() : base(NodeType.FlowControl)
6060
};
6161
this.Inputs.Add(LastIndex);
6262

63-
CurrentIndex = new CodeGenOutputViewModel<VariableReference<int>>(PortType.Integer)
64-
{
65-
Name = "Current Index"
66-
};
67-
this.Outputs.Add(CurrentIndex);
63+
ForLoop value = new ForLoop();
6864

6965
var loopBodyChanged = LoopBodyFlow.Values.Connect().Select(_ => Unit.Default).StartWith(Unit.Default);
7066
var loopEndChanged = LoopEndFlow.Values.Connect().Select(_ => Unit.Default).StartWith(Unit.Default);
@@ -73,15 +69,22 @@ public ForLoopNode() : base(NodeType.FlowControl)
7369
Name = "",
7470
Value = Observable.CombineLatest(loopBodyChanged, loopEndChanged, FirstIndex.ValueChanged, LastIndex.ValueChanged,
7571
(bodyChange, endChange, firstI, lastI) => (BodyChange: bodyChange, EndChange: endChange, FirstI: firstI, LastI: lastI))
76-
.Select(v => new ForLoop
77-
{
78-
LoopBody = new StatementSequence(LoopBodyFlow.Values.Items),
79-
LoopEnd = new StatementSequence(LoopEndFlow.Values.Items),
80-
LowerBound = v.FirstI ?? new IntLiteral{ Value = 0 },
81-
UpperBound = v.LastI ?? new IntLiteral { Value = 1 }
72+
.Select(v => {
73+
value.LoopBody = new StatementSequence(LoopBodyFlow.Values.Items);
74+
value.LoopEnd = new StatementSequence(LoopEndFlow.Values.Items);
75+
value.LowerBound = v.FirstI ?? new IntLiteral {Value = 0};
76+
value.UpperBound = v.LastI ?? new IntLiteral {Value = 1};
77+
return value;
8278
})
8379
};
8480
this.Outputs.Add(FlowIn);
81+
82+
CurrentIndex = new CodeGenOutputViewModel<ITypedExpression<int>>(PortType.Integer)
83+
{
84+
Name = "Current Index",
85+
Value = Observable.Return(new VariableReference<int>{ LocalVariable = value.CurrentIndex })
86+
};
87+
this.Outputs.Add(CurrentIndex);
8588
}
8689
}
8790
}

ExampleCodeGenApp/Views/CodePreviewView.xaml

+8-3
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@
88
d:DesignHeight="300" d:DesignWidth="300">
99
<Grid Background="#f1f1f1">
1010
<Grid.RowDefinitions>
11-
<RowDefinition Height="40"/>
11+
<RowDefinition Height="Auto"/>
12+
<RowDefinition Height="Auto"/>
1213
<RowDefinition Height="*"/>
1314
</Grid.RowDefinitions>
14-
<Label Content="Code" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontSize="18" FontFamily="Segoe UI Semilight" Grid.RowSpan="2"/>
15+
<Label Content="Code" HorizontalAlignment="Left" Margin="10,10,0,10" VerticalAlignment="Top" FontSize="18" FontFamily="Segoe UI Semilight"/>
1516

16-
<Grid Grid.Row="1" Margin="10,10,10,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
17+
<Grid Grid.Row="1" Margin="10,0,10,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
18+
<TextBlock x:Name="errorTextBlock" Foreground="Red" HorizontalAlignment="Left" VerticalAlignment="Top" TextWrapping="Wrap"/>
19+
</Grid>
20+
21+
<Grid Grid.Row="2" Margin="10,0,10,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
1722
<TextBlock x:Name="codeTextBlock" HorizontalAlignment="Left" VerticalAlignment="Top"/>
1823
</Grid>
1924
</Grid>

ExampleCodeGenApp/Views/CodePreviewView.xaml.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Reactive.Disposables;
45
using System.Text;
56
using System.Threading.Tasks;
67
using System.Windows;
@@ -40,9 +41,10 @@ public CodePreviewView()
4041
{
4142
InitializeComponent();
4243

43-
this.WhenActivated(d => d(
44-
this.OneWayBind(ViewModel, vm => vm.CompiledCode, v => v.codeTextBlock.Text)
45-
));
44+
this.WhenActivated(d => {
45+
this.OneWayBind(ViewModel, vm => vm.CompiledCode, v => v.codeTextBlock.Text).DisposeWith(d);
46+
this.OneWayBind(ViewModel, vm => vm.CompilerError, v => v.errorTextBlock.Text).DisposeWith(d);
47+
});
4648
}
4749
}
4850
}

0 commit comments

Comments
 (0)