graphix-compiler 0.9.0

A dataflow language for UIs and network programming, compiler
Documentation
use super::{
    array::{Array, ArrayRef, ArraySlice},
    bind::{Bind, ByRef, Deref, Ref},
    callsite::CallSite,
    data::{Struct, StructRef, StructWith, Tuple, TupleRef, Variant},
    error::{Qop, TryCatch},
    lambda::Lambda,
    module::Module,
    op::{Add, And, Div, Eq, Gt, Gte, Lt, Lte, Mod, Mul, Ne, Not, Or, Sub},
    select::Select,
    Any, Block, Connect, ConnectDeref, Constant, Sample, StringInterpolate, TypeCast,
    TypeDef, Use,
};
use crate::{
    expr::{
        self, ApplyExpr, Expr, ExprId, ExprKind, ModuleKind, SelectExpr, StructExpr,
        StructWithExpr,
    },
    node::{
        error::OrNever,
        map::{Map, MapRef},
        op::{CheckedAdd, CheckedDiv, CheckedMod, CheckedMul, CheckedSub},
        ExplicitParens, Nop,
    },
    typ::Type,
    CFlag, ExecCtx, Node, Rt, Scope, UserEvent,
};
use anyhow::{bail, Context, Result};
use compact_str::format_compact;
use enumflags2::BitFlags;

pub(crate) fn compile<R: Rt, E: UserEvent>(
    ctx: &mut ExecCtx<R, E>,
    flags: BitFlags<CFlag>,
    spec: Expr,
    scope: &Scope,
    top_id: ExprId,
) -> Result<Node<R, E>> {
    if ctx.env.lsp_mode {
        ctx.scope_map.push(crate::ScopeMapEntry {
            pos: spec.pos,
            ori: spec.ori.clone(),
            scope: scope.clone(),
        });
    }
    match &spec.kind {
        ExprKind::NoOp => Ok(Nop::new(Type::Bottom)),
        ExprKind::ExplicitParens(s) => {
            ExplicitParens::compile(ctx, flags, (**s).clone(), scope, top_id)
        }
        ExprKind::Constant(v) => Constant::compile(spec.clone(), v),
        ExprKind::Do { exprs } => {
            let scope = scope.append(&format_compact!("do{}", spec.id.inner()));
            Block::compile(ctx, flags, spec.clone(), &scope, top_id, false, exprs)
        }
        ExprKind::Array { args } => {
            Array::compile(ctx, flags, spec.clone(), scope, top_id, args)
        }
        ExprKind::ArrayRef { source, i } => {
            ArrayRef::compile(ctx, flags, spec.clone(), scope, top_id, source, i)
        }
        ExprKind::ArraySlice { source, start, end } => ArraySlice::compile(
            ctx,
            flags,
            spec.clone(),
            scope,
            top_id,
            source,
            start,
            end,
        ),
        ExprKind::StringInterpolate { args } => {
            StringInterpolate::compile(ctx, flags, spec.clone(), scope, top_id, args)
        }
        ExprKind::Tuple { args } => {
            Tuple::compile(ctx, flags, spec.clone(), scope, top_id, args)
        }
        ExprKind::Variant { tag, args } => {
            Variant::compile(ctx, flags, spec.clone(), scope, top_id, tag, args)
        }
        ExprKind::Struct(StructExpr { args }) => {
            Struct::compile(ctx, flags, spec.clone(), scope, top_id, args)
        }
        ExprKind::Module { name, value } => {
            let scope = scope.append(&name);
            if ctx.env.modules.contains(&scope.lexical) {
                bail!("duplicate module definition {}", scope.lexical)
            }
            if ctx.env.lsp_mode {
                let def_ori = match value {
                    ModuleKind::Resolved { exprs, .. } => {
                        exprs.first().map(|e| e.ori.clone())
                    }
                    _ => None,
                };
                ctx.module_references.push(crate::ModuleRefSite {
                    pos: spec.pos,
                    ori: spec.ori.clone(),
                    name: crate::expr::ModPath::from([name.as_str()]),
                    canonical: scope.lexical.clone(),
                    def_ori,
                });
            }
            match value {
                ModuleKind::Unresolved { .. } => {
                    bail!("external modules are not allowed in this context")
                }
                ModuleKind::Resolved { exprs, sig: None, from_interface: _ } => {
                    let res = Block::compile(
                        ctx,
                        flags,
                        spec.clone(),
                        &scope,
                        top_id,
                        true,
                        exprs,
                    )
                    .with_context(|| spec.ori.clone())?;
                    ctx.env.modules.insert_cow(scope.lexical.clone());
                    Ok(res)
                }
                ModuleKind::Resolved { exprs, sig: Some(sig), from_interface: _ } => {
                    Module::compile_static(
                        ctx,
                        flags,
                        spec.clone(),
                        &scope,
                        sig.clone(),
                        exprs.clone(),
                        top_id,
                    )
                }
                ModuleKind::Dynamic { sandbox, sig, source } => Module::compile_dynamic(
                    ctx,
                    flags,
                    spec.clone(),
                    &scope,
                    sandbox.clone(),
                    sig.clone(),
                    source.clone(),
                    top_id,
                ),
            }
        }
        ExprKind::Use { name } => Use::compile(ctx, spec.clone(), scope, name),
        ExprKind::Connect { name, value, deref: true } => {
            ConnectDeref::compile(ctx, flags, spec.clone(), scope, top_id, name, value)
        }
        ExprKind::Connect { name, value, deref: false } => {
            Connect::compile(ctx, flags, spec.clone(), scope, top_id, name, value)
        }
        ExprKind::Lambda(l) => {
            Lambda::compile(ctx, flags, spec.clone(), scope, l, top_id)
        }
        ExprKind::Any { args } => {
            Any::compile(ctx, flags, spec.clone(), scope, top_id, args)
        }
        ExprKind::Apply(ApplyExpr { args, function: f }) => {
            CallSite::compile(ctx, flags, spec.clone(), scope, top_id, args, f)
        }
        ExprKind::Bind(b) => Bind::compile(ctx, flags, spec.clone(), scope, top_id, b),
        ExprKind::Qop(e) => Qop::compile(ctx, flags, spec.clone(), scope, top_id, e),
        ExprKind::OrNever(e) => {
            OrNever::compile(ctx, flags, spec.clone(), scope, top_id, e)
        }
        ExprKind::TryCatch(tc) => {
            TryCatch::new(ctx, flags, spec.clone(), scope, top_id, tc)
        }
        ExprKind::ByRef(e) => ByRef::compile(ctx, flags, spec.clone(), scope, top_id, e),
        ExprKind::Deref(e) => Deref::compile(ctx, flags, spec.clone(), scope, top_id, e),
        ExprKind::Ref { name } => Ref::compile(ctx, spec.clone(), scope, top_id, name),
        ExprKind::TupleRef { source, field } => {
            TupleRef::compile(ctx, flags, spec.clone(), scope, top_id, source, field)
        }
        ExprKind::StructRef { source, field } => {
            StructRef::compile(ctx, flags, spec.clone(), scope, top_id, source, field)
        }
        ExprKind::StructWith(StructWithExpr { source, replace }) => {
            StructWith::compile(ctx, flags, spec.clone(), scope, top_id, source, replace)
        }
        ExprKind::Select(SelectExpr { arg, arms }) => {
            Select::compile(ctx, flags, spec.clone(), scope, top_id, arg, arms)
        }
        ExprKind::TypeCast { expr, typ } => {
            TypeCast::compile(ctx, flags, spec.clone(), scope, top_id, expr, typ)
        }
        ExprKind::TypeDef(expr::TypeDefExpr { name, params, typ }) => {
            TypeDef::compile(ctx, spec.clone(), scope, name, params, typ)
        }
        ExprKind::Map { args } => {
            Map::compile(ctx, flags, spec.clone(), scope, top_id, args)
        }
        ExprKind::MapRef { source, key } => {
            MapRef::compile(ctx, flags, spec.clone(), scope, top_id, source, key)
        }
        ExprKind::Not { expr } => {
            Not::compile(ctx, flags, spec.clone(), scope, top_id, expr)
        }
        ExprKind::Eq { lhs, rhs } => {
            Eq::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Ne { lhs, rhs } => {
            Ne::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Lt { lhs, rhs } => {
            Lt::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Gt { lhs, rhs } => {
            Gt::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Lte { lhs, rhs } => {
            Lte::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Gte { lhs, rhs } => {
            Gte::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::And { lhs, rhs } => {
            And::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Or { lhs, rhs } => {
            Or::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Add { lhs, rhs } => {
            Add::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::CheckedAdd { lhs, rhs } => {
            CheckedAdd::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Sub { lhs, rhs } => {
            Sub::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::CheckedSub { lhs, rhs } => {
            CheckedSub::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Mul { lhs, rhs } => {
            Mul::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::CheckedMul { lhs, rhs } => {
            CheckedMul::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Div { lhs, rhs } => {
            Div::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::CheckedDiv { lhs, rhs } => {
            CheckedDiv::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Mod { lhs, rhs } => {
            Mod::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::CheckedMod { lhs, rhs } => {
            CheckedMod::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
        ExprKind::Sample { lhs, rhs } => {
            Sample::compile(ctx, flags, spec.clone(), scope, top_id, lhs, rhs)
        }
    }
}