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:
John 2025-03-11 00:36:42 -05:00
parent c0ad544486
commit 7e311cb0ef
14 changed files with 213 additions and 163 deletions

View File

@ -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`])+ `)`

View File

@ -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)?,
})
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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),
}
}

View File

@ -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,
}

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)?))),

View File

@ -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}"),
}
}
}

View File

@ -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))
}
}

View File

@ -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()),
}
}

View File

@ -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>> {

View File

@ -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}")
}
}