harn-kernel 0.10.52

Portable compiler, program artifact, and deterministic execution kernel for Harn
Documentation
use harn_parser::{ShapeField, TypeExpr};

use crate::Constant;

use super::WireProgram;
use crate::artifact::{Diagnostic, EntryKind};

pub(in crate::artifact) fn encode_wire_program(
    program: &WireProgram,
) -> Result<Vec<u8>, Diagnostic> {
    let mut writer = ArtifactWriter::new();
    writer.bytes(&program.semantic_abi);
    writer.string(&program.entry)?;
    writer.u8(match program.entry_kind {
        EntryKind::Function => 0,
        EntryKind::Pipeline => 1,
    });
    writer.boolean(program.expects_harness);
    writer.len(program.chunks.len(), "chunks")?;
    writer.len(program.functions.len(), "functions")?;
    for chunk in &program.chunks {
        writer.byte_vec(&chunk.code, "instruction bytes")?;
        writer.len(chunk.constants.len(), "constants")?;
        for constant in &chunk.constants {
            writer.constant(constant)?;
        }
        writer.u32_vec(&chunk.lines, "source lines")?;
        writer.u32_vec(&chunk.columns, "source columns")?;
        writer.optional_string(chunk.source_file.as_deref())?;
        writer.len(chunk.functions.len(), "function references")?;
        for function in &chunk.functions {
            writer.u32(*function);
        }
        writer.len(chunk.local_slots.len(), "local slots")?;
        for slot in &chunk.local_slots {
            writer.string(&slot.name)?;
            writer.boolean(slot.mutable);
            writer.u32(slot.scope_depth);
        }
        writer.boolean(chunk.references_outer_names);
    }
    for function in &program.functions {
        writer.string(&function.name)?;
        writer.string_vec(&function.type_params, "type parameters")?;
        writer.string_vec(&function.nominal_type_names, "nominal type names")?;
        writer.len(function.params.len(), "parameters")?;
        for param in &function.params {
            writer.string(&param.name)?;
            match &param.type_expr {
                Some(type_expr) => {
                    writer.u8(1);
                    writer.type_expr(type_expr)?;
                }
                None => writer.u8(0),
            }
            writer.boolean(param.has_default);
        }
        match function.default_start {
            Some(start) => {
                writer.u8(1);
                writer.u32(start);
            }
            None => writer.u8(0),
        }
        writer.u32(function.chunk);
        writer.boolean(function.is_generator);
        writer.boolean(function.is_stream);
        writer.boolean(function.has_rest_param);
        writer.boolean(function.has_runtime_type_checks);
    }
    Ok(writer.finish())
}

struct ArtifactWriter {
    bytes: Vec<u8>,
}

impl ArtifactWriter {
    fn new() -> Self {
        Self { bytes: Vec::new() }
    }

    fn finish(self) -> Vec<u8> {
        self.bytes
    }

    fn bytes(&mut self, bytes: &[u8]) {
        self.bytes.extend_from_slice(bytes);
    }

    fn u8(&mut self, value: u8) {
        self.bytes.push(value);
    }

    fn boolean(&mut self, value: bool) {
        self.u8(value.into());
    }

    fn u32(&mut self, value: u32) {
        self.bytes.extend_from_slice(&value.to_be_bytes());
    }

    fn u64(&mut self, value: u64) {
        self.bytes.extend_from_slice(&value.to_be_bytes());
    }

    fn i64(&mut self, value: i64) {
        self.bytes.extend_from_slice(&value.to_be_bytes());
    }

    fn len(&mut self, value: usize, kind: &str) -> Result<(), Diagnostic> {
        let value = u32::try_from(value).map_err(|_| {
            Diagnostic::artifact(
                "artifact_too_large",
                format!("artifact has too many {kind} for the portable u32 format"),
            )
        })?;
        self.u32(value);
        Ok(())
    }

    fn string(&mut self, value: &str) -> Result<(), Diagnostic> {
        self.len(value.len(), "string bytes")?;
        self.bytes(value.as_bytes());
        Ok(())
    }

