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 abstract record Binding(Expr Value, Token Start);
public record VarBinding(Pattern Pattern, Expr Value) : Binding(Value); public record VarBinding(Pattern Pattern, Expr Value) : Binding(Value, Pattern.Start);
public record FuncBinding(Token Name, Pattern[] Params, Expr Value) : Binding(Value) public record FuncBinding(Token Name, Pattern[] Params, Expr Value) : Binding(Value, Name)
{ {
public override string ToString() public override string ToString()
{ {

View File

@ -38,7 +38,6 @@ public class Env
var name = (string)identifier.Literal!; var name = (string)identifier.Literal!;
if (values.ContainsKey(name)) if (values.ContainsKey(name))
{ {
// TODO use real location info
throw new RuntimeError(identifier, $"Cannot redefine variable {name} in same scope."); throw new RuntimeError(identifier, $"Cannot redefine variable {name} in same scope.");
} }
values[name] = value; values[name] = value;
@ -56,7 +55,6 @@ public class Env
{ {
return enclosing[identifier]; return enclosing[identifier];
} }
// TODO use real location info
throw new RuntimeError(identifier, $"Undefined variable {name}."); 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> class PatternBinder : AST.IPatternVisitor<(object, Env), ValueTuple>
{ {
@ -110,7 +115,7 @@ public class Interpreter : AST.IExprVisitor<Env, object>
} }
return ValueTuple.Create(); 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) 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!; var tag = (string)pattern.Tag.Literal!;
if (v.Tag != tag) 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) 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); 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 PatternMismatchException(pattern.Start, $"Matched value {obj} is not a variant.");
throw new Exception($"Not a variant.");
} }
} }
@ -448,9 +452,10 @@ public class Interpreter : AST.IExprVisitor<Env, object>
} }
catch (Exception e) catch (Exception e)
{ {
// TODO use real info var start = e is PatternMismatchException ?
var tok = new Token(TokenType.Let, "let", null, new(0, 1, 1), new(0, 1, 1)); ((PatternMismatchException)e).Start :
throw new RuntimeError(tok, e.Message); binding.Start;
throw new RuntimeError(start, e.Message);
} }
break; break;
default: default:
@ -593,8 +598,6 @@ public class Interpreter : AST.IExprVisitor<Env, object>
public object visitWhenExpr(Env env, AST.When expr) public object visitWhenExpr(Env env, AST.When expr)
{ {
var head = evaluate(env, expr.Head); 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) foreach (var c in expr.Cases)
{ {
try try
@ -603,15 +606,15 @@ public class Interpreter : AST.IExprVisitor<Env, object>
c.Pattern.accept((head, newEnv), new PatternBinder()); c.Pattern.accept((head, newEnv), new PatternBinder());
return evaluate(newEnv, c.Value); return evaluate(newEnv, c.Value);
} }
catch (PatternTagMismatchException) catch (VariantTagMismatchException)
{ {
continue; 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.");
} }
} }