2022-12-13 13:34:52 -05:00
|
|
|
// Lower NIR into AIR
|
|
|
|
//
|
2023-01-17 23:09:25 -05:00
|
|
|
// Copyright (C) 2014-2023 Ryan Specialty, LLC.
|
2022-12-13 13:34:52 -05:00
|
|
|
//
|
|
|
|
// This file is part of TAME.
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
//! Lower [NIR](super) into [AIR](crate::asg::air).
|
|
|
|
|
|
|
|
use std::{error::Error, fmt::Display};
|
|
|
|
|
2023-01-23 16:30:25 -05:00
|
|
|
use crate::{
|
|
|
|
asg::{air::Air, ExprOp},
|
|
|
|
diagnose::Diagnostic,
|
|
|
|
nir::NirEntity,
|
|
|
|
parse::prelude::*,
|
tamer: asg::air: AIR as a sum IR
This introduces a new macro `sum_ir!` to help with a long-standing problem
of not being able to easily narrow types in Rust without a whole lot of
boilerplate. This patch includes a bit of documentation, so see that for
more information.
This was not a welcome change---I jumped down this rabbit hole trying to
decompose `AirAggregate` so that I can share portions of parsing with the
current parser and a template parser. I can now proceed with that.
This is not the only implementation that I had tried. I previously inverted
the approach, as I've been doing manually for some time: manually create
types to hold the sets of variants, and then create a sum type to hold those
types. That works, but it resulted in a mess for systems that have to use
the IR, since now you have two enums to contend with. I didn't find that to
be appropriate, because we shouldn't complicate the external API for
implementation details.
The enum for IRs is supposed to be like a bytecode---a list of operations
that can be performed with the IR. They can be grouped if it makes sense
for a public API, but in my case, I only wanted subsets for the sake of
delegating responsibilities to smaller subsystems, while retaining the
context that `match` provides via its exhaustiveness checking but does not
expose as something concrete (which is deeply frustrating!).
Anyway, here we are; this'll be refined over time, hopefully, and
portions of it can be generalized for removing boilerplate from other IRs.
Another thing to note is that this syntax is really a compromise---I had to
move on, and I was spending too much time trying to get creative with
`macro_rules!`. It isn't the best, and it doesn't seem very Rust-like in
some places and is therefore not necessarily all that intuitive. This can
be refined further in the future. But the end result, all things
considered, isn't too bad.
DEV-13708
2023-03-02 15:15:28 -05:00
|
|
|
span::UNKNOWN_SPAN,
|
2023-01-23 16:30:25 -05:00
|
|
|
};
|
2022-12-13 13:34:52 -05:00
|
|
|
|
|
|
|
use super::Nir;
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq, Default)]
|
|
|
|
pub enum NirToAir {
|
|
|
|
#[default]
|
|
|
|
Ready,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for NirToAir {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
use NirToAir::*;
|
|
|
|
|
|
|
|
match self {
|
|
|
|
Ready => write!(f, "ready to lower NIR to AIR"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ParseState for NirToAir {
|
|
|
|
type Token = Nir;
|
|
|
|
type Object = Air;
|
|
|
|
type Error = NirToAirError;
|
|
|
|
|
|
|
|
fn parse_token(
|
|
|
|
self,
|
2023-01-23 16:30:25 -05:00
|
|
|
tok: Self::Token,
|
2022-12-13 13:34:52 -05:00
|
|
|
_: NoContext,
|
|
|
|
) -> TransitionResult<Self::Super> {
|
2023-01-23 16:30:25 -05:00
|
|
|
use NirToAir::*;
|
|
|
|
|
|
|
|
#[cfg(not(feature = "wip-nir-to-air"))]
|
|
|
|
{
|
|
|
|
let _ = tok; // prevent `unused_variables` warning
|
tamer: asg::air: AIR as a sum IR
This introduces a new macro `sum_ir!` to help with a long-standing problem
of not being able to easily narrow types in Rust without a whole lot of
boilerplate. This patch includes a bit of documentation, so see that for
more information.
This was not a welcome change---I jumped down this rabbit hole trying to
decompose `AirAggregate` so that I can share portions of parsing with the
current parser and a template parser. I can now proceed with that.
This is not the only implementation that I had tried. I previously inverted
the approach, as I've been doing manually for some time: manually create
types to hold the sets of variants, and then create a sum type to hold those
types. That works, but it resulted in a mess for systems that have to use
the IR, since now you have two enums to contend with. I didn't find that to
be appropriate, because we shouldn't complicate the external API for
implementation details.
The enum for IRs is supposed to be like a bytecode---a list of operations
that can be performed with the IR. They can be grouped if it makes sense
for a public API, but in my case, I only wanted subsets for the sake of
delegating responsibilities to smaller subsystems, while retaining the
context that `match` provides via its exhaustiveness checking but does not
expose as something concrete (which is deeply frustrating!).
Anyway, here we are; this'll be refined over time, hopefully, and
portions of it can be generalized for removing boilerplate from other IRs.
Another thing to note is that this syntax is really a compromise---I had to
move on, and I was spending too much time trying to get creative with
`macro_rules!`. It isn't the best, and it doesn't seem very Rust-like in
some places and is therefore not necessarily all that intuitive. This can
be refined further in the future. But the end result, all things
considered, isn't too bad.
DEV-13708
2023-03-02 15:15:28 -05:00
|
|
|
return Transition(Ready).ok(Air::Todo(UNKNOWN_SPAN));
|
2023-01-23 16:30:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(unreachable_code)] // due to wip-nir-to-air
|
|
|
|
match (self, tok) {
|
2023-01-30 16:51:24 -05:00
|
|
|
(Ready, Nir::Open(NirEntity::Package, span)) => {
|
|
|
|
Transition(Ready).ok(Air::PkgOpen(span))
|
|
|
|
}
|
|
|
|
|
|
|
|
(Ready, Nir::Close(NirEntity::Package, span)) => {
|
|
|
|
Transition(Ready).ok(Air::PkgClose(span))
|
|
|
|
}
|
|
|
|
|
2023-02-22 23:45:23 -05:00
|
|
|
(Ready, Nir::Open(NirEntity::Rate | NirEntity::Sum, span)) => {
|
2023-01-23 16:30:25 -05:00
|
|
|
Transition(Ready).ok(Air::ExprOpen(ExprOp::Sum, span))
|
|
|
|
}
|
2023-02-24 15:55:25 -05:00
|
|
|
(Ready, Nir::Open(NirEntity::Product, span)) => {
|
|
|
|
Transition(Ready).ok(Air::ExprOpen(ExprOp::Product, span))
|
2023-01-23 16:30:25 -05:00
|
|
|
}
|
2023-02-24 23:01:02 -05:00
|
|
|
(Ready, Nir::Open(NirEntity::Classify | NirEntity::All, span)) => {
|
|
|
|
Transition(Ready).ok(Air::ExprOpen(ExprOp::Conj, span))
|
|
|
|
}
|
|
|
|
(Ready, Nir::Open(NirEntity::Any, span)) => {
|
|
|
|
Transition(Ready).ok(Air::ExprOpen(ExprOp::Disj, span))
|
|
|
|
}
|
2023-01-23 16:30:25 -05:00
|
|
|
|
2023-02-28 15:31:49 -05:00
|
|
|
(Ready, Nir::Open(NirEntity::Tpl, span)) => {
|
|
|
|
Transition(Ready).ok(Air::TplOpen(span))
|
|
|
|
}
|
|
|
|
|
|
|
|
(Ready, Nir::Close(NirEntity::Tpl, span)) => {
|
|
|
|
Transition(Ready).ok(Air::TplClose(span))
|
|
|
|
}
|
|
|
|
|
2023-02-24 15:55:25 -05:00
|
|
|
(
|
|
|
|
Ready,
|
|
|
|
Nir::Close(
|
2023-02-24 23:01:02 -05:00
|
|
|
NirEntity::Rate
|
|
|
|
| NirEntity::Sum
|
|
|
|
| NirEntity::Product
|
|
|
|
| NirEntity::Classify
|
|
|
|
| NirEntity::All
|
|
|
|
| NirEntity::Any,
|
2023-02-24 15:55:25 -05:00
|
|
|
span,
|
|
|
|
),
|
|
|
|
) => Transition(Ready).ok(Air::ExprClose(span)),
|
|
|
|
|
2023-01-23 16:30:25 -05:00
|
|
|
(Ready, Nir::BindIdent(spair)) => {
|
2023-02-28 11:31:06 -05:00
|
|
|
Transition(Ready).ok(Air::BindIdent(spair))
|
2023-01-23 16:30:25 -05:00
|
|
|
}
|
|
|
|
|
2023-02-24 16:41:17 -05:00
|
|
|
(
|
|
|
|
Ready,
|
|
|
|
Nir::Todo
|
|
|
|
| Nir::TodoAttr(..)
|
|
|
|
| Nir::Ref(..)
|
|
|
|
| Nir::Desc(..)
|
|
|
|
| Nir::Text(_)
|
|
|
|
| Nir::Open(NirEntity::TplParam, _)
|
|
|
|
| Nir::Close(NirEntity::TplParam, _),
|
tamer: asg::air: AIR as a sum IR
This introduces a new macro `sum_ir!` to help with a long-standing problem
of not being able to easily narrow types in Rust without a whole lot of
boilerplate. This patch includes a bit of documentation, so see that for
more information.
This was not a welcome change---I jumped down this rabbit hole trying to
decompose `AirAggregate` so that I can share portions of parsing with the
current parser and a template parser. I can now proceed with that.
This is not the only implementation that I had tried. I previously inverted
the approach, as I've been doing manually for some time: manually create
types to hold the sets of variants, and then create a sum type to hold those
types. That works, but it resulted in a mess for systems that have to use
the IR, since now you have two enums to contend with. I didn't find that to
be appropriate, because we shouldn't complicate the external API for
implementation details.
The enum for IRs is supposed to be like a bytecode---a list of operations
that can be performed with the IR. They can be grouped if it makes sense
for a public API, but in my case, I only wanted subsets for the sake of
delegating responsibilities to smaller subsystems, while retaining the
context that `match` provides via its exhaustiveness checking but does not
expose as something concrete (which is deeply frustrating!).
Anyway, here we are; this'll be refined over time, hopefully, and
portions of it can be generalized for removing boilerplate from other IRs.
Another thing to note is that this syntax is really a compromise---I had to
move on, and I was spending too much time trying to get creative with
`macro_rules!`. It isn't the best, and it doesn't seem very Rust-like in
some places and is therefore not necessarily all that intuitive. This can
be refined further in the future. But the end result, all things
considered, isn't too bad.
DEV-13708
2023-03-02 15:15:28 -05:00
|
|
|
) => Transition(Ready).ok(Air::Todo(UNKNOWN_SPAN)),
|
2023-01-23 16:30:25 -05:00
|
|
|
}
|
2022-12-13 13:34:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn is_accepting(&self, _: &Self::Context) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
|
|
pub enum NirToAirError {
|
|
|
|
Todo,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for NirToAirError {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
use NirToAirError::*;
|
|
|
|
|
|
|
|
match self {
|
|
|
|
Todo => write!(f, "TODO"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for NirToAirError {}
|
|
|
|
|
|
|
|
impl Diagnostic for NirToAirError {
|
|
|
|
fn describe(&self) -> Vec<crate::diagnose::AnnotatedSpan> {
|
|
|
|
// TODO
|
|
|
|
vec![]
|
|
|
|
}
|
|
|
|
}
|
2023-01-23 16:30:25 -05:00
|
|
|
|
|
|
|
#[cfg(all(test, feature = "wip-nir-to-air"))]
|
|
|
|
mod test;
|