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:
parent
c0ad544486
commit
7e311cb0ef
@ -396,7 +396,7 @@ pub enum ExprKind {
|
||||
/// A backtick-quoted subexpression-literal
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Quote {
|
||||
pub quote: Box<ExprKind>,
|
||||
pub quote: Box<Expr>,
|
||||
}
|
||||
|
||||
/// A local variable declaration [Stmt]
|
||||
@ -435,14 +435,14 @@ pub struct MatchArm(pub Pattern, pub Expr);
|
||||
/// An [Assign]ment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Assign {
|
||||
pub parts: Box<(ExprKind, ExprKind)>,
|
||||
pub parts: Box<(Expr, Expr)>,
|
||||
}
|
||||
|
||||
/// A [Modify]-assignment expression: [`Expr`] ([`ModifyKind`] [`Expr`])\+
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Modify {
|
||||
pub kind: ModifyKind,
|
||||
pub parts: Box<(ExprKind, ExprKind)>,
|
||||
pub parts: Box<(Expr, Expr)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
@ -463,7 +463,7 @@ pub enum ModifyKind {
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Binary {
|
||||
pub kind: BinaryKind,
|
||||
pub parts: Box<(ExprKind, ExprKind)>,
|
||||
pub parts: Box<(Expr, Expr)>,
|
||||
}
|
||||
|
||||
/// A [Binary] operator
|
||||
@ -497,7 +497,7 @@ pub enum BinaryKind {
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Unary {
|
||||
pub kind: UnaryKind,
|
||||
pub tail: Box<ExprKind>,
|
||||
pub tail: Box<Expr>,
|
||||
}
|
||||
|
||||
/// A [Unary] operator
|
||||
@ -519,14 +519,14 @@ pub enum UnaryKind {
|
||||
/// A cast expression: [`Expr`] `as` [`Ty`]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Cast {
|
||||
pub head: Box<ExprKind>,
|
||||
pub head: Box<Expr>,
|
||||
pub ty: Ty,
|
||||
}
|
||||
|
||||
/// A [Member] access expression: [`Expr`] [`MemberKind`]\*
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Member {
|
||||
pub head: Box<ExprKind>,
|
||||
pub head: Box<Expr>,
|
||||
pub kind: MemberKind,
|
||||
}
|
||||
|
||||
@ -541,7 +541,7 @@ pub enum MemberKind {
|
||||
/// A repeated [Index] expression: a[10, 20, 30][40, 50, 60]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Index {
|
||||
pub head: Box<ExprKind>,
|
||||
pub head: Box<Expr>,
|
||||
pub indices: Vec<Expr>,
|
||||
}
|
||||
|
||||
@ -569,15 +569,15 @@ pub struct Array {
|
||||
/// `[` [Expr] `;` [Literal] `]`
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct ArrayRep {
|
||||
pub value: Box<ExprKind>,
|
||||
pub repeat: Box<ExprKind>,
|
||||
pub value: Box<Expr>,
|
||||
pub repeat: Box<Expr>,
|
||||
}
|
||||
|
||||
/// An address-of expression: `&` `mut`? [`Expr`]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct AddrOf {
|
||||
pub mutable: Mutability,
|
||||
pub expr: Box<ExprKind>,
|
||||
pub expr: Box<Expr>,
|
||||
}
|
||||
|
||||
/// A [Block] expression: `{` [`Stmt`]\* [`Expr`]? `}`
|
||||
@ -589,7 +589,7 @@ pub struct Block {
|
||||
/// A [Grouping](Group) expression `(` [`Expr`] `)`
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Group {
|
||||
pub expr: Box<ExprKind>,
|
||||
pub expr: Box<Expr>,
|
||||
}
|
||||
|
||||
/// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)`
|
||||
|
@ -857,12 +857,12 @@ mod convert {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ExprKind> for Pattern {
|
||||
type Error = ExprKind;
|
||||
impl TryFrom<Expr> for Pattern {
|
||||
type Error = Expr;
|
||||
|
||||
/// Performs the conversion. On failure, returns the *first* non-pattern subexpression.
|
||||
fn try_from(value: ExprKind) -> Result<Self, Self::Error> {
|
||||
Ok(match value {
|
||||
fn try_from(value: Expr) -> Result<Self, Self::Error> {
|
||||
Ok(match value.kind {
|
||||
ExprKind::Literal(literal) => Pattern::Literal(literal),
|
||||
ExprKind::Path(Path { absolute: false, ref parts }) => match parts.as_slice() {
|
||||
[PathPart::Ident(name)] => Pattern::Name(*name),
|
||||
@ -873,7 +873,7 @@ mod convert {
|
||||
ExprKind::Tuple(Tuple { exprs }) => Pattern::Tuple(
|
||||
exprs
|
||||
.into_iter()
|
||||
.map(|e| Pattern::try_from(e.kind))
|
||||
.map(Pattern::try_from)
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
ExprKind::AddrOf(AddrOf { mutable, expr }) => {
|
||||
@ -882,14 +882,14 @@ mod convert {
|
||||
ExprKind::Array(Array { values }) => Pattern::Array(
|
||||
values
|
||||
.into_iter()
|
||||
.map(|e| Pattern::try_from(e.kind))
|
||||
.map(Pattern::try_from)
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
ExprKind::Binary(Binary { kind: BinaryKind::Call, parts }) => {
|
||||
let (ExprKind::Path(path), args) = *parts else {
|
||||
let (Expr { kind: ExprKind::Path(path), .. }, args) = *parts else {
|
||||
return Err(parts.0);
|
||||
};
|
||||
match args {
|
||||
match args.kind {
|
||||
ExprKind::Empty | ExprKind::Tuple(_) => {}
|
||||
_ => return Err(args),
|
||||
}
|
||||
@ -905,12 +905,12 @@ mod convert {
|
||||
let fields = init
|
||||
.into_iter()
|
||||
.map(|Fielder { name, init }| {
|
||||
Ok((name, init.map(|i| Pattern::try_from(i.kind)).transpose()?))
|
||||
Ok((name, init.map(|i| Pattern::try_from(*i)).transpose()?))
|
||||
})
|
||||
.collect::<Result<_, Self::Error>>()?;
|
||||
Pattern::Struct(to, fields)
|
||||
}
|
||||
err => Err(err)?,
|
||||
_ => Err(value)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -294,14 +294,14 @@ pub trait Fold {
|
||||
fn fold_assign(&mut self, a: Assign) -> Assign {
|
||||
let Assign { parts } = a;
|
||||
let (head, tail) = *parts;
|
||||
Assign { parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))) }
|
||||
Assign { parts: Box::new((self.fold_expr(head), self.fold_expr(tail))) }
|
||||
}
|
||||
fn fold_modify(&mut self, m: Modify) -> Modify {
|
||||
let Modify { kind, parts } = m;
|
||||
let (head, tail) = *parts;
|
||||
Modify {
|
||||
kind: self.fold_modify_kind(kind),
|
||||
parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))),
|
||||
parts: Box::new((self.fold_expr(head), self.fold_expr(tail))),
|
||||
}
|
||||
}
|
||||
fn fold_modify_kind(&mut self, kind: ModifyKind) -> ModifyKind {
|
||||
@ -312,7 +312,7 @@ pub trait Fold {
|
||||
let (head, tail) = *parts;
|
||||
Binary {
|
||||
kind: self.fold_binary_kind(kind),
|
||||
parts: Box::new((self.fold_expr_kind(head), self.fold_expr_kind(tail))),
|
||||
parts: Box::new((self.fold_expr(head), self.fold_expr(tail))),
|
||||
}
|
||||
}
|
||||
fn fold_binary_kind(&mut self, kind: BinaryKind) -> BinaryKind {
|
||||
@ -320,18 +320,18 @@ pub trait Fold {
|
||||
}
|
||||
fn fold_unary(&mut self, u: Unary) -> Unary {
|
||||
let Unary { kind, tail } = u;
|
||||
Unary { kind: self.fold_unary_kind(kind), tail: Box::new(self.fold_expr_kind(*tail)) }
|
||||
Unary { kind: self.fold_unary_kind(kind), tail: Box::new(self.fold_expr(*tail)) }
|
||||
}
|
||||
fn fold_unary_kind(&mut self, kind: UnaryKind) -> UnaryKind {
|
||||
kind
|
||||
}
|
||||
fn fold_cast(&mut self, cast: Cast) -> Cast {
|
||||
let Cast { head, ty } = cast;
|
||||
Cast { head: Box::new(self.fold_expr_kind(*head)), ty: self.fold_ty(ty) }
|
||||
Cast { head: Box::new(self.fold_expr(*head)), ty: self.fold_ty(ty) }
|
||||
}
|
||||
fn fold_member(&mut self, m: Member) -> Member {
|
||||
let Member { head, kind } = m;
|
||||
Member { head: Box::new(self.fold_expr_kind(*head)), kind: self.fold_member_kind(kind) }
|
||||
Member { head: Box::new(self.fold_expr(*head)), kind: self.fold_member_kind(kind) }
|
||||
}
|
||||
fn fold_member_kind(&mut self, kind: MemberKind) -> MemberKind {
|
||||
or_fold_member_kind(self, kind)
|
||||
@ -339,7 +339,7 @@ pub trait Fold {
|
||||
fn fold_index(&mut self, i: Index) -> Index {
|
||||
let Index { head, indices } = i;
|
||||
Index {
|
||||
head: Box::new(self.fold_expr_kind(*head)),
|
||||
head: Box::new(self.fold_expr(*head)),
|
||||
indices: indices.into_iter().map(|e| self.fold_expr(e)).collect(),
|
||||
}
|
||||
}
|
||||
@ -363,15 +363,15 @@ pub trait Fold {
|
||||
fn fold_array_rep(&mut self, a: ArrayRep) -> ArrayRep {
|
||||
let ArrayRep { value, repeat } = a;
|
||||
ArrayRep {
|
||||
value: Box::new(self.fold_expr_kind(*value)),
|
||||
repeat: Box::new(self.fold_expr_kind(*repeat)),
|
||||
value: Box::new(self.fold_expr(*value)),
|
||||
repeat: Box::new(self.fold_expr(*repeat)),
|
||||
}
|
||||
}
|
||||
fn fold_addrof(&mut self, a: AddrOf) -> AddrOf {
|
||||
let AddrOf { mutable, expr } = a;
|
||||
AddrOf {
|
||||
mutable: self.fold_mutability(mutable),
|
||||
expr: Box::new(self.fold_expr_kind(*expr)),
|
||||
expr: Box::new(self.fold_expr(*expr)),
|
||||
}
|
||||
}
|
||||
fn fold_block(&mut self, b: Block) -> Block {
|
||||
@ -380,7 +380,7 @@ pub trait Fold {
|
||||
}
|
||||
fn fold_group(&mut self, g: Group) -> Group {
|
||||
let Group { expr } = g;
|
||||
Group { expr: Box::new(self.fold_expr_kind(*expr)) }
|
||||
Group { expr: Box::new(self.fold_expr(*expr)) }
|
||||
}
|
||||
fn fold_tuple(&mut self, t: Tuple) -> Tuple {
|
||||
let Tuple { exprs } = t;
|
||||
|
@ -253,39 +253,39 @@ pub trait Visit<'a>: Sized {
|
||||
fn visit_assign(&mut self, a: &'a Assign) {
|
||||
let Assign { parts } = a;
|
||||
let (head, tail) = parts.as_ref();
|
||||
self.visit_expr_kind(head);
|
||||
self.visit_expr_kind(tail);
|
||||
self.visit_expr(head);
|
||||
self.visit_expr(tail);
|
||||
}
|
||||
fn visit_modify(&mut self, m: &'a Modify) {
|
||||
let Modify { kind, parts } = m;
|
||||
let (head, tail) = parts.as_ref();
|
||||
self.visit_modify_kind(kind);
|
||||
self.visit_expr_kind(head);
|
||||
self.visit_expr_kind(tail);
|
||||
self.visit_expr(head);
|
||||
self.visit_expr(tail);
|
||||
}
|
||||
fn visit_modify_kind(&mut self, _kind: &'a ModifyKind) {}
|
||||
fn visit_binary(&mut self, b: &'a Binary) {
|
||||
let Binary { kind, parts } = b;
|
||||
let (head, tail) = parts.as_ref();
|
||||
self.visit_binary_kind(kind);
|
||||
self.visit_expr_kind(head);
|
||||
self.visit_expr_kind(tail);
|
||||
self.visit_expr(head);
|
||||
self.visit_expr(tail);
|
||||
}
|
||||
fn visit_binary_kind(&mut self, _kind: &'a BinaryKind) {}
|
||||
fn visit_unary(&mut self, u: &'a Unary) {
|
||||
let Unary { kind, tail } = u;
|
||||
self.visit_unary_kind(kind);
|
||||
self.visit_expr_kind(tail);
|
||||
self.visit_expr(tail);
|
||||
}
|
||||
fn visit_unary_kind(&mut self, _kind: &'a UnaryKind) {}
|
||||
fn visit_cast(&mut self, cast: &'a Cast) {
|
||||
let Cast { head, ty } = cast;
|
||||
self.visit_expr_kind(head);
|
||||
self.visit_expr(head);
|
||||
self.visit_ty(ty);
|
||||
}
|
||||
fn visit_member(&mut self, m: &'a Member) {
|
||||
let Member { head, kind } = m;
|
||||
self.visit_expr_kind(head);
|
||||
self.visit_expr(head);
|
||||
self.visit_member_kind(kind);
|
||||
}
|
||||
fn visit_member_kind(&mut self, kind: &'a MemberKind) {
|
||||
@ -293,7 +293,7 @@ pub trait Visit<'a>: Sized {
|
||||
}
|
||||
fn visit_index(&mut self, i: &'a Index) {
|
||||
let Index { head, indices } = i;
|
||||
self.visit_expr_kind(head);
|
||||
self.visit_expr(head);
|
||||
indices.iter().for_each(|e| self.visit_expr(e));
|
||||
}
|
||||
fn visit_structor(&mut self, s: &'a Structor) {
|
||||
@ -314,13 +314,13 @@ pub trait Visit<'a>: Sized {
|
||||
}
|
||||
fn visit_array_rep(&mut self, a: &'a ArrayRep) {
|
||||
let ArrayRep { value, repeat } = a;
|
||||
self.visit_expr_kind(value);
|
||||
self.visit_expr_kind(repeat);
|
||||
self.visit_expr(value);
|
||||
self.visit_expr(repeat);
|
||||
}
|
||||
fn visit_addrof(&mut self, a: &'a AddrOf) {
|
||||
let AddrOf { mutable, expr } = a;
|
||||
self.visit_mutability(mutable);
|
||||
self.visit_expr_kind(expr);
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
fn visit_block(&mut self, b: &'a Block) {
|
||||
let Block { stmts } = b;
|
||||
@ -328,7 +328,7 @@ pub trait Visit<'a>: Sized {
|
||||
}
|
||||
fn visit_group(&mut self, g: &'a Group) {
|
||||
let Group { expr } = g;
|
||||
self.visit_expr_kind(expr)
|
||||
self.visit_expr(expr)
|
||||
}
|
||||
fn visit_tuple(&mut self, t: &'a Tuple) {
|
||||
let Tuple { exprs } = t;
|
||||
|
@ -7,7 +7,7 @@ pub struct SquashGroups;
|
||||
impl Fold for SquashGroups {
|
||||
fn fold_expr_kind(&mut self, kind: ExprKind) -> ExprKind {
|
||||
match kind {
|
||||
ExprKind::Group(Group { expr }) => self.fold_expr_kind(*expr),
|
||||
ExprKind::Group(Group { expr }) => self.fold_expr(*expr).kind,
|
||||
_ => or_fold_expr_kind(self, kind),
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,10 @@ fn desugar_while(extents: Span, kind: ExprKind) -> ExprKind {
|
||||
|
||||
let loop_body = If { cond, pass, fail: Else { body: Some(Box::new(break_expr)) } };
|
||||
let loop_body = ExprKind::If(loop_body);
|
||||
ExprKind::Unary(Unary { kind: UnaryKind::Loop, tail: Box::new(loop_body) })
|
||||
ExprKind::Unary(Unary {
|
||||
kind: UnaryKind::Loop,
|
||||
tail: Box::new(Expr { extents, kind: loop_body }),
|
||||
})
|
||||
}
|
||||
_ => kind,
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)?))),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
|
||||
use cl_ast::ExprKind;
|
||||
use cl_ast::Expr;
|
||||
use cl_lexer::error::{Error as LexError, Reason};
|
||||
use std::fmt::Display;
|
||||
pub type PResult<T> = Result<T, Error>;
|
||||
@ -30,7 +30,7 @@ pub enum ErrorKind {
|
||||
ExpectedParsing {
|
||||
want: Parsing,
|
||||
},
|
||||
InvalidPattern(Box<ExprKind>),
|
||||
InvalidPattern(Box<Expr>),
|
||||
/// Indicates unfinished code
|
||||
Todo(&'static str),
|
||||
}
|
||||
@ -135,7 +135,7 @@ impl Display for Error {
|
||||
ErrorKind::Todo(_) => write!(f, "{loc} {reason} {while_parsing:?}"),
|
||||
// lexical errors print their own higher-resolution loc info
|
||||
ErrorKind::Lexical(e) => write!(f, "{e} (while parsing {while_parsing})"),
|
||||
_ => write!(f, "{loc} {reason} while parsing {while_parsing}"),
|
||||
_ => write!(f, "{loc}: {reason} while parsing {while_parsing}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -888,26 +888,15 @@ impl Parse<'_> for StmtKind {
|
||||
|
||||
impl Parse<'_> for Expr {
|
||||
/// Parses an [Expr]
|
||||
///
|
||||
/// See also: [ExprKind::parse]
|
||||
fn parse(p: &mut Parser) -> PResult<Expr> {
|
||||
let start = p.loc();
|
||||
Ok(Expr { kind: ExprKind::parse(p)?, extents: Span(start, p.loc()) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse<'_> for ExprKind {
|
||||
/// Parses an [ExprKind] at the lowest precedence level
|
||||
// Implementer's note: Do not call this from within [prec::exprkind]
|
||||
fn parse(p: &mut Parser<'_>) -> PResult<ExprKind> {
|
||||
prec::exprkind(p, 0)
|
||||
prec::expr(p, 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse<'_> for Quote {
|
||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||
let quote = delim(
|
||||
ExprKind::parse,
|
||||
Expr::parse,
|
||||
(TokenKind::Grave, TokenKind::Grave),
|
||||
Parsing::ExprKind,
|
||||
)(p)?
|
||||
@ -981,16 +970,20 @@ impl Parse<'_> for AddrOf {
|
||||
match p.peek_kind(P)? {
|
||||
TokenKind::Amp => {
|
||||
p.consume_peeked();
|
||||
Ok(AddrOf { mutable: Mutability::parse(p)?, expr: ExprKind::parse(p)?.into() })
|
||||
Ok(AddrOf { mutable: Mutability::parse(p)?, expr: Expr::parse(p)?.into() })
|
||||
}
|
||||
TokenKind::AmpAmp => {
|
||||
let start = p.loc();
|
||||
p.consume_peeked();
|
||||
Ok(AddrOf {
|
||||
mutable: Mutability::Not,
|
||||
expr: ExprKind::AddrOf(AddrOf {
|
||||
mutable: Mutability::parse(p)?,
|
||||
expr: ExprKind::parse(p)?.into(),
|
||||
})
|
||||
expr: Expr {
|
||||
kind: ExprKind::AddrOf(AddrOf {
|
||||
mutable: Mutability::parse(p)?,
|
||||
expr: Expr::parse(p)?.into(),
|
||||
}),
|
||||
extents: Span(start, p.loc()),
|
||||
}
|
||||
.into(),
|
||||
})
|
||||
}
|
||||
@ -1009,9 +1002,7 @@ impl Parse<'_> for Block {
|
||||
|
||||
/// Conditions (which precede curly-braced blocks) get special treatment
|
||||
fn condition(p: &mut Parser) -> PResult<Expr> {
|
||||
let start = p.loc();
|
||||
let kind = prec::exprkind(p, prec::Precedence::Condition.level())?;
|
||||
Ok(Expr { kind, extents: Span(start, p.loc()) })
|
||||
prec::expr(p, prec::Precedence::Condition.level())
|
||||
}
|
||||
|
||||
impl Parse<'_> for While {
|
||||
@ -1088,7 +1079,7 @@ impl Parse<'_> for Return {
|
||||
|
||||
impl Parse<'_> for Pattern {
|
||||
fn parse(p: &mut Parser<'_>) -> PResult<Self> {
|
||||
let value = prec::exprkind(p, prec::Precedence::Pattern.level())?;
|
||||
let value = prec::expr(p, prec::Precedence::Pattern.level())?;
|
||||
Pattern::try_from(value).map_err(|e| p.error(InvalidPattern(e.into()), Parsing::Pattern))
|
||||
}
|
||||
}
|
||||
|
@ -8,36 +8,40 @@
|
||||
use super::{Parse, *};
|
||||
|
||||
/// Parses an [ExprKind]
|
||||
pub fn exprkind(p: &mut Parser, power: u8) -> PResult<ExprKind> {
|
||||
pub fn expr(p: &mut Parser, power: u8) -> PResult<Expr> {
|
||||
let parsing = Parsing::ExprKind;
|
||||
|
||||
let start = p.loc();
|
||||
// Prefix expressions
|
||||
let mut head = match p.peek_kind(Parsing::Unary)? {
|
||||
literal_like!() => Literal::parse(p)?.into(),
|
||||
path_like!() => exprkind_pathlike(p)?,
|
||||
TokenKind::Amp | TokenKind::AmpAmp => AddrOf::parse(p)?.into(),
|
||||
TokenKind::Grave => Quote::parse(p)?.into(),
|
||||
TokenKind::LCurly => Block::parse(p)?.into(),
|
||||
TokenKind::LBrack => exprkind_arraylike(p)?,
|
||||
TokenKind::LParen => exprkind_tuplelike(p)?,
|
||||
TokenKind::Let => Let::parse(p)?.into(),
|
||||
TokenKind::Match => Match::parse(p)?.into(),
|
||||
TokenKind::While => ExprKind::While(While::parse(p)?),
|
||||
TokenKind::If => ExprKind::If(If::parse(p)?),
|
||||
TokenKind::For => ExprKind::For(For::parse(p)?),
|
||||
TokenKind::Break => ExprKind::Break(Break::parse(p)?),
|
||||
TokenKind::Return => ExprKind::Return(Return::parse(p)?),
|
||||
TokenKind::Continue => {
|
||||
p.consume_peeked();
|
||||
ExprKind::Continue
|
||||
}
|
||||
let mut head = Expr {
|
||||
kind: match p.peek_kind(Parsing::Unary)? {
|
||||
literal_like!() => Literal::parse(p)?.into(),
|
||||
path_like!() => exprkind_pathlike(p)?,
|
||||
TokenKind::Amp | TokenKind::AmpAmp => AddrOf::parse(p)?.into(),
|
||||
TokenKind::Grave => Quote::parse(p)?.into(),
|
||||
TokenKind::LCurly => Block::parse(p)?.into(),
|
||||
TokenKind::LBrack => exprkind_arraylike(p)?,
|
||||
TokenKind::LParen => exprkind_tuplelike(p)?,
|
||||
TokenKind::Let => Let::parse(p)?.into(),
|
||||
TokenKind::Match => Match::parse(p)?.into(),
|
||||
TokenKind::While => ExprKind::While(While::parse(p)?),
|
||||
TokenKind::If => ExprKind::If(If::parse(p)?),
|
||||
TokenKind::For => ExprKind::For(For::parse(p)?),
|
||||
TokenKind::Break => ExprKind::Break(Break::parse(p)?),
|
||||
TokenKind::Return => ExprKind::Return(Return::parse(p)?),
|
||||
TokenKind::Continue => {
|
||||
p.consume_peeked();
|
||||
ExprKind::Continue
|
||||
}
|
||||
|
||||
op => {
|
||||
let (kind, prec) = from_prefix(op).ok_or_else(|| p.error(Unexpected(op), parsing))?;
|
||||
let ((), after) = prec.prefix().expect("should have a precedence");
|
||||
p.consume_peeked();
|
||||
Unary { kind, tail: exprkind(p, after)?.into() }.into()
|
||||
}
|
||||
op => {
|
||||
let (kind, prec) =
|
||||
from_prefix(op).ok_or_else(|| p.error(Unexpected(op), parsing))?;
|
||||
let ((), after) = prec.prefix().expect("should have a precedence");
|
||||
p.consume_peeked();
|
||||
Unary { kind, tail: expr(p, after)?.into() }.into()
|
||||
}
|
||||
},
|
||||
extents: Span(start, p.loc()),
|
||||
};
|
||||
|
||||
fn from_postfix(op: TokenKind) -> Option<Precedence> {
|
||||
@ -58,36 +62,50 @@ pub fn exprkind(p: &mut Parser, power: u8) -> PResult<ExprKind> {
|
||||
break;
|
||||
}
|
||||
|
||||
head = match op {
|
||||
TokenKind::LBrack => {
|
||||
p.consume_peeked();
|
||||
let indices =
|
||||
sep(Expr::parse, TokenKind::Comma, TokenKind::RBrack, parsing)(p)?;
|
||||
p.match_type(TokenKind::RBrack, parsing)?;
|
||||
ExprKind::Index(Index { head: head.into(), indices })
|
||||
}
|
||||
TokenKind::LParen => {
|
||||
p.consume_peeked();
|
||||
let exprs = sep(Expr::parse, TokenKind::Comma, TokenKind::RParen, parsing)(p)?;
|
||||
p.match_type(TokenKind::RParen, parsing)?;
|
||||
Binary { kind: BinaryKind::Call, parts: (head, Tuple { exprs }.into()).into() }
|
||||
head = Expr {
|
||||
kind: match op {
|
||||
TokenKind::LBrack => {
|
||||
p.consume_peeked();
|
||||
let indices =
|
||||
sep(Expr::parse, TokenKind::Comma, TokenKind::RBrack, parsing)(p)?;
|
||||
p.match_type(TokenKind::RBrack, parsing)?;
|
||||
ExprKind::Index(Index { head: head.into(), indices })
|
||||
}
|
||||
TokenKind::LParen => {
|
||||
p.consume_peeked();
|
||||
let exprs =
|
||||
sep(Expr::parse, TokenKind::Comma, TokenKind::RParen, parsing)(p)?;
|
||||
p.match_type(TokenKind::RParen, parsing)?;
|
||||
Binary {
|
||||
kind: BinaryKind::Call,
|
||||
parts: (
|
||||
head,
|
||||
Expr {
|
||||
kind: Tuple { exprs }.into(),
|
||||
extents: Span(start, p.loc()),
|
||||
},
|
||||
)
|
||||
.into(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
TokenKind::LCurly => match head {
|
||||
ExprKind::Path(path) => ExprKind::Structor(structor_body(p, path)?),
|
||||
_ => break,
|
||||
}
|
||||
TokenKind::LCurly => match head.kind {
|
||||
ExprKind::Path(path) => ExprKind::Structor(structor_body(p, path)?),
|
||||
_ => break,
|
||||
},
|
||||
TokenKind::Dot => {
|
||||
p.consume_peeked();
|
||||
let kind = MemberKind::parse(p)?;
|
||||
Member { head: Box::new(head), kind }.into()
|
||||
}
|
||||
TokenKind::As => {
|
||||
p.consume_peeked();
|
||||
let ty = Ty::parse(p)?;
|
||||
Cast { head: head.into(), ty }.into()
|
||||
}
|
||||
_ => Err(p.error(Unexpected(op), parsing))?,
|
||||
},
|
||||
TokenKind::Dot => {
|
||||
p.consume_peeked();
|
||||
let kind = MemberKind::parse(p)?;
|
||||
Member { head: Box::new(head), kind }.into()
|
||||
}
|
||||
TokenKind::As => {
|
||||
p.consume_peeked();
|
||||
let ty = Ty::parse(p)?;
|
||||
Cast { head: head.into(), ty }.into()
|
||||
}
|
||||
_ => Err(p.error(Unexpected(op), parsing))?,
|
||||
extents: Span(start, p.loc()),
|
||||
};
|
||||
continue;
|
||||
}
|
||||
@ -99,8 +117,11 @@ pub fn exprkind(p: &mut Parser, power: u8) -> PResult<ExprKind> {
|
||||
}
|
||||
p.consume_peeked();
|
||||
|
||||
let tail = exprkind(p, after)?;
|
||||
head = Binary { kind, parts: (head, tail).into() }.into();
|
||||
let tail = expr(p, after)?;
|
||||
head = Expr {
|
||||
kind: Binary { kind, parts: (head, tail).into() }.into(),
|
||||
extents: Span(start, p.loc()),
|
||||
};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -111,8 +132,11 @@ pub fn exprkind(p: &mut Parser, power: u8) -> PResult<ExprKind> {
|
||||
}
|
||||
p.consume_peeked();
|
||||
|
||||
let tail = exprkind(p, after)?;
|
||||
head = Modify { kind, parts: (head, tail).into() }.into();
|
||||
let tail = expr(p, after)?;
|
||||
head = Expr {
|
||||
kind: Modify { kind, parts: (head, tail).into() }.into(),
|
||||
extents: Span(start, p.loc()),
|
||||
};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -125,8 +149,12 @@ pub fn exprkind(p: &mut Parser, power: u8) -> PResult<ExprKind> {
|
||||
}
|
||||
p.consume_peeked();
|
||||
|
||||
let tail = exprkind(p, after)?;
|
||||
head = Assign { parts: (head, tail).into() }.into();
|
||||
let tail = expr(p, after)?;
|
||||
head = Expr {
|
||||
kind: Assign { parts: (head, tail).into() }.into(),
|
||||
extents: Span(start, p.loc()),
|
||||
};
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -138,7 +166,9 @@ pub fn exprkind(p: &mut Parser, power: u8) -> PResult<ExprKind> {
|
||||
p.consume_peeked();
|
||||
|
||||
let ty = Ty::parse(p)?;
|
||||
head = Cast { head: head.into(), ty }.into();
|
||||
head =
|
||||
Expr { kind: Cast { head: head.into(), ty }.into(), extents: Span(start, p.loc()) };
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -174,10 +204,10 @@ fn exprkind_array_rep(p: &mut Parser) -> PResult<ExprKind> {
|
||||
let first = Expr::parse(p)?;
|
||||
Ok(match p.peek_kind(P)? {
|
||||
TokenKind::Semi => ArrayRep {
|
||||
value: first.kind.into(),
|
||||
value: first.into(),
|
||||
repeat: {
|
||||
p.consume_peeked();
|
||||
Box::new(exprkind(p, 0)?)
|
||||
Box::new(expr(p, 0)?)
|
||||
},
|
||||
}
|
||||
.into(),
|
||||
@ -224,7 +254,7 @@ fn exprkind_group(p: &mut Parser) -> PResult<ExprKind> {
|
||||
}
|
||||
Ok(Tuple { exprs }.into())
|
||||
}
|
||||
_ => Ok(Group { expr: first.kind.into() }.into()),
|
||||
_ => Ok(Group { expr: first.into() }.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,8 @@ pub fn run(args: Args) -> Result<(), Box<dyn Error>> {
|
||||
fn get_line() {
|
||||
match repline::Repline::new("", "", "").read() {
|
||||
Ok(line) => Ok(ConValue::String(line.into())),
|
||||
Err(repline::Error::CtrlD(line)) => Ok(ConValue::String(line.into())),
|
||||
Err(repline::Error::CtrlC(_)) => Err(cl_interpret::error::Error::Break(ConValue::Empty)),
|
||||
Err(e) => Ok(ConValue::String(e.to_string().into())),
|
||||
}
|
||||
}
|
||||
@ -87,7 +89,13 @@ fn load_file(env: &mut Environment, path: impl AsRef<Path>) -> Result<ConValue,
|
||||
code
|
||||
}
|
||||
};
|
||||
Ok(env.eval(&code)?)
|
||||
match env.eval(&code) {
|
||||
Ok(v) => Ok(v),
|
||||
Err(e) => {
|
||||
eprintln!("{e}");
|
||||
Ok(ConValue::Empty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lex_code(code: &str, path: Option<impl AsRef<Path>>) -> Result<(), Box<dyn Error>> {
|
||||
|
@ -42,6 +42,6 @@ impl Loc {
|
||||
impl std::fmt::Display for Loc {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Loc { line, col } = self;
|
||||
write!(f, "{line}:{col}:")
|
||||
write!(f, "{line}:{col}")
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user