conlang: Add unconditional loop expression, for desugaring
This commit is contained in:
parent
ec1a1255ad
commit
00d72b823a
@ -367,6 +367,7 @@ mod display {
|
||||
ExprKind::Empty => "()".fmt(f),
|
||||
ExprKind::Group(v) => v.fmt(f),
|
||||
ExprKind::Tuple(v) => v.fmt(f),
|
||||
ExprKind::Loop(v) => v.fmt(f),
|
||||
ExprKind::While(v) => v.fmt(f),
|
||||
ExprKind::If(v) => v.fmt(f),
|
||||
ExprKind::For(v) => v.fmt(f),
|
||||
@ -534,6 +535,12 @@ mod display {
|
||||
write!(f, "({})", self.expr)
|
||||
}
|
||||
}
|
||||
impl Display for Loop {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Self { body } = self;
|
||||
write!(f, "loop {body}")
|
||||
}
|
||||
}
|
||||
impl Display for While {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let Self { cond, pass, fail } = self;
|
||||
|
@ -346,6 +346,8 @@ pub enum ExprKind {
|
||||
Group(Group),
|
||||
/// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)`
|
||||
Tuple(Tuple),
|
||||
/// A [Loop] expression: `loop` [`Block`]
|
||||
Loop(Loop),
|
||||
/// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]?
|
||||
While(While),
|
||||
/// An [If] expression: `if` [`Expr`] [`Block`] [`Else`]?
|
||||
@ -492,6 +494,12 @@ pub struct Tuple {
|
||||
pub exprs: Vec<Expr>,
|
||||
}
|
||||
|
||||
/// A [Loop] expression: `loop` [`Block`]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Loop {
|
||||
pub body: Block,
|
||||
}
|
||||
|
||||
/// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]?
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct While {
|
||||
|
@ -131,6 +131,7 @@ impl Interpret for ExprKind {
|
||||
ExprKind::Empty => Ok(ConValue::Empty),
|
||||
ExprKind::Group(v) => v.interpret(env),
|
||||
ExprKind::Tuple(v) => v.interpret(env),
|
||||
ExprKind::Loop(v) => v.interpret(env),
|
||||
ExprKind::While(v) => v.interpret(env),
|
||||
ExprKind::If(v) => v.interpret(env),
|
||||
ExprKind::For(v) => v.interpret(env),
|
||||
@ -365,17 +366,32 @@ impl Interpret for Tuple {
|
||||
)?))
|
||||
}
|
||||
}
|
||||
impl Interpret for While {
|
||||
impl Interpret for Loop {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Self { cond, pass, fail } = self;
|
||||
while cond.interpret(env)?.truthy()? {
|
||||
match pass.interpret(env) {
|
||||
let Self { body } = self;
|
||||
loop {
|
||||
match body.interpret(env) {
|
||||
Err(Error::Break(value)) => return Ok(value),
|
||||
Err(Error::Continue) => continue,
|
||||
e => e?,
|
||||
};
|
||||
}
|
||||
fail.interpret(env)
|
||||
}
|
||||
}
|
||||
impl Interpret for While {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Self { cond, pass, fail } = self;
|
||||
loop {
|
||||
if cond.interpret(env)?.truthy()? {
|
||||
match pass.interpret(env) {
|
||||
Err(Error::Break(value)) => return Ok(value),
|
||||
Err(Error::Continue) => continue,
|
||||
e => e?,
|
||||
};
|
||||
} else {
|
||||
break fail.interpret(env);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Interpret for If {
|
||||
@ -392,23 +408,24 @@ impl Interpret for For {
|
||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||
let Self { bind: Identifier(name), cond, pass, fail } = self;
|
||||
// TODO: A better iterator model
|
||||
let bounds = match cond.interpret(env)? {
|
||||
let mut bounds = match cond.interpret(env)? {
|
||||
ConValue::RangeExc(a, b) => a..=b,
|
||||
ConValue::RangeInc(a, b) => a..=b,
|
||||
_ => Err(Error::TypeError)?,
|
||||
};
|
||||
{
|
||||
loop {
|
||||
let mut env = env.frame("loop variable");
|
||||
for loop_var in bounds {
|
||||
if let Some(loop_var) = bounds.next() {
|
||||
env.insert(name, Some(loop_var.into()));
|
||||
match pass.interpret(&mut env) {
|
||||
Err(Error::Break(value)) => return Ok(value),
|
||||
Err(Error::Continue) => continue,
|
||||
result => result?,
|
||||
};
|
||||
} else {
|
||||
break fail.interpret(&mut env);
|
||||
}
|
||||
}
|
||||
fail.interpret(env)
|
||||
}
|
||||
}
|
||||
impl Interpret for Else {
|
||||
|
@ -103,6 +103,7 @@ pub enum Parsing {
|
||||
Block,
|
||||
Group,
|
||||
Tuple,
|
||||
Loop,
|
||||
While,
|
||||
If,
|
||||
For,
|
||||
@ -204,6 +205,7 @@ impl Display for Parsing {
|
||||
Parsing::Block => "a block",
|
||||
Parsing::Group => "a grouped expression",
|
||||
Parsing::Tuple => "a tuple",
|
||||
Parsing::Loop => "an unconditional loop expression",
|
||||
Parsing::While => "a while expression",
|
||||
Parsing::If => "an if expression",
|
||||
Parsing::For => "a for expression",
|
||||
|
@ -809,6 +809,7 @@ impl<'t> Parser<'t> {
|
||||
self.consume_peeked();
|
||||
Unary { kind, tail: self.exprkind(after)?.into() }.into()
|
||||
}
|
||||
TokenKind::Loop => ExprKind::Loop(self.parse_loop()?),
|
||||
TokenKind::While => ExprKind::While(self.parse_while()?),
|
||||
TokenKind::If => ExprKind::If(self.parse_if()?),
|
||||
TokenKind::For => ExprKind::For(self.parse_for()?),
|
||||
@ -1010,6 +1011,12 @@ impl<'t> Parser<'t> {
|
||||
}
|
||||
/// ## Control flow subexpressions
|
||||
impl<'t> Parser<'t> {
|
||||
/// [Loop] = `loop` [Block]
|
||||
pub fn parse_loop(&mut self) -> PResult<Loop> {
|
||||
self.match_type(TokenKind::Loop, Parsing::Loop)?;
|
||||
Ok(Loop { body: self.block()? })
|
||||
}
|
||||
|
||||
/// [While] = `while` [Expr] [Block] [Else]?
|
||||
pub fn parse_while(&mut self) -> PResult<While> {
|
||||
self.match_type(TokenKind::While, Parsing::While)?;
|
||||
|
@ -383,6 +383,7 @@ pub mod yamlify {
|
||||
ExprKind::Empty => {}
|
||||
ExprKind::Group(k) => k.yaml(y),
|
||||
ExprKind::Tuple(k) => k.yaml(y),
|
||||
ExprKind::Loop(k) => k.yaml(y),
|
||||
ExprKind::While(k) => k.yaml(y),
|
||||
ExprKind::If(k) => k.yaml(y),
|
||||
ExprKind::For(k) => k.yaml(y),
|
||||
@ -472,6 +473,12 @@ pub mod yamlify {
|
||||
y.key("Group").yaml(expr);
|
||||
}
|
||||
}
|
||||
impl Yamlify for Loop {
|
||||
fn yaml(&self, y: &mut Yamler) {
|
||||
let Self { body } = self;
|
||||
y.key("Loop").yaml(body);
|
||||
}
|
||||
}
|
||||
impl Yamlify for While {
|
||||
fn yaml(&self, y: &mut Yamler) {
|
||||
let Self { cond, pass, fail } = self;
|
||||
|
@ -26,6 +26,7 @@ pub enum TokenKind {
|
||||
Impl,
|
||||
In,
|
||||
Let,
|
||||
Loop,
|
||||
Mod,
|
||||
Mut,
|
||||
Pub,
|
||||
@ -122,6 +123,7 @@ impl Display for TokenKind {
|
||||
TokenKind::Impl => "impl".fmt(f),
|
||||
TokenKind::In => "in".fmt(f),
|
||||
TokenKind::Let => "let".fmt(f),
|
||||
TokenKind::Loop => "loop".fmt(f),
|
||||
TokenKind::Mod => "mod".fmt(f),
|
||||
TokenKind::Mut => "mut".fmt(f),
|
||||
TokenKind::Pub => "pub".fmt(f),
|
||||
@ -158,6 +160,7 @@ impl FromStr for TokenKind {
|
||||
"impl" => Self::Impl,
|
||||
"in" => Self::In,
|
||||
"let" => Self::Let,
|
||||
"loop" => Self::Loop,
|
||||
"mod" => Self::Mod,
|
||||
"mut" => Self::Mut,
|
||||
"pub" => Self::Pub,
|
||||
|
@ -99,7 +99,7 @@ Index = Primary ('[' Indices ']')* ;
|
||||
Indices = (Expr ',')* Expr? ;
|
||||
|
||||
Primary = Literal | Path | Array | ArrayRep | AddrOf
|
||||
| Block | Group
|
||||
| Block | Group | Loop
|
||||
| If | While | For | Break | Return | Continue;
|
||||
|
||||
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
|
||||
@ -114,6 +114,7 @@ Block = '{' Stmt* '}';
|
||||
Group = Empty | '(' (Expr | Tuple) ')' ;
|
||||
Tuple = (Expr ',')* Expr? ;
|
||||
|
||||
Loop = "loop" Block ;
|
||||
While = "while" Expr Block Else ;
|
||||
If = "if" Expr Block Else ;
|
||||
For = "for" Identifier "in" Expr Block Else ;
|
||||
|
Loading…
Reference in New Issue
Block a user