/
interpreter-m.n
113 lines (94 loc) · 2.66 KB
/
interpreter-m.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
107
108
109
110
111
112
113
// REFERENCE: Nemerle.Compiler
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
using Nemerle.Collections;
public class Robot
{
public mutable Orientation : byte;
public mutable X : int;
public mutable Y : int;
public IsDown : bool
{
get { Orientation == 1 }
}
public override ToString () : string
{
$"($X, $Y)"
}
}
public variant Expr {
| MoveBy { steps : int; }
| Left
| Right
| Value { prop : string; }
| If { cond : Expr.Value; then : Expr; els : Expr; }
}
public module Scripts
{
public Run (obj : Robot, expr : Expr) : void
{
def check_value (val) {
System.Convert.ToBoolean (obj.GetType ().GetProperty (val.prop).GetValue (obj, null))
}
match (expr) {
| Expr.MoveBy (steps) =>
match (obj.Orientation) {
| 0 => obj.X += steps
| 1 => obj.Y += steps
| 2 => obj.X -= steps
| _ => obj.Y -= steps
}
| Expr.Left => obj.Orientation = ((obj.Orientation + 3) % 4) :> byte;
| Expr.Right => obj.Orientation = ((obj.Orientation + 1) % 4) :> byte;
| Expr.Value as val => _ = check_value (val)
| Expr.If (val, e1, e2) =>
if (check_value (val))
Run (obj, e1)
else
Run (obj, e2)
}
}
public Run (obj : Robot, name : string) : void
{
def script = GetScript (name);
foreach (e in script) Run (obj, e)
}
public GetScript (name : string) : list [Expr]
{
| "myscript1" =>
[Expr.Right (), Expr.MoveBy (5),
Expr.If (Expr.Value ("IsDown"), Expr.MoveBy (3), Expr.Left ())]
| _ => throw System.ArgumentException ($"unknown script $name")
}
public GenerateRun (obj : PExpr, expr : Expr) : PExpr
{
def check_value (val) {
<[ $obj.$(val.prop : dyn) ]>
}
match (expr) {
| Expr.MoveBy (steps) =>
<[ match ($obj.Orientation) {
| 0 => $obj.X += $(steps : int)
| 1 => $obj.Y += $(steps : int)
| 2 => $obj.X -= $(steps : int)
| _ => $obj.Y -= $(steps : int)
}
]>
| Expr.Left => <[ $obj.Orientation = (($obj.Orientation + 3) % 4) :> byte ]>;
| Expr.Right => <[ $obj.Orientation = (($obj.Orientation + 1) % 4) :> byte ]>;
| Expr.Value as val => <[ _ = $(check_value (val)) ]>
| Expr.If (val, e1, e2) =>
<[ if ($(check_value (val)))
$(GenerateRun (obj, e1))
else
$(GenerateRun (obj, e2))
]>
}
}
}
macro GenerateRun (obj, name : string)
{
def script = Scripts.GetScript (name);
def exprs = NList.Map (script, fun (e) { Scripts.GenerateRun (obj, e) });
<[ { ..$exprs } ]>
}