    fn optional_string(&mut self, value: Option<&str>) -> Result<(), Diagnostic> {
        match value {
            Some(value) => {
                self.u8(1);
                self.string(value)
            }
            None => {
                self.u8(0);
                Ok(())
            }
        }
    }

    fn byte_vec(&mut self, value: &[u8], kind: &str) -> Result<(), Diagnostic> {
        self.len(value.len(), kind)?;
        self.bytes(value);
        Ok(())
    }

    fn u32_vec(&mut self, value: &[u32], kind: &str) -> Result<(), Diagnostic> {
        self.len(value.len(), kind)?;
        for item in value {
            self.u32(*item);
        }
        Ok(())
    }

    fn string_vec(&mut self, value: &[String], kind: &str) -> Result<(), Diagnostic> {
        self.len(value.len(), kind)?;
        for item in value {
            self.string(item)?;
        }
        Ok(())
    }

    fn constant(&mut self, constant: &Constant) -> Result<(), Diagnostic> {
        match constant {
            Constant::Int(value) => {
                self.u8(0);
                self.i64(*value);
            }
            Constant::Float(value) => {
                self.u8(1);
                self.u64(value.to_bits());
            }
            Constant::String(value) => {
                self.u8(2);
                self.string(value)?;
            }
            Constant::Bool(value) => {
                self.u8(3);
                self.boolean(*value);
            }
            Constant::Nil => self.u8(4),
            Constant::Duration(value) => {
                self.u8(5);
                self.i64(*value);
            }
        }
        Ok(())
    }

    fn type_expr(&mut self, type_expr: &TypeExpr) -> Result<(), Diagnostic> {
        match type_expr {
            TypeExpr::Named(name) => {
                self.u8(0);
                self.string(name)?;
            }
            TypeExpr::Union(items) => {
                self.u8(1);
                self.type_vec(items, "union members")?;
            }
            TypeExpr::Intersection(items) => {
                self.u8(2);
                self.type_vec(items, "intersection members")?;
            }
            TypeExpr::Shape(fields) => {
                self.u8(3);
                self.shape_fields(fields)?;
            }
            TypeExpr::OpenShape { fields, rests } => {
                self.u8(4);
                self.shape_fields(fields)?;
                self.type_vec(rests, "open-shape rests")?;
            }
            TypeExpr::List(inner) => {
                self.u8(5);
                self.type_expr(inner)?;
            }
            TypeExpr::Tuple(items) => {
                self.u8(6);
                self.type_vec(items, "tuple members")?;
            }
            TypeExpr::DictType(key, value) => {
                self.u8(7);
                self.type_expr(key)?;
                self.type_expr(value)?;
            }
            TypeExpr::Iter(inner) => {
                self.u8(8);
                self.type_expr(inner)?;
            }
            TypeExpr::Generator(inner) => {
                self.u8(9);
                self.type_expr(inner)?;
            }
            TypeExpr::Stream(inner) => {
                self.u8(10);
                self.type_expr(inner)?;
            }
            TypeExpr::Owned(inner) => {
                self.u8(11);
                self.type_expr(inner)?;
            }
            TypeExpr::Applied { name, args } => {
                self.u8(12);
                self.string(name)?;
                self.type_vec(args, "applied type arguments")?;
            }
            TypeExpr::FnType {
                params,
                return_type,
            } => {
                self.u8(13);
                self.type_vec(params, "function type parameters")?;
                self.type_expr(return_type)?;
            }
            TypeExpr::Never => self.u8(14),
            TypeExpr::LitString(value) => {
                self.u8(15);
                self.string(value)?;
            }
            TypeExpr::LitInt(value) => {
                self.u8(16);
                self.i64(*value);
            }
        }
        Ok(())
    }

    fn type_vec(&mut self, values: &[TypeExpr], kind: &str) -> Result<(), Diagnostic> {
        self.len(values.len(), kind)?;
        for value in values {
            self.type_expr(value)?;
        }
        Ok(())
    }

    fn shape_fields(&mut self, fields: &[ShapeField]) -> Result<(), Diagnostic> {
        self.len(fields.len(), "shape fields")?;
        for field in fields {
            self.string(&field.name)?;
            self.type_expr(&field.type_expr)?;
            self.boolean(field.optional);
        }
        Ok(())
    }
}