Implemented pattern matching in let-exprs
This commit is contained in:
parent
ca97c93181
commit
c12a0cffc8
103
Interpreter.cs
103
Interpreter.cs
@ -75,6 +75,79 @@ public class Interpreter : AST.IExprVisitor<Env, object>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class PatternTagMismatchException : Exception
|
||||||
|
{
|
||||||
|
public PatternTagMismatchException(string patternTag, string valueTag) : base($"Pattern tag {patternTag} does not match value tag {valueTag}.") { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PatternTypeMismatchException : Exception { }
|
||||||
|
|
||||||
|
class PatternBinder : AST.IPatternVisitor<(object, Env), ValueTuple>
|
||||||
|
{
|
||||||
|
public ValueTuple visitFieldPatternPattern((object, Env) context, AST.FieldPattern pattern)
|
||||||
|
{
|
||||||
|
return (pattern.Pattern ?? new AST.SimplePattern(pattern.Name)).accept(context, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueTuple visitRecordPatternPattern((object, Env) context, AST.RecordPattern pattern)
|
||||||
|
{
|
||||||
|
var (obj, env) = context;
|
||||||
|
switch (obj)
|
||||||
|
{
|
||||||
|
case Record r:
|
||||||
|
var removedLabels = new List<string>();
|
||||||
|
foreach (var field in pattern.Fields)
|
||||||
|
{
|
||||||
|
removedLabels.Add(field.Name.Value);
|
||||||
|
var fieldValue = r.Get(field.Name.Value);
|
||||||
|
field.accept((fieldValue, env), this);
|
||||||
|
}
|
||||||
|
if (pattern.Rest != null)
|
||||||
|
{
|
||||||
|
var rest = r.Without(removedLabels);
|
||||||
|
pattern.Rest.accept((rest, env), this);
|
||||||
|
}
|
||||||
|
return ValueTuple.Create();
|
||||||
|
}
|
||||||
|
throw new PatternTypeMismatchException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueTuple visitSimplePatternPattern((object, Env) context, AST.SimplePattern pattern)
|
||||||
|
{
|
||||||
|
var (obj, env) = context;
|
||||||
|
if (pattern.Identifier == null)
|
||||||
|
{
|
||||||
|
return ValueTuple.Create();
|
||||||
|
}
|
||||||
|
env[pattern.Identifier] = obj;
|
||||||
|
return ValueTuple.Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueTuple visitVariantPatternPattern((object, Env) context, AST.VariantPattern pattern)
|
||||||
|
{
|
||||||
|
var (obj, env) = context;
|
||||||
|
switch (obj)
|
||||||
|
{
|
||||||
|
case Variant v:
|
||||||
|
if (v.Tag != pattern.Tag.Value)
|
||||||
|
{
|
||||||
|
throw new PatternTagMismatchException(pattern.Tag.Value, v.Tag);
|
||||||
|
}
|
||||||
|
if (v.Value == null && pattern.Argument == null)
|
||||||
|
{
|
||||||
|
return ValueTuple.Create();
|
||||||
|
}
|
||||||
|
if (v.Value != null && pattern.Argument != null)
|
||||||
|
{
|
||||||
|
return pattern.Argument.accept((v.Value, env), this);
|
||||||
|
}
|
||||||
|
throw new PatternTypeMismatchException();
|
||||||
|
}
|
||||||
|
// TODO throw a better exception
|
||||||
|
throw new Exception($"Not a variant.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class List
|
private class List
|
||||||
{
|
{
|
||||||
public required ImmutableList<object> Items { get; init; }
|
public required ImmutableList<object> Items { get; init; }
|
||||||
@ -138,6 +211,11 @@ public class Interpreter : AST.IExprVisitor<Env, object>
|
|||||||
return values.Peek();
|
return values.Peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Record Without(IEnumerable<string> labels)
|
||||||
|
{
|
||||||
|
return new Record { Fields = Fields.RemoveRange(labels) };
|
||||||
|
}
|
||||||
|
|
||||||
public Record Remove(string name)
|
public Record Remove(string name)
|
||||||
{
|
{
|
||||||
ImmutableStack<object>? values;
|
ImmutableStack<object>? values;
|
||||||
@ -364,17 +442,16 @@ public class Interpreter : AST.IExprVisitor<Env, object>
|
|||||||
switch (binding)
|
switch (binding)
|
||||||
{
|
{
|
||||||
case AST.VarBinding(var pattern, var valueExpr):
|
case AST.VarBinding(var pattern, var valueExpr):
|
||||||
switch (pattern)
|
var value = evaluate(env, valueExpr);
|
||||||
|
try
|
||||||
{
|
{
|
||||||
case AST.SimplePattern(var identifier):
|
pattern.accept((value, newEnv), new PatternBinder());
|
||||||
var value = evaluate(env, valueExpr);
|
}
|
||||||
if (identifier != null)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
newEnv[identifier] = value;
|
// TODO use real info
|
||||||
}
|
var tok = new Token(TokenType.Let, "let", null, 1);
|
||||||
break;
|
throw new RuntimeError(tok, e.Message);
|
||||||
default:
|
|
||||||
throw new NotImplementedException("TODO moar patternz");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -509,7 +586,11 @@ public class Interpreter : AST.IExprVisitor<Env, object>
|
|||||||
|
|
||||||
public object visitVariantExpr(Env env, AST.Variant expr)
|
public object visitVariantExpr(Env env, AST.Variant expr)
|
||||||
{
|
{
|
||||||
return new Variant(expr.Tag.Value, expr.Argument);
|
if (expr.Argument == null)
|
||||||
|
{
|
||||||
|
return new Variant(expr.Tag.Value, null);
|
||||||
|
}
|
||||||
|
return new Variant(expr.Tag.Value, evaluate(env, expr.Argument));
|
||||||
}
|
}
|
||||||
|
|
||||||
public object visitWhenExpr(Env env, AST.When expr)
|
public object visitWhenExpr(Env env, AST.When expr)
|
||||||
|
Loading…
Reference in New Issue
Block a user