conlang: RIP THE EXPRKIND BANDAGE OFF

cl-ast: No more bare ExprKind: every Expr has a Span
cl-interpret: Give errors a span
cl-repl: Print eval errors in load_file, instead of returning them. These changes are relevant.
This commit is contained in:
2025-03-11 00:36:42 -05:00
parent c0ad544486
commit 7e311cb0ef
14 changed files with 213 additions and 163 deletions

View File

@@ -1,7 +1,7 @@
//! Values in the dynamically typed AST interpreter.
//!
//! The most permanent fix is a temporary one.
use cl_ast::{format::FmtAdapter, ExprKind, Sym};
use cl_ast::{format::FmtAdapter, Expr, Sym};
use super::{
builtin::Builtin,
@@ -42,7 +42,7 @@ pub enum ConValue {
/// An entire namespace
Module(Box<HashMap<Sym, Option<ConValue>>>),
/// A quoted expression
Quote(Box<ExprKind>),
Quote(Box<Expr>),
/// A callable thing
Function(Rc<Function>),
/// A built-in function
@@ -152,9 +152,9 @@ from! {
char => ConValue::Char,
Sym => ConValue::String,
&str => ConValue::String,
Expr => ConValue::Quote,
String => ConValue::String,
Rc<str> => ConValue::String,
ExprKind => ConValue::Quote,
Function => ConValue::Function,
Vec<ConValue> => ConValue::Tuple,
&'static Builtin => ConValue::Builtin,
@@ -262,7 +262,7 @@ impl std::fmt::Display for ConValue {
ConValue::Bool(v) => v.fmt(f),
ConValue::Char(v) => v.fmt(f),
ConValue::String(v) => v.fmt(f),
ConValue::Ref(v) => write!(f, "&{v}"),
ConValue::Ref(v) => write!(f, "&{}", v.borrow()),
ConValue::Array(array) => {
'['.fmt(f)?;
for (idx, element) in array.iter().enumerate() {

View File

@@ -1,6 +1,7 @@
//! The [Error] type represents any error thrown by the [Environment](super::Environment)
use cl_ast::{Pattern, Sym};
use cl_structures::span::Span;
use super::convalue::ConValue;
@@ -46,6 +47,18 @@ pub enum Error {
MatchNonexhaustive,
/// Error produced by a Builtin
BuiltinDebug(String),
/// Error with associated line information
WithSpan(Box<Error>, Span),
}
impl Error {
/// Adds a [Span] to this [Error], if there isn't already a more specific one.
pub fn with_span(self, span: Span) -> Self {
match self {
Self::WithSpan(..) => self,
err => Self::WithSpan(Box::new(err), span),
}
}
}
impl std::error::Error for Error {}
@@ -92,6 +105,7 @@ impl std::fmt::Display for Error {
write!(f, "Fell through a non-exhaustive match expression!")
}
Error::BuiltinDebug(s) => write!(f, "DEBUG: {s}"),
Error::WithSpan(e, span) => write!(f, "{}..{}: {e}", span.head, span.tail),
}
}
}

View File

@@ -173,8 +173,7 @@ impl Interpret for Enum {
}
impl Interpret for Impl {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { target: ImplKind::Type(Ty { extents: _, kind: TyKind::Path(name) }), body } =
self
let Self { target: ImplKind::Type(Ty { extents, kind: TyKind::Path(name) }), body } = self
else {
eprintln!("TODO: impl X for Ty");
return Ok(ConValue::Empty);
@@ -185,7 +184,9 @@ impl Interpret for Impl {
let (frame, _) = env
.pop_frame()
.expect("Environment frames must be balanced");
match assignment::addrof_path(env, name.parts.as_slice())? {
match assignment::addrof_path(env, name.parts.as_slice())
.map_err(|err| err.with_span(*extents))?
{
Some(ConValue::Module(m)) => m.extend(frame),
Some(other) => eprintln!("TODO: impl for {other}"),
None => {}
@@ -262,12 +263,13 @@ impl Interpret for UseTree {
impl Interpret for Stmt {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { extents: _, kind, semi } = self;
let Self { extents, kind, semi } = self;
let out = match kind {
StmtKind::Empty => ConValue::Empty,
StmtKind::Item(stmt) => stmt.interpret(env)?,
StmtKind::Expr(stmt) => stmt.interpret(env)?,
};
StmtKind::Empty => Ok(ConValue::Empty),
StmtKind::Item(stmt) => stmt.interpret(env),
StmtKind::Expr(stmt) => stmt.interpret(env),
}
.map_err(|err| err.with_span(*extents))?;
Ok(match semi {
Semi::Terminated => ConValue::Empty,
Semi::Unterminated => out,
@@ -278,8 +280,8 @@ impl Interpret for Stmt {
impl Interpret for Expr {
#[inline]
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { extents: _, kind } = self;
kind.interpret(env)
let Self { extents, kind } = self;
kind.interpret(env).map_err(|err| err.with_span(*extents))
}
}
@@ -374,11 +376,11 @@ mod assignment {
Ok(())
}
pub(super) fn assign(env: &mut Environment, pat: &ExprKind, value: ConValue) -> IResult<()> {
pub(super) fn assign(env: &mut Environment, pat: &Expr, value: ConValue) -> IResult<()> {
if let Ok(pat) = Pattern::try_from(pat.clone()) {
return pat_assign(env, &pat, value);
}
match pat {
match &pat.kind {
ExprKind::Member(member) => *addrof_member(env, member)? = value,
ExprKind::Index(index) => *addrof_index(env, index)? = value,
ExprKind::Path(path) => *addrof_path(env, &path.parts)? = Some(value),
@@ -389,9 +391,9 @@ mod assignment {
pub(super) fn addrof<'e>(
env: &'e mut Environment,
pat: &ExprKind,
pat: &Expr,
) -> IResult<&'e mut ConValue> {
match pat {
match &pat.kind {
ExprKind::Path(path) => addrof_path(env, &path.parts)?
.as_mut()
.ok_or(Error::NotInitialized("".into())),
@@ -422,7 +424,7 @@ mod assignment {
member: &Member,
) -> IResult<&'e mut ConValue> {
let Member { head, kind } = member;
let ExprKind::Path(path) = head.as_ref() else {
let ExprKind::Path(path) = &head.kind else {
return Err(Error::TypeError);
};
let slot = addrof_path(env, &path.parts)?
@@ -641,7 +643,7 @@ fn cast(value: ConValue, ty: Sym) -> IResult<ConValue> {
ConValue::Int(i) => i as _,
ConValue::Bool(b) => b as _,
ConValue::Char(c) => c as _,
ConValue::Ref(v) => return cast((*v).clone(), ty),
ConValue::Ref(v) => return cast((*v).borrow().clone(), ty),
// TODO: This, better
ConValue::Float(_) if ty.starts_with('f') => return Ok(value),
ConValue::Float(f) => f as _,
@@ -684,7 +686,7 @@ impl Interpret for Cast {
impl Interpret for Member {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Member { head, kind } = self;
if let ExprKind::Path(_) = head.as_ref() {
if let ExprKind::Path(_) = &head.kind {
return assignment::addrof_member(env, self).cloned();
}
let head = head.interpret(env)?;
@@ -728,6 +730,8 @@ impl Interpret for Structor {
let Self { to: Path { absolute: _, parts }, init } = self;
use std::collections::HashMap;
// Look up struct/enum-struct definition
let name = match parts.last() {
Some(PathPart::Ident(name)) => *name,
Some(PathPart::SelfKw) => "self".into(),
@@ -793,7 +797,7 @@ impl Interpret for ArrayRep {
impl Interpret for AddrOf {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { mutable: _, expr } = self;
match expr.as_ref() {
match &expr.kind {
ExprKind::Index(_) => todo!("AddrOf array index"),
ExprKind::Path(_) => todo!("Path traversal in addrof"),
_ => Ok(ConValue::Ref(Rc::new(expr.interpret(env)?))),