mod eval;
mod ir_compiler;
mod ir_error;
mod ir_interpreter;
mod ir_query;
mod ir_value;
pub use self::eval::{IrEval, IrEvalBreak, IrEvalOutcome};
pub use self::ir_compiler::{IrCompile, IrCompiler};
pub use self::ir_error::{IrError, IrErrorKind};
pub use self::ir_interpreter::IrInterpreter;
pub use self::ir_value::IrValue;
pub(crate) use self::ir_interpreter::IrBudget;
pub(crate) use self::ir_query::IrQuery;
use crate::Spanned;
use runestick::{ConstValue, Span};
macro_rules! decl_kind {
(
$(#[$meta:meta])*
$vis:vis enum $name:ident {
$($(#[$field_meta:meta])* $variant:ident($ty:ty)),* $(,)?
}
) => {
$(#[$meta])*
$vis enum $name {
$($(#[$field_meta])* $variant($ty),)*
}
$(
impl From<$ty> for $name {
fn from(value: $ty) -> $name {
$name::$variant(value)
}
}
)*
}
}
#[derive(Debug, Clone, Spanned)]
pub struct Ir {
#[rune(span)]
pub(crate) span: Span,
pub(crate) kind: IrKind,
}
impl Ir {
pub(crate) fn new<S, K>(spanned: S, kind: K) -> Self
where
S: Spanned,
IrKind: From<K>,
{
Self {
span: spanned.span(),
kind: IrKind::from(kind),
}
}
}
#[derive(Debug, Clone, Spanned)]
pub struct IrTarget {
#[rune(span)]
pub(crate) span: Span,
pub(crate) kind: IrTargetKind,
}
#[derive(Debug, Clone)]
pub enum IrTargetKind {
Name(Box<str>),
Field(Box<IrTarget>, Box<str>),
Index(Box<IrTarget>, usize),
}
decl_kind! {
#[derive(Debug, Clone)]
pub enum IrKind {
Scope(IrScope),
Binary(IrBinary),
Decl(IrDecl),
Set(IrSet),
Assign(IrAssign),
Template(IrTemplate),
Name(Box<str>),
Target(IrTarget),
Value(ConstValue),
Branches(IrBranches),
Loop(IrLoop),
Break(IrBreak),
Vec(IrVec),
Tuple(IrTuple),
Object(IrObject),
Call(IrCall),
}
}
#[derive(Debug, Clone, Spanned)]
pub struct IrFn {
#[rune(span)]
pub(crate) span: Span,
pub(crate) args: Vec<Box<str>>,
pub(crate) ir: Ir,
}
#[derive(Debug, Clone, Spanned)]
pub struct IrScope {
#[rune(span)]
pub(crate) span: Span,
pub(crate) instructions: Vec<Ir>,
pub(crate) last: Option<Box<Ir>>,
}
#[derive(Debug, Clone, Spanned)]
pub struct IrBinary {
#[rune(span)]
pub(crate) span: Span,
pub(crate) op: IrBinaryOp,
pub(crate) lhs: Box<Ir>,
pub(crate) rhs: Box<Ir>,
}
#[derive(Debug, Clone, Spanned)]
pub struct IrDecl {
#[rune(span)]
pub(crate) span: Span,
pub(crate) name: Box<str>,
pub(crate) value: Box<Ir>,
}
#[derive(Debug, Clone, Spanned)]
pub struct IrSet {
#[rune(span)]
pub(crate) span: Span,
pub(crate) target: IrTarget,
pub(crate) value: Box<Ir>,
}
#[derive(Debug, Clone, Spanned)]
pub struct IrAssign {
#[rune(span)]
pub(crate) span: Span,
pub(crate) target: IrTarget,
pub(crate) value: Box<Ir>,
pub(crate) op: IrAssignOp,
}
#[derive(Debug, Clone, Spanned)]
pub struct IrTemplate {
#[rune(span)]
pub(crate) span: Span,
pub(crate) components: Vec<IrTemplateComponent>,
}
#[derive(Debug, Clone)]
pub enum IrTemplateComponent {
Ir(Ir),
String(Box<str>),
}
#[derive(Debug, Clone)]
pub struct IrBranches {
pub(crate) branches: Vec<(IrCondition, IrScope)>,
pub(crate) default_branch: Option<IrScope>,
}
#[derive(Debug, Clone, Spanned)]
pub enum IrCondition {
Ir(Ir),
Let(IrLet),
}
#[derive(Debug, Clone, Spanned)]
pub struct IrLet {
#[rune(span)]
pub(crate) span: Span,
pub(crate) pat: IrPat,
pub(crate) ir: Ir,
}
#[derive(Debug, Clone)]
pub enum IrPat {
Ignore,
Binding(Box<str>),
}
#[derive(Debug, Clone, Spanned)]
pub struct IrLoop {
#[rune(span)]
pub(crate) span: Span,
pub(crate) label: Option<Box<str>>,
pub(crate) condition: Option<Box<IrCondition>>,
pub(crate) body: IrScope,
}
#[derive(Debug, Clone, Spanned)]
pub struct IrBreak {
#[rune(span)]
pub(crate) span: Span,
pub(crate) kind: IrBreakKind,
}
#[derive(Debug, Clone)]
pub enum IrBreakKind {
Inherent,
Label(Box<str>),
Ir(Box<Ir>),
}
#[derive(Debug, Clone, Spanned)]
pub struct IrTuple {
#[rune(span)]
pub(crate) span: Span,
pub(crate) items: Box<[Ir]>,
}
#[derive(Debug, Clone, Spanned)]
pub struct IrObject {
#[rune(span)]
pub(crate) span: Span,
pub(crate) assignments: Box<[(Box<str>, Ir)]>,
}
#[derive(Debug, Clone, Spanned)]
pub struct IrCall {
#[rune(span)]
pub(crate) span: Span,
pub(crate) target: Box<str>,
pub(crate) args: Vec<Ir>,
}
#[derive(Debug, Clone, Spanned)]
pub struct IrVec {
#[rune(span)]
pub(crate) span: Span,
pub(crate) items: Box<[Ir]>,
}
#[derive(Debug, Clone, Copy)]
pub enum IrBinaryOp {
Add,
Sub,
Mul,
Div,
Shl,
Shr,
Lt,
Lte,
Eq,
Gt,
Gte,
}
#[derive(Debug, Clone, Copy)]
pub enum IrAssignOp {
Add,
Sub,
Mul,
Div,
Shl,
Shr,
}
impl IrAssignOp {
pub(crate) fn assign<S>(
self,
spanned: S,
target: &mut IrValue,
operand: IrValue,
) -> Result<(), IrError>
where
S: Copy + Spanned,
{
if let IrValue::Integer(target) = target {
if let IrValue::Integer(operand) = operand {
return Ok(self.assign_int(spanned, target, operand)?);
}
}
Err(IrError::msg(spanned, "unsupported operands"))
}
fn assign_int<S>(
self,
spanned: S,
target: &mut num::BigInt,
operand: num::BigInt,
) -> Result<(), IrError>
where
S: Copy + Spanned,
{
use std::convert::TryFrom;
use std::ops::{AddAssign, MulAssign, ShlAssign, ShrAssign, SubAssign};
match self {
IrAssignOp::Add => {
target.add_assign(operand);
}
IrAssignOp::Sub => {
target.sub_assign(operand);
}
IrAssignOp::Mul => {
target.mul_assign(operand);
}
IrAssignOp::Div => {
*target = target
.checked_div(&operand)
.ok_or_else(|| IrError::msg(spanned, "division by zero"))?;
}
IrAssignOp::Shl => {
let operand =
u32::try_from(operand).map_err(|_| IrError::msg(spanned, "bad operand"))?;
target.shl_assign(operand);
}
IrAssignOp::Shr => {
let operand =
u32::try_from(operand).map_err(|_| IrError::msg(spanned, "bad operand"))?;
target.shr_assign(operand);
}
}
Ok(())
}
}