conlang: Add unconditional loop expression, for desugaring

This commit is contained in:
John 2024-04-17 00:29:09 -05:00
parent ec1a1255ad
commit 00d72b823a
8 changed files with 62 additions and 10 deletions

View File

@ -367,6 +367,7 @@ mod display {
ExprKind::Empty => "()".fmt(f), ExprKind::Empty => "()".fmt(f),
ExprKind::Group(v) => v.fmt(f), ExprKind::Group(v) => v.fmt(f),
ExprKind::Tuple(v) => v.fmt(f), ExprKind::Tuple(v) => v.fmt(f),
ExprKind::Loop(v) => v.fmt(f),
ExprKind::While(v) => v.fmt(f), ExprKind::While(v) => v.fmt(f),
ExprKind::If(v) => v.fmt(f), ExprKind::If(v) => v.fmt(f),
ExprKind::For(v) => v.fmt(f), ExprKind::For(v) => v.fmt(f),
@ -534,6 +535,12 @@ mod display {
write!(f, "({})", self.expr) 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 { impl Display for While {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { cond, pass, fail } = self; let Self { cond, pass, fail } = self;

View File

@ -346,6 +346,8 @@ pub enum ExprKind {
Group(Group), Group(Group),
/// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)` /// A [Tuple] expression: `(` [`Expr`] (`,` [`Expr`])+ `)`
Tuple(Tuple), Tuple(Tuple),
/// A [Loop] expression: `loop` [`Block`]
Loop(Loop),
/// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]? /// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]?
While(While), While(While),
/// An [If] expression: `if` [`Expr`] [`Block`] [`Else`]? /// An [If] expression: `if` [`Expr`] [`Block`] [`Else`]?
@ -492,6 +494,12 @@ pub struct Tuple {
pub exprs: Vec<Expr>, 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`]? /// A [While] expression: `while` [`Expr`] [`Block`] [`Else`]?
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct While { pub struct While {

View File

@ -131,6 +131,7 @@ impl Interpret for ExprKind {
ExprKind::Empty => Ok(ConValue::Empty), ExprKind::Empty => Ok(ConValue::Empty),
ExprKind::Group(v) => v.interpret(env), ExprKind::Group(v) => v.interpret(env),
ExprKind::Tuple(v) => v.interpret(env), ExprKind::Tuple(v) => v.interpret(env),
ExprKind::Loop(v) => v.interpret(env),
ExprKind::While(v) => v.interpret(env), ExprKind::While(v) => v.interpret(env),
ExprKind::If(v) => v.interpret(env), ExprKind::If(v) => v.interpret(env),
ExprKind::For(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> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { cond, pass, fail } = self; let Self { body } = self;
while cond.interpret(env)?.truthy()? { loop {
match pass.interpret(env) { match body.interpret(env) {
Err(Error::Break(value)) => return Ok(value), Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue, Err(Error::Continue) => continue,
e => e?, 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 { impl Interpret for If {
@ -392,23 +408,24 @@ impl Interpret for For {
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> { fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
let Self { bind: Identifier(name), cond, pass, fail } = self; let Self { bind: Identifier(name), cond, pass, fail } = self;
// TODO: A better iterator model // 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::RangeExc(a, b) => a..=b,
ConValue::RangeInc(a, b) => a..=b, ConValue::RangeInc(a, b) => a..=b,
_ => Err(Error::TypeError)?, _ => Err(Error::TypeError)?,
}; };
{ loop {
let mut env = env.frame("loop variable"); 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())); env.insert(name, Some(loop_var.into()));
match pass.interpret(&mut env) { match pass.interpret(&mut env) {
Err(Error::Break(value)) => return Ok(value), Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue, Err(Error::Continue) => continue,
result => result?, result => result?,
}; };
} else {
break fail.interpret(&mut env);
} }
} }
fail.interpret(env)
} }
} }
impl Interpret for Else { impl Interpret for Else {

View File

@ -103,6 +103,7 @@ pub enum Parsing {
Block, Block,
Group, Group,
Tuple, Tuple,
Loop,
While, While,
If, If,
For, For,
@ -204,6 +205,7 @@ impl Display for Parsing {
Parsing::Block => "a block", Parsing::Block => "a block",
Parsing::Group => "a grouped expression", Parsing::Group => "a grouped expression",
Parsing::Tuple => "a tuple", Parsing::Tuple => "a tuple",
Parsing::Loop => "an unconditional loop expression",
Parsing::While => "a while expression", Parsing::While => "a while expression",
Parsing::If => "an if expression", Parsing::If => "an if expression",
Parsing::For => "a for expression", Parsing::For => "a for expression",

View File

@ -809,6 +809,7 @@ impl<'t> Parser<'t> {
self.consume_peeked(); self.consume_peeked();
Unary { kind, tail: self.exprkind(after)?.into() }.into() Unary { kind, tail: self.exprkind(after)?.into() }.into()
} }
TokenKind::Loop => ExprKind::Loop(self.parse_loop()?),
TokenKind::While => ExprKind::While(self.parse_while()?), TokenKind::While => ExprKind::While(self.parse_while()?),
TokenKind::If => ExprKind::If(self.parse_if()?), TokenKind::If => ExprKind::If(self.parse_if()?),
TokenKind::For => ExprKind::For(self.parse_for()?), TokenKind::For => ExprKind::For(self.parse_for()?),
@ -1010,6 +1011,12 @@ impl<'t> Parser<'t> {
} }
/// ## Control flow subexpressions /// ## Control flow subexpressions
impl<'t> Parser<'t> { 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]? /// [While] = `while` [Expr] [Block] [Else]?
pub fn parse_while(&mut self) -> PResult<While> { pub fn parse_while(&mut self) -> PResult<While> {
self.match_type(TokenKind::While, Parsing::While)?; self.match_type(TokenKind::While, Parsing::While)?;

View File

@ -383,6 +383,7 @@ pub mod yamlify {
ExprKind::Empty => {} ExprKind::Empty => {}
ExprKind::Group(k) => k.yaml(y), ExprKind::Group(k) => k.yaml(y),
ExprKind::Tuple(k) => k.yaml(y), ExprKind::Tuple(k) => k.yaml(y),
ExprKind::Loop(k) => k.yaml(y),
ExprKind::While(k) => k.yaml(y), ExprKind::While(k) => k.yaml(y),
ExprKind::If(k) => k.yaml(y), ExprKind::If(k) => k.yaml(y),
ExprKind::For(k) => k.yaml(y), ExprKind::For(k) => k.yaml(y),
@ -472,6 +473,12 @@ pub mod yamlify {
y.key("Group").yaml(expr); 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 { impl Yamlify for While {
fn yaml(&self, y: &mut Yamler) { fn yaml(&self, y: &mut Yamler) {
let Self { cond, pass, fail } = self; let Self { cond, pass, fail } = self;

View File

@ -26,6 +26,7 @@ pub enum TokenKind {
Impl, Impl,
In, In,
Let, Let,
Loop,
Mod, Mod,
Mut, Mut,
Pub, Pub,
@ -122,6 +123,7 @@ impl Display for TokenKind {
TokenKind::Impl => "impl".fmt(f), TokenKind::Impl => "impl".fmt(f),
TokenKind::In => "in".fmt(f), TokenKind::In => "in".fmt(f),
TokenKind::Let => "let".fmt(f), TokenKind::Let => "let".fmt(f),
TokenKind::Loop => "loop".fmt(f),
TokenKind::Mod => "mod".fmt(f), TokenKind::Mod => "mod".fmt(f),
TokenKind::Mut => "mut".fmt(f), TokenKind::Mut => "mut".fmt(f),
TokenKind::Pub => "pub".fmt(f), TokenKind::Pub => "pub".fmt(f),
@ -158,6 +160,7 @@ impl FromStr for TokenKind {
"impl" => Self::Impl, "impl" => Self::Impl,
"in" => Self::In, "in" => Self::In,
"let" => Self::Let, "let" => Self::Let,
"loop" => Self::Loop,
"mod" => Self::Mod, "mod" => Self::Mod,
"mut" => Self::Mut, "mut" => Self::Mut,
"pub" => Self::Pub, "pub" => Self::Pub,

View File

@ -99,7 +99,7 @@ Index = Primary ('[' Indices ']')* ;
Indices = (Expr ',')* Expr? ; Indices = (Expr ',')* Expr? ;
Primary = Literal | Path | Array | ArrayRep | AddrOf Primary = Literal | Path | Array | ArrayRep | AddrOf
| Block | Group | Block | Group | Loop
| If | While | For | Break | Return | Continue; | If | While | For | Break | Return | Continue;
Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ; Literal = STRING | CHARACTER | FLOAT | INTEGER | Bool ;
@ -114,6 +114,7 @@ Block = '{' Stmt* '}';
Group = Empty | '(' (Expr | Tuple) ')' ; Group = Empty | '(' (Expr | Tuple) ')' ;
Tuple = (Expr ',')* Expr? ; Tuple = (Expr ',')* Expr? ;
Loop = "loop" Block ;
While = "while" Expr Block Else ; While = "while" Expr Block Else ;
If = "if" Expr Block Else ; If = "if" Expr Block Else ;
For = "for" Identifier "in" Expr Block Else ; For = "for" Identifier "in" Expr Block Else ;