### DMASM Error Type Examples Source: https://context7.com/willox/dmasm/llms.txt Demonstrates instantiation of various error types from dmasm for assembly, disassembly, and compilation. CompileError handling shows matching specific error variants. ```rust use dmasm::assembler::AssembleError; use dmasm::disassembler::DisassembleError; use dmasm::compiler::CompileError; // AssembleError variants let _ = AssembleError::ProcNotFound("/proc/missing".into()); let _ = AssembleError::TypeNotFound("/datum/nope".into()); let _ = AssembleError::InvalidVariableName; // DisassembleError variants — all carry byte offset context let _ = DisassembleError::UnknownOpcode { offset: 0x0C, opcode: 0xDEAD }; let _ = DisassembleError::InvalidString { offset: 0x04, id: 9999 }; let _ = DisassembleError::InvalidProc { offset: 0x08, id: 1234 }; let _ = DisassembleError::UnexpectedEnd; // CompileError — wraps dreammaker parse errors let result = dmasm::compiler::compile_expr("a +* b", &["a", "b"]); match result { Err(CompileError::ParseError(e)) => eprintln!("parse: {}", e), Err(CompileError::UnsupportedBuiltin { proc }) => eprintln!("builtin: {}", proc), Err(CompileError::ExpectedLValue) => eprintln!("not an l-value"), Err(e) => eprintln!("{}", e), Ok(_) => {} } ``` -------------------------------- ### Implementing AssembleEnv for BYOND String Pool Source: https://context7.com/willox/dmasm/llms.txt Provides an example implementation of the `AssembleEnv` trait for a `DmbEnv` struct, which wraps a BYOND .dmb string pool. This allows bridging DMASM strings to integer indices. Requires `dmasm::assembler` import. ```rust use dmasm::assembler::{AssembleEnv, AssembleError}; /// Example: wraps a BYOND .dmb string pool struct DmbEnv { string_pool: Vec, var_names: Vec, proc_paths: Vec, } impl AssembleEnv for DmbEnv { fn get_string_index(&mut self, data: &[u8]) -> Option { let s = String::from_utf8_lossy(data).into_owned(); if let Some(i) = self.string_pool.iter().position(|x| x == &s) { return Some(i as u32); } self.string_pool.push(s); Some(self.string_pool.len() as u32 - 1) } fn get_variable_name_index(&mut self, name: &[u8]) -> Option { let n = String::from_utf8_lossy(name).into_owned(); self.var_names.iter().position(|x| x == &n).map(|i| i as u32) } fn get_proc_index(&mut self, path: &str) -> Option { self.proc_paths.iter().position(|x| x == path).map(|i| i as u32) } fn get_type(&mut self, _path: &str) -> Option<(u8, u32)> { // Return (type_tag, type_data) from the .dmb type table None // not supported in this example } } ``` -------------------------------- ### Implementing DisassembleEnv for BYOND Index Resolution Source: https://context7.com/willox/dmasm/llms.txt Shows an example implementation of the `DisassembleEnv` trait for a `DmbDisEnv` struct, which mirrors `AssembleEnv`. This allows converting numeric indices in bytecode back into human-readable strings. Requires `dmasm::disassembler` import. ```rust use dmasm::disassembler::{DisassembleEnv}; struct DmbDisEnv { string_pool: Vec>, var_names: Vec>, proc_paths: Vec, type_table: std::collections::HashMap<(u32, u32), Vec>, } impl DisassembleEnv for DmbDisEnv { fn get_string_data(&mut self, index: u32) -> Option> { self.string_pool.get(index as usize).cloned() } fn get_variable_name(&mut self, index: u32) -> Option> { self.var_names.get(index as usize).cloned() } fn get_proc_name(&mut self, index: u32) -> Option { self.proc_paths.get(index as usize).cloned() } fn value_to_string_data(&mut self, tag: u32, data: u32) -> Option> { // Resolve type-path values (mobs, objs, datums, etc.) self.type_table.get(&(tag, data)).cloned() } } ``` -------------------------------- ### Build and Format DMASM Nodes in Rust Source: https://context7.com/willox/dmasm/llms.txt Demonstrates how to manually construct `Node` elements, which represent comments, labels, or instructions in DMASM. It also shows how to render these nodes into human-readable DMASM text using the `format` helper. ```rust use dmasm::{Node, Instruction, assembler, disassembler, format, format_disassembly}; use dmasm::disassembler::DebugData; // Build nodes by hand let nodes: Vec = vec![ Node::Comment(" simple addition".into()), Node::Instruction(Instruction::PushInt(10), ()), Node::Instruction(Instruction::PushInt(32), ()), Node::Instruction(Instruction::Add, ()), Node::Instruction(Instruction::Ret, ()), ]; // Render to DMASM text let text = format(&nodes); assert!(text.contains("PushInt 10")); assert!(text.contains("Add")); // Strip debug data (no-op for () data) let stripped: Vec = nodes.into_iter().map(|n| n.strip_debug_data()).collect(); ``` -------------------------------- ### Assemble Nodes to Bytecode Source: https://context7.com/willox/dmasm/llms.txt Converts a slice of `Node`s into a `Vec` bytecode stream. Requires an `AssembleEnv` implementation to map string literals, variable names, and proc paths to their runtime indices. Label forward-references are resolved in a second pass. ```rust use dmasm::{Node, Instruction}; use dmasm::operands::{Label, Variable, DMString}; use dmasm::assembler::{assemble, AssembleEnv, AssembleError}; struct RuntimeEnv { strings: std::collections::HashMap, u32>, } impl AssembleEnv for RuntimeEnv { fn get_string_index(&mut self, data: &[u8]) -> Option { Some(*self.strings.entry(data.to_vec()).or_insert_with(|| self.strings.len() as u32)) } fn get_variable_name_index(&mut self, name: &[u8]) -> Option { Some(0) } fn get_proc_index(&mut self, _path: &str) -> Option { None } // no procs needed here fn get_type(&mut self, _path: &str) -> Option<(u8, u32)> { None } } let nodes: Vec = vec![ Node::Label("Loop".into()), Node::Instruction(Instruction::GetVar(Variable::Local(0)), ()), Node::Instruction(Instruction::PushInt(0), ()), Node::Instruction(Instruction::Tg, ()), Node::Instruction(Instruction::JzLoop(Label("Exit".into())), ()), Node::Instruction(Instruction::PreDec(Variable::Local(0)), ()), Node::Instruction(Instruction::JmpLoop(Label("Loop".into())), ()), Node::Label("Exit".into()), Node::Instruction(Instruction::End, ()), ]; let mut env = RuntimeEnv { strings: Default::default() }; match assemble(&nodes, &mut env) { Ok(bytecode) => println!("{} u32 words emitted", bytecode.len()), Err(AssembleError::ProcNotFound(p)) => eprintln!("proc not found: {}", p), Err(AssembleError::TypeNotFound(t)) => eprintln!("type not found: {}", t), Err(e) => eprintln!("error: {:?}", e), } ``` -------------------------------- ### `Instruction` Enum — Full Opcode Table Source: https://context7.com/willox/dmasm/llms.txt Provides a reference for all available DM opcodes within the `Instruction` enum, detailing their variants and usage. ```APIDOC ## `Instruction` Enum — Full Opcode Table The `Instruction` enum has one variant per DM opcode (`0x00`–`0x18C` plus `0x1337`/`0x1338` for auxtools). Each variant implements `assemble`, `disassemble`, and `serialize` automatically via the `instructions!` macro, as well as `Display` (which calls `serialize`). ```rust use dmasm::Instruction; use dmasm::operands::{Label, Variable, Value, DMString, Proc}; // Stack / arithmetic let push = Instruction::PushInt(42); let add = Instruction::Add; let ret = Instruction::Ret; let end = Instruction::End; // Control flow let jmp = Instruction::Jmp(Label("MyLabel".into())); let jz = Instruction::Jz(Label("MyLabel".into())); let jnz = Instruction::JnzLoop(Label("MyLabel".into())); // loop-safe variant // Variable access let get = Instruction::GetVar(Variable::Src); let set = Instruction::SetVar(Variable::Local(0)); let aug = Instruction::AugAdd(Variable::Local(1)); // Call instructions let call = Instruction::CallGlob(2, Proc("/proc/my_proc".into())); let call_dyn = Instruction::CallName(3); // dynamic proc call by name // Push a hardcoded DM value let push_null = Instruction::PushVal(Value::Null); let push_num = Instruction::PushVal(Value::Number(3.14)); let push_str = Instruction::PushVal(Value::DMString(DMString(b"hello".to_vec()))); let push_path = Instruction::PushVal(Value::Path("/mob/player".into())); // Debug info let dbg_file = Instruction::DbgFile(DMString(b"main.dm".to_vec())); let dbg_line = Instruction::DbgLine(42); // Display (serialize) any instruction println!("{}", push); // PushInt 42 println!("{}", call); // CallGlob 2 /proc/my_proc println!("{}", push_str); // PushVal "hello" ``` ``` -------------------------------- ### Display DMASM Instructions Source: https://context7.com/willox/dmasm/llms.txt Demonstrates the creation and display (serialization) of various `Instruction` enum variants. Each variant represents a DM opcode. ```rust use dmasm::Instruction; use dmasm::operands::{Label, Variable, Value, DMString, Proc}; // Stack / arithmetic let push = Instruction::PushInt(42); let add = Instruction::Add; let ret = Instruction::Ret; let end = Instruction::End; // Control flow let jmp = Instruction::Jmp(Label("MyLabel".into())); let jz = Instruction::Jz(Label("MyLabel".into())); let jnz = Instruction::JnzLoop(Label("MyLabel".into())); // loop-safe variant // Variable access let get = Instruction::GetVar(Variable::Src); let set = Instruction::SetVar(Variable::Local(0)); let aug = Instruction::AugAdd(Variable::Local(1)); // Call instructions let call = Instruction::CallGlob(2, Proc("/proc/my_proc".into())); let call_dyn = Instruction::CallName(3); // dynamic proc call by name // Push a hardcoded DM value let push_null = Instruction::PushVal(Value::Null); let push_num = Instruction::PushVal(Value::Number(3.14)); let push_str = Instruction::PushVal(Value::DMString(DMString(b"hello".to_vec()))); let push_path = Instruction::PushVal(Value::Path("/mob/player".into())); // Debug info let dbg_file = Instruction::DbgFile(DMString(b"main.dm".to_vec())); let dbg_line = Instruction::DbgLine(42); // Display (serialize) any instruction println!("{}", push); // PushInt 42 println!("{}", call); // CallGlob 2 /proc/my_proc println!("{}", push_str); // PushVal "hello" ``` -------------------------------- ### Parse DMASM Text and Assemble Bytecode in Rust Source: https://context7.com/willox/dmasm/llms.txt Shows how to parse DMASM source text into a `Vec` using `dmasm::parser::parse` and then assemble these nodes into raw bytecode using `dmasm::assembler::assemble`. Requires a custom implementation of `AssembleEnv` to resolve identifiers. ```rust use dmasm::assembler::{self, AssembleEnv, AssembleError}; // Minimal AssembleEnv implementation for testing struct MyEnv; impl AssembleEnv for MyEnv { fn get_string_index(&mut self, _data: &[u8]) -> Option { Some(42) } fn get_variable_name_index(&mut self, _name: &[u8]) -> Option { Some(43) } fn get_proc_index(&mut self, _path: &str) -> Option { Some(44) } fn get_type(&mut self, _path: &str) -> Option<(u8, u32)> { Some((0x09, 0x01)) } } // parse is re-exported through the crate but lives in parser let source = r#" ; Set up debug info DbgFile "main.dm" DbgLine 5 ; Conditional jump example PushInt 1 Jz Done PushInt 99 Ret Done: PushInt 0 Ret "#; // Parse text -> nodes let nodes = dmasm::parser::parse(source).expect("parse failed"); // Assemble nodes -> bytecode let mut env = MyEnv; let bytecode: Vec = assembler::assemble(&nodes, &mut env).expect("assemble failed"); println!("bytecode words: {}", bytecode.len()); ``` -------------------------------- ### Compile DM Expression to Nodes and Assemble Source: https://context7.com/willox/dmasm/llms.txt Compile a DM source expression string into a `Vec>` using `compile_expr`. The output nodes are ready for assembly. Requires implementing `AssembleEnv`. ```rust use dmasm::compiler::{compile_expr, CompileError}; use dmasm::assembler::{assemble, AssembleEnv}; use dmasm::format; struct TestEnv; impl AssembleEnv for TestEnv { fn get_string_index(&mut self, _: &[u8]) -> Option { Some(1) } fn get_variable_name_index(&mut self, _: &[u8]) -> Option { Some(2) } fn get_proc_index(&mut self, _: &str) -> Option { Some(3) } fn get_type(&mut self, _: &str) -> Option<(u8, u32)> { Some((0x09, 1)) } } // Compile "a * 2 + b" with two parameters a and b match compile_expr("a * 2 + b", &["a", "b"]) { Ok(nodes) => { println!("---" --- DMASM ---\n{}", format(&nodes)); let bytecode = assemble(&nodes, &mut TestEnv).unwrap(); println!("bytecode: {:x?}", bytecode); } Err(CompileError::ParseError(e)) => eprintln!("DM parse error: {}", e), Err(CompileError::UnsupportedBuiltin { proc }) => eprintln!("unsupported: {}", proc), Err(e) => eprintln!("compile error: {}", e), } // Null-safe field access let nodes = compile_expr("a?.b++", &["a"]).unwrap(); println!("{}", format(&nodes)); ``` -------------------------------- ### Format DMASM Nodes to Plain Text Source: https://context7.com/willox/dmasm/llms.txt Use the `format` function to render a slice of `Node` as plain DMASM text. This includes comments, labels, and instructions with their operands. ```rust use dmasm::{Node, Instruction, format}; use dmasm::operands::{Label, Variable}; let nodes: Vec = vec![ Node::Comment(" countdown".into()), Node::Label("Loop".into()), Node::Instruction(Instruction::PostDec(Variable::Local(0)), (), Node::Instruction(Instruction::GetVar(Variable::Local(0)), ()), Node::Instruction(Instruction::JnzLoop(Label("Loop".into())), ()), Node::Instruction(Instruction::End, ()), ]; let text = format(&nodes); println!("{}", text); ``` -------------------------------- ### `format` — Plain Node Formatter Source: https://context7.com/willox/dmasm/llms.txt Renders a slice of `Node` as plain DMASM text, preserving comments, labels, and instructions with their operands. ```APIDOC ## `format` — Plain Node Formatter Renders any `&[Node]` (regardless of debug data type) as plain DMASM text, reproducing comments, label definitions, and instructions with their operands. ```rust use dmasm::{Node, Instruction, format}; use dmasm::operands::{Label, Variable}; let nodes: Vec = vec![ Node::Comment(" countdown".into()), Node::Label("Loop".into()), Node::Instruction(Instruction::PostDec(Variable::Local(0)), (..)), Node::Instruction(Instruction::GetVar(Variable::Local(0)), (..)), Node::Instruction(Instruction::JnzLoop(Label("Loop".into())), (..)), Node::Instruction(Instruction::End, (..)), ]; let text = format(&nodes); println!("{}", text); // ; countdown // Loop: // PostDec local(0) // GetVar local(0) // JnzLoop LAB_0000 <- (label name set at construction time) // End ``` ``` -------------------------------- ### Format Disassembly Output Source: https://context7.com/willox/dmasm/llms.txt Renders a slice of `Node` into a multi-column string for debugger-style output. Includes a cursor marker, word offset, raw bytecode, and mnemonic with operands. Can optionally display a cursor at a specific word offset. ```rust use dmasm::{Node, Instruction, format_disassembly}; use dmasm::disassembler::{disassemble, DebugData}; // (reusing MyDisEnv from above) let bytecode: Vec = vec![ 0x84, 42, // DbgFile "string_42" 0x85, 7, // DbgLine 7 0x50, 100, // PushInt 100 0x12, // Ret ]; let mut env = MyDisEnv; let (nodes, _) = disassemble(&bytecode, &mut env); // No cursor let text = format_disassembly(&nodes, None); println!("{}", text); // With cursor pointing at word offset 4 (the PushInt instruction) let text_cursor = format_disassembly(&nodes, Some(4)); println!("{}", text_cursor); // Outputs: // 0000: 00000084 0000002A DbgFile "string_42" // 0002: 00000085 00000007 DbgLine 7 // >0004: 00000050 00000064 PushInt 100 // 0006: 00000012 Ret ``` -------------------------------- ### Disassemble Bytecode to Nodes Source: https://context7.com/willox/dmasm/llms.txt Converts a bytecode slice into `Node`s, optionally returning a `DisassembleError`. Labels are automatically inserted before jump targets. `DebugData` is included for each instruction, providing word offset and original bytecode. ```rust use dmasm::{Node, format_disassembly}; use dmasm::disassembler::{disassemble, DisassembleEnv, DisassembleError, DebugData}; struct MyDisEnv; impl DisassembleEnv for MyDisEnv { fn get_string_data(&mut self, index: u32) -> Option> { Some(format!("string_{}", index).into_bytes()) } fn get_variable_name(&mut self, index: u32) -> Option> { Some(format!("var_{}", index).into_bytes()) } fn get_proc_name(&mut self, index: u32) -> Option { Some(format!("/proc/func{}", index)) } fn value_to_string_data(&mut self, tag: u32, data: u32) -> Option> { Some(format!("/datum/tag{}data{}", tag, data).into_bytes()) } } // Bytecode for: PushInt 5; Ret; End (opcodes 0x50 0x05 0x12 0x00) let bytecode: Vec = vec![0x50, 5, 0x12, 0x00]; let mut env = MyDisEnv; let (nodes, err) = disassemble(&bytecode, &mut env); if let Some(e) = err { eprintln!("disassembly stopped early: {:?}", e); } // Print with offsets and hex (cursor at offset 2 shows '>' marker) println!("{}", format_disassembly(&nodes, Some(2))); // Expected output: // 0000: 00000050 00000005 PushInt 5 // >0002: 00000012 Ret // 0003: 00000000 End ``` -------------------------------- ### `compiler::compile_expr` — DM Expression to Nodes Source: https://context7.com/willox/dmasm/llms.txt Compiles a DM source expression string into a `Vec>`. The output nodes prepare the stack for assembly. ```APIDOC ## `compiler::compile_expr` — DM Expression to Nodes Compiles a DM source expression string directly into a `Vec>`. Parameters are named positionally; the output nodes push the result and parameter values onto the stack then emit `NewList` + `Ret`, ready for assembly. Uses the `dreammaker` crate for parsing. ```rust use dmasm::compiler::{compile_expr, CompileError}; use dmasm::assembler::{assemble, AssembleEnv}; use dmasm::format; struct TestEnv; impl AssembleEnv for TestEnv { fn get_string_index(&mut self, _: &[u8]) -> Option { Some(1) } fn get_variable_name_index(&mut self, _: &[u8]) -> Option { Some(2) } fn get_proc_index(&mut self, _: &str) -> Option { Some(3) } fn get_type(&mut self, _: &str) -> Option<(u8, u32)> { Some((0x09, 1)) } } // Compile "a * 2 + b" with two parameters a and b match compile_expr("a * 2 + b", &["a", "b"]) { Ok(nodes) => { println!("--- DMASM --- {}", format(&nodes)); let bytecode = assemble(&nodes, &mut TestEnv).unwrap(); println!("bytecode: {:x?}", bytecode); } Err(CompileError::ParseError(e)) => eprintln!("DM parse error: {}", e), Err(CompileError::UnsupportedBuiltin { proc }) => eprintln!("unsupported: {}", proc), Err(e) => eprintln!("compile error: {}", e), } // Null-safe field access let nodes = compile_expr("a?.b++", &["a"]).unwrap(); println!("{}", format(&nodes)); ``` ``` -------------------------------- ### Variable Operand Encoding in DMASM Source: https://context7.com/willox/dmasm/llms.txt Demonstrates various ways to use the `Variable` enum to encode DM access modifiers, including simple variables, chained fields, and nested variants. Ensure `dmasm::operands` is imported. ```rust use dmasm::operands::{Variable, DMString, Proc}; let v_src = Variable::Src; let v_usr = Variable::Usr; let v_dot = Variable::Dot; let v_arg0 = Variable::Arg(0); let v_local2 = Variable::Local(2); let v_global = Variable::Global(DMString(b"my_global".to_vec())); let v_field = Variable::Field(DMString(b"x".to_vec())); // Chained field: set cache to src, then access field "name" let v_chain = Variable::SetCache( Box::new(Variable::Src), Box::new(Variable::Field(DMString(b"name".to_vec()))), ); // initial(src.health) let v_initial = Variable::Initial(Box::new(Variable::SetCache( Box::new(Variable::Src), Box::new(Variable::Field(DMString(b"health".to_vec()))), ))); // Static proc reference let v_sproc = Variable::StaticProc(Proc("/datum/proc/on_hit".into())); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.