Include correct tokens in pattern mismatch errors

This commit is contained in:
Brandon Dyck 2023-08-06 17:07:00 -06:00
parent 7d006d8889
commit 93215cd294
2 changed files with 25 additions and 22 deletions

6
AST.cs
View File

@ -42,9 +42,9 @@ public partial record SimplePattern
}
}
public abstract record Binding(Expr Value);
public record VarBinding(Pattern Pattern, Expr Value) : Binding(Value);
public record FuncBinding(Token Name, Pattern[] Params, Expr Value) : Binding(Value)
public abstract record Binding(Expr Value, Token Start);
public record VarBinding(Pattern Pattern, Expr Value) : Binding(Value, Pattern.Start);
public record FuncBinding(Token Name, Pattern[] Params, Expr Value) : Binding(Value, Name)
{
public override string ToString()
{

View File

@ -38,7 +38,6 @@ public class Env
var name = (string)identifier.Literal!;
if (values.ContainsKey(name))
{
// TODO use real location info
throw new RuntimeError(identifier, $"Cannot redefine variable {name} in same scope.");
}
values[name] = value;
@ -56,7 +55,6 @@ public class Env
{
return enclosing[identifier];
}
// TODO use real location info
throw new RuntimeError(identifier, $"Undefined variable {name}.");
}
}
@ -75,12 +73,19 @@ public class Interpreter : AST.IExprVisitor<Env, object>
}
}
private class PatternTagMismatchException : Exception
private class PatternMismatchException : Exception
{
public PatternTagMismatchException(string patternTag, string valueTag) : base($"Pattern tag {patternTag} does not match value tag {valueTag}.") { }
public readonly Token Start;
public PatternMismatchException(Token start, string message) : base(message)
{
Start = start;
}
}
private class PatternTypeMismatchException : Exception { }
private class VariantTagMismatchException : PatternMismatchException
{
public VariantTagMismatchException(Token start, string patternTag, string valueTag) : base(start, $"Pattern tag {patternTag} does not match value tag {valueTag}.") { }
}
class PatternBinder : AST.IPatternVisitor<(object, Env), ValueTuple>
{
@ -110,7 +115,7 @@ public class Interpreter : AST.IExprVisitor<Env, object>
}
return ValueTuple.Create();
}
throw new PatternTypeMismatchException();
throw new PatternMismatchException(pattern.Start, "Matched value {obj} is not a record.");
}
public ValueTuple visitSimplePatternPattern((object, Env) context, AST.SimplePattern pattern)
@ -133,7 +138,7 @@ public class Interpreter : AST.IExprVisitor<Env, object>
var tag = (string)pattern.Tag.Literal!;
if (v.Tag != tag)
{
throw new PatternTagMismatchException(tag, v.Tag);
throw new VariantTagMismatchException(pattern.Start, tag, v.Tag);
}
if (v.Value == null && pattern.Argument == null)
{
@ -143,10 +148,9 @@ public class Interpreter : AST.IExprVisitor<Env, object>
{
return pattern.Argument.accept((v.Value, env), this);
}
throw new PatternTypeMismatchException();
throw new PatternMismatchException(pattern.Start, "Variant pattern arity does not match variant value.");
}
// TODO throw a better exception
throw new Exception($"Not a variant.");
throw new PatternMismatchException(pattern.Start, $"Matched value {obj} is not a variant.");
}
}
@ -448,9 +452,10 @@ public class Interpreter : AST.IExprVisitor<Env, object>
}
catch (Exception e)
{
// TODO use real info
var tok = new Token(TokenType.Let, "let", null, new(0, 1, 1), new(0, 1, 1));
throw new RuntimeError(tok, e.Message);
var start = e is PatternMismatchException ?
((PatternMismatchException)e).Start :
binding.Start;
throw new RuntimeError(start, e.Message);
}
break;
default:
@ -593,8 +598,6 @@ public class Interpreter : AST.IExprVisitor<Env, object>
public object visitWhenExpr(Env env, AST.When expr)
{
var head = evaluate(env, expr.Head);
// TODO use real info
var tok = new Token(TokenType.When, "when", null, new(0, 1, 1), new(0, 1, 1));
foreach (var c in expr.Cases)
{
try
@ -603,15 +606,15 @@ public class Interpreter : AST.IExprVisitor<Env, object>
c.Pattern.accept((head, newEnv), new PatternBinder());
return evaluate(newEnv, c.Value);
}
catch (PatternTagMismatchException)
catch (VariantTagMismatchException)
{
continue;
}
catch (PatternTypeMismatchException e)
catch (PatternMismatchException e)
{
throw new RuntimeError(tok, e.Message);
throw new RuntimeError(e.Start, e.Message);
}
}
throw new RuntimeError(tok, "No matching patterns.");
throw new RuntimeError(expr.Start, "No matching patterns.");
}
}