Include correct tokens in pattern mismatch errors
This commit is contained in:
parent
7d006d8889
commit
93215cd294
6
AST.cs
6
AST.cs
@ -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()
|
||||||
{
|
{
|
||||||
|
@ -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.");
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user