Files @ 729feec4d37a
Branch filter:

Location: CSY/reowolf/src/protocol/ast_printer.rs

729feec4d37a 13.4 KiB application/rls-services+xml Show Annotation Show as Raw Download as Raw
MH
WIP on debugging AST writing
use std::fmt::{Display, Write};
use std::io::Write as IOWrite;

use super::ast::*;
use std::borrow::Borrow;

const INDENT: usize = 2;

const PREFIX_EMPTY: &'static str = "    ";
const PREFIX_ROOT_ID: &'static str = "Root";
const PREFIX_PRAGMA_ID: &'static str = "Prag";
const PREFIX_IMPORT_ID: &'static str = "Imp ";
const PREFIX_TYPE_ANNOT_ID: &'static str = "TyAn";
const PREFIX_VARIABLE_ID: &'static str = "Var ";
const PREFIX_PARAMETER_ID: &'static str = "Par ";
const PREFIX_LOCAL_ID: &'static str = "Loc ";
const PREFIX_DEFINITION_ID: &'static str = "Def ";
const PREFIX_STRUCT_ID: &'static str = "DefS";
const PREFIX_ENUM_ID: &'static str = "DefE";
const PREFIX_COMPONENT_ID: &'static str = "DefC";
const PREFIX_FUNCTION_ID: &'static str = "DefF";
const PREFIX_STMT_ID: &'static str = "Stmt";
const PREFIX_BLOCK_STMT_ID: &'static str = "SBl ";
const PREFIX_LOCAL_STMT_ID: &'static str = "SLoc";
const PREFIX_MEM_STMT_ID: &'static str = "SMem";
const PREFIX_CHANNEL_STMT_ID: &'static str = "SCha";
const PREFIX_SKIP_STMT_ID: &'static str = "SSki";
const PREFIX_LABELED_STMT_ID: &'static str = "SLab";
const PREFIX_IF_STMT_ID: &'static str = "SIf ";
const PREFIX_ENDIF_STMT_ID: &'static str = "SEIf";
const PREFIX_WHILE_STMT_ID: &'static str = "SWhi";
const PREFIX_ENDWHILE_STMT_ID: &'static str = "SEWh";
const PREFIX_BREAK_STMT_ID: &'static str = "SBre";
const PREFIX_CONTINUE_STMT_ID: &'static str = "SCon";
const PREFIX_SYNC_STMT_ID: &'static str = "SSyn";
const PREFIX_ENDSYNC_STMT_ID: &'static str = "SESy";
const PREFIX_RETURN_STMT_ID: &'static str = "SRet";
const PREFIX_ASSERT_STMT_ID: &'static str = "SAsr";
const PREFIX_GOTO_STMT_ID: &'static str = "SGot";
const PREFIX_NEW_STMT_ID: &'static str = "SNew";
const PREFIX_PUT_STMT_ID: &'static str = "SPut";
const PREFIX_EXPR_STMT_ID: &'static str = "SExp";
const PREFIX_ASSIGNMENT_EXPR_ID: &'static str = "EAsi";
const PREFIX_CONDITIONAL_EXPR_ID: &'static str = "ECnd";
const PREFIX_BINARY_EXPR_ID: &'static str = "EBin";
const PREFIX_UNARY_EXPR_ID: &'static str = "EUna";
const PREFIX_INDEXING_EXPR_ID: &'static str = "EIdx";
const PREFIX_SLICING_EXPR_ID: &'static str = "ESli";
const PREFIX_SELECT_EXPR_ID: &'static str = "ESel";
const PREFIX_ARRAY_EXPR_ID: &'static str = "EArr";
const PREFIX_CONST_EXPR_ID: &'static str = "ECns";
const PREFIX_CALL_EXPR_ID: &'static str = "ECll";
const PREFIX_VARIABLE_EXPR_ID: &'static str = "EVar";

pub(crate) struct ASTWriter {
    buffer: String,
    temp: String,
}

impl ASTWriter {
    pub(crate) fn new() -> Self {
        Self{ buffer: String::with_capacity(4096), temp: String::with_capacity(256) }
    }
    pub(crate) fn write_ast<W: IOWrite>(&mut self, w: &mut W, heap: &Heap) {
        for root_id in heap.protocol_descriptions.iter().map(|v| v.this) {
            self.write_module(heap, root_id);
            w.write_all(self.buffer.as_bytes()).expect("flush buffer");
            self.buffer.clear();
        }
    }

    //--------------------------------------------------------------------------
    // Top-level module writing
    //--------------------------------------------------------------------------

    fn write_module(&mut self, heap: &Heap, root_id: RootId) {
        self.write_id_and_indent(PREFIX_ROOT_ID, root_id.0.index, 0);
        self.buffer.write_str("Module:\n");

        let root = &heap[root_id];

        self.write_indent(0);
        write!(&mut self.buffer, "- ID: {}\n", root.this.0.index);

        self.write_indent(0);
        self.buffer.write_str("- Pragmas:\n");

        for pragma_id in &root.pragmas {
            self.write_pragma(&heap[*pragma_id], 1);
        }

        self.write_indent(0);
        self.buffer.write_str("- Imports:\n");

        for import_id in &root.imports {
            self.write_import(&heap[*import_id], 1);
        }

        self.write_indent(0);
        self.buffer.write_str("- Definitions:\n");

        for definition_id in &root.definitions {
            self.write_definition(heap, &heap[*definition_id], 1);
        }
    }

    fn write_pragma(&mut self, pragma: &Pragma, indent: usize) {
        match pragma {
            Pragma::Version(pragma) => {
                self.write_id_and_indent(PREFIX_PRAGMA_ID, pragma.this.0.index, indent);
                write!(&mut self.buffer, "- Version: {}\n", pragma.version);
            },
            Pragma::Module(pragma) => {
                self.write_id_and_indent(PREFIX_PRAGMA_ID, pragma.this.0.index, indent);
                write!(&mut self.buffer, "- Module: {}\n", String::from_utf8_lossy(&pragma.value));
            }
        }
    }

    fn write_import(&mut self, import: &Import, indent: usize) {
        let indent2 = indent + 1;
        match import {
            Import::Module(import) => {
                self.write_id_and_indent(PREFIX_IMPORT_ID, import.this.0.index, indent);
                write!(&mut self.buffer, "- ModuleImport:\n");

                self.write_indent(indent2);
                write!(&mut self.buffer, "- Name: {}\n", String::from_utf8_lossy(&import.module_name));
                self.write_indent(indent2);
                write!(&mut self.buffer, "- Alias: {}\n", String::from_utf8_lossy(&import.alias));
                self.write_indent(indent2);
                write_option(&mut self.temp, import.module_id.map(|v| v.0.index));
                write!(&mut self.buffer, "- Target: {}\n", &self.temp);
            },
            Import::Symbols(import) => {
                self.write_id_and_indent(PREFIX_IMPORT_ID, import.this.0.index, indent);
                write!(&mut self.buffer, "- SymbolImport:\n");

                self.write_indent(indent2);
                write!(&mut self.buffer, "- Name: {}\n", String::from_utf8_lossy(&import.module_name));
                self.write_indent(indent2);
                write_option(&mut self.temp, import.module_id.map(|v| v.0.index));
                write!(&mut self.buffer, "- Target: {}\n", &self.temp);

                self.write_indent(indent2);
                write!(&mut self.buffer, "- Symbols:\n");

                let indent3 = indent2 + 1;
                let indent4 = indent3 + 1;
                for symbol in &import.symbols {
                    self.write_indent(indent3);
                    write!(&mut self.buffer, "- AliasedSymbol:\n");
                    self.write_indent(indent4);
                    write!(&mut self.buffer, "- Name: {}\n", String::from_utf8_lossy(&symbol.name));
                    self.write_indent(indent4);
                    write!(&mut self.buffer, "- Alias: {}\n", String::from_utf8_lossy(&symbol.alias));
                    self.write_indent(indent4);
                    write_option(&mut self.temp, symbol.definition_id.map(|v| v.0.index));
                    write!(&mut self.buffer, "- Definition: {}\n", &self.temp);
                }
            }
        }
    }

    //--------------------------------------------------------------------------
    // Top-level definition writing
    //--------------------------------------------------------------------------

    fn write_definition(&mut self, heap: &Heap, def: &Definition, indent: usize) {
        match def {
            Definition::Struct(_) => todo!("implement Definition::Struct"),
            Definition::Enum(_) => todo!("implement Definition::Enum"),
            Definition::Function(_) => todo!("implement Definition::Function"),
            Definition::Component(def) => {
                self.write_id_and_indent(PREFIX_COMPONENT_ID, def.this.0.0.index, indent);
                write!(&mut self.buffer, "- Component:\n");

                let indent2 = indent + 1;
                let indent3 = indent2 + 1;
                let indent4 = indent3 + 1;
                self.write_indent(indent2);
                write!(&mut self.buffer, "- Name: {}\n", String::from_utf8_lossy(&def.identifier.value));
                self.write_indent(indent2);
                write!(&mut self.buffer, "- Variant: {:?}\n", &def.variant);
                self.write_indent(indent2);
                write!(&mut self.buffer, "- Parameters:\n");

                for parameter_id in &def.parameters {
                    let param = &heap[*parameter_id];
                    self.write_indent(indent3);
                    write!(&mut self.buffer, "- Parameter\n");

                    self.write_indent(indent4);
                    write!(&mut self.buffer, "- Name: {}\n", String::from_utf8_lossy(&param.identifier.value));
                    self.write_indent(indent4);
                    write!(&mut self.buffer, "- Type: ");
                    write_type(&mut self.buffer, &heap[param.type_annotation]);
                    self.buffer.push('\n');
                }

                self.write_indent(indent2);
                write!(&mut self.buffer, "- Body:\n");

                self.write_stmt(heap, def.body, indent3);
            }
        }
    }

    fn write_stmt(&mut self, heap: &Heap, stmt_id: StatementId, indent: usize) {
        let stmt = &heap[stmt_id];

        match stmt {
            Statement::Block(stmt) => {
                self.write_id_and_indent(PREFIX_BLOCK_STMT_ID, stmt.this.0.0.index, indent);
                write!(&mut self.buffer, "- Block:\n");
                for stmt_id in &stmt.statements {
                    self.write_stmt(heap, *stmt_id, indent + 1);
                }
            },
            Statement::Local(stmt) => {
                match stmt {
                    LocalStatement::Channel(stmt) => {
                        self.write_id_and_indent(PREFIX_CHANNEL_STMT_ID, stmt.this.0.0.0.index, indent);
                        write!(&mut self.buffer, "- Channel:\n");

                        let indent2 = indent + 1;
                        let indent3 = indent2 + 1;
                        let from = &heap[stmt.from];
                        self.write_id_and_indent(PREFIX_LOCAL_ID, stmt.from.0.0.index, indent2);
                    },
                    LocalStatement::Memory(stmt) => {

                    }
                }
            },
            Statement::Skip(stmt) => {
                self.write_id_and_indent(PREFIX_SKIP_STMT_ID, stmt.this.0.0.index, indent);
                write!(&mut self.buffer, "- Skip\n");
            },
            Statement::Labeled(stmt) => {
                self.write_id_and_indent(PREFIX_LABELED_STMT_ID, stmt.this.0.0.index, indent);
                write!(&mut self.buffer, "- LabeledStatement\n");

                let indent1 = indent + 1;
                let indent2 = indent + 2;
                self.write_indent(indent1);
                write!(&mut self.buffer, "- Label: {}\n", String::from_utf8_lossy(&stmt.label.value));
                self.write_indent(indent1);
                write!(&mut self.buffer, "- Statement:\n");
                self.write_stmt(heap, stmt.body, indent2);
            },
            Statement::If(stmt) => {

            },
            Statement::EndIf(stmt) => {

            },
            Statement::While(stmt) => {

            },
            Statement::EndWhile(stmt) => {

            },
            Statement::Break(stmt) => {

            },
            Statement::Continue(stmt) => {

            },
            Statement::Synchronous(stmt) => {

            },
            Statement::EndSynchronous(stmt) => {

            },
            Statement::Return(stmt) => {

            },
            Statement::Assert(stmt) => {

            },
            Statement::Goto(stmt) => {

            },
            Statement::New(stmt) => {

            },
            Statement::Put(stmt) => {

            },
            Statement::Expression(stmt) => {

            }
        }
    }

    fn write_local(&mut self, heap: &Heap, local_id: LocalId, indent: usize) {
        o
    }

    //--------------------------------------------------------------------------
    // Printing Utilities
    //--------------------------------------------------------------------------

    fn write_id_and_indent(&mut self, prefix: &'static str, id: u32, indent: usize) {
        write!(&mut self.buffer, "{}[{:04}] ", prefix, id);
        for _ in 0..indent*INDENT {
            self.buffer.push(' ');
        }
    }

    fn write_indent(&mut self, indent: usize) {
        write!(&mut self.buffer, "{}       ", PREFIX_EMPTY);
        for _ in 0..indent*INDENT {
            self.buffer.push(' ');
        }
    }

    fn flush<W: IOWrite>(&mut self, w: &mut W) {
        w.write(self.buffer.as_bytes()).unwrap();
        self.buffer.clear()
    }
}

fn write_option<V: Display>(target: &mut String, value: Option<V>) {
    target.clear();
    match &value {
        Some(v) => write!(target, "Some({})", v),
        None => target.write_str("None")
    };
}

fn write_type(target: &mut String, t: &TypeAnnotation) {
    match &t.the_type.primitive {
        PrimitiveType::Input => target.write_str("in"),
        PrimitiveType::Output => target.write_str("out"),
        PrimitiveType::Message => target.write_str("msg"),
        PrimitiveType::Boolean => target.write_str("bool"),
        PrimitiveType::Byte => target.write_str("byte"),
        PrimitiveType::Short => target.write_str("short"),
        PrimitiveType::Int => target.write_str("int"),
        PrimitiveType::Long => target.write_str("long"),
        PrimitiveType::Symbolic(symbolic) => {
            let mut temp = String::new();
            write_option(&mut temp, symbolic.definition.map(|v| v.0.index));
            write!(target, "Symbolic(name: {}, target: {})", String::from_utf8_lossy(&symbolic.identifier.value), &temp);
        }
    };

    if t.the_type.array {
        target.push_str("[]");
    }
}