-
Notifications
You must be signed in to change notification settings - Fork 89
/
GoTo.n
106 lines (94 loc) · 2.99 KB
/
GoTo.n
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
using Nemerle;
using Nemerle.Collections;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using Nemerle.Compiler.Typedtree;
using Nemerle.Utility;
namespace Nemerle.Imperative.GoTo
{
macro GoToMacro(@label : PExpr)
syntax ("goto", @label)
{
Implementation.DoTransformGoTo(Macros.ImplicitCTX(), @label)
}
macro LabelMacro(@label : PExpr)
syntax ("label", @label)
{
Implementation.DoTransformLabel(Macros.ImplicitCTX(), @label)
}
module Implementation
{
private GetLabelMap(typer : Typer) : Hashtable[Name, PExprLabel]
{
mutable labelMap = typer.CurrentMethodBuilder.UserData[typeof(PExprLabel)] :> Hashtable[Name, PExprLabel];
when (labelMap == null)
{
labelMap = Hashtable.[Name, PExprLabel]();
typer.CurrentMethodBuilder.UserData[typeof(PExprLabel)] = labelMap;
}
labelMap
}
private GetLabel(typer : Typer, name : Name) : PExprLabel
{
def labelMap = GetLabelMap(typer);
mutable @label;
unless (labelMap.TryGetValue(name, out @label))
{
@label = PExprLabel(typer.Manager, name);
labelMap[name] = @label;
}
@label
}
public DoTransformGoTo(typer : Typer, @label : PExpr) : PExpr
{
Macros.DefineCTX(typer);
match (@label)
{
| <[ $(name : name) ]> => GetLabel(typer, name).Goto()
| _ => Message.Error(@label.Location, "Expected simple name."); <[ () ]>
}
}
public DoTransformLabel(typer : Typer, @label : PExpr) : PExpr
{
Macros.DefineCTX(typer);
match (@label)
{
| <[ $(name : name) ]> =>
GetLabel(typer, name).Label(@label.Location)
| _ => Message.Error(@label.Location, "Expected simple name."); <[ () ]>
}
}
}
public sealed class PExprLabel
{
private static mutable _nextId : int;
private _manager : ManagerClass;
private _name : Name;
private _id : int;
private mutable _isLabelDefined : bool;
public this(manager : ManagerClass, name : Name)
{
_manager = manager;
_name = name;
_nextId++;
_id = _nextId;
}
public Goto() : PExpr
{
PExpr.Typed(Location.Default, TExpr.Goto(_manager.InternalType.Void, _id, 1))
}
public Label(loc : Location) : PExpr
{
if (_isLabelDefined)
{
def message = $"Label '$_name' ($_id) multiply defined";
Message.Error(message);
<[ () ]>
}
else
try PExpr.Typed(Location.Default, TExpr.Label(_manager.InternalType.Void, _id, TExpr.DefaultValue(loc, _manager.InternalType.Void)))
//try PExpr.Typed(loc, TExpr.Label(loc, _manager.InternalType.Void, _id, TExpr.Literal(loc, _manager.InternalType.Void, Literal.Void())))
finally _isLabelDefined = true;
}
}
}