-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUndefinedVariableChecker.cs
More file actions
71 lines (67 loc) · 3.32 KB
/
Copy pathUndefinedVariableChecker.cs
File metadata and controls
71 lines (67 loc) · 3.32 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
namespace YuchikiML {
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System;
class VariableUndefinedException : Exception {
public readonly String Variable;
public readonly ImmutableList<Expr> PartialExpressions;
public VariableUndefinedException() {}
public VariableUndefinedException(string message) : base(message) {}
public VariableUndefinedException(string message, Exception inner) : base(message, inner) {}
public VariableUndefinedException(string variable, ImmutableList<Expr> partialExpressions) =>
(Variable, PartialExpressions) = (variable, partialExpressions);
public VariableUndefinedException(Var variable) : this(variable.Name, ImmutableList<Expr>.Empty) {}
public VariableUndefinedException(Expr currentExpression, VariableUndefinedException ex) : this(ex.Variable, currentExpression.Size() > 50 ? ex.PartialExpressions : ex.PartialExpressions.Add(currentExpression)) {}
}
public static class UndefinedVariableChecker {
public static void Check(Expr e) => Check(e, ImmutableHashSet<string>.Empty);
public static void Check(Expr e, ImmutableHashSet<string> occurrence) {
try {
switch (e) {
case Literal lit:
return;
case Var variable:
if (occurrence.Contains(variable.Name) || BuiltInFunctions.BuiltIns.ContainsKey(variable.Name)) return;
throw new VariableUndefinedException(variable.Name, ImmutableList<Expr>.Empty);
case BinOperator binOp:
Check(binOp.Left, occurrence);
Check(binOp.Right, occurrence);
return;
case Not n:
Check(n.Body, occurrence);
return;
case If ifExpr:
Check(ifExpr.Condition, occurrence);
Check(ifExpr.Left, occurrence);
Check(ifExpr.Right, occurrence);
return;
case Bind bind:
{
Check(bind.VarBody, occurrence);
var newOccurrence = occurrence.Add(bind.Variable);
Check(bind.ExprBody, newOccurrence);
return;
}
case LetRec letRec:
{
var newOccurrence = occurrence.Add(letRec.Function);
Check(letRec.VarBody, newOccurrence.Add(letRec.Argument));
Check(letRec.ExprBody, newOccurrence);
return;
}
case Abs abs:
{
var newOccurrence = occurrence.Add(abs.Variable);
Check(abs.Body, newOccurrence);
}
return;
default:
throw new ArgumentOutOfRangeException();
}
} catch (VariableUndefinedException ex) {
throw new VariableUndefinedException(e, ex);
}
}
}
}