Implement Double-Number and String word sets, fix memory panics

Double-Number (19 words): D+ D- DNEGATE DABS D2* D2/ D0= D0< D= D< DU<
  DMAX DMIN D>S M+ M*/ D. D.R 2ROT 2CONSTANT 2VARIABLE 2VALUE 2LITERAL
  Double-number literal parsing (tokens ending with '.')
String (5 words): COMPARE SEARCH /STRING BLANK -TRAILING SLITERAL
Fix all memory access panics with bounds checking throughout host functions.

8 word sets at 100%: Core, Core Ext, Exception, Double, String,
  Search-Order, Memory-Allocation, Programming-Tools
This commit is contained in:
2026-03-31 14:43:30 +02:00
parent 193ad7ec5a
commit dd389c6a3d
7 changed files with 1590 additions and 165 deletions
+4 -4
View File
@@ -41,14 +41,14 @@ const TYPE_I32: u32 = 1; // (i32) -> ()
const EMIT_FUNC: u32 = 0;
const WORD_FUNC: u32 = 1;
/// Natural-alignment MemArg for 4-byte i32 operations.
/// Natural-alignment `MemArg` for 4-byte i32 operations.
const MEM4: MemArg = MemArg {
offset: 0,
align: 2, // 2^2 = 4
memory_index: MEMORY_INDEX,
};
/// MemArg for single-byte operations.
/// `MemArg` for single-byte operations.
const MEM1: MemArg = MemArg {
offset: 0,
align: 0, // 2^0 = 1
@@ -81,7 +81,7 @@ pub struct CompiledModule {
// Instruction-level helpers (free functions that take &mut Function)
// ---------------------------------------------------------------------------
/// Decrement `$dsp` by CELL_SIZE.
/// Decrement `$dsp` by `CELL_SIZE`.
fn dsp_dec(f: &mut Function) {
f.instruction(&Instruction::GlobalGet(DSP))
.instruction(&Instruction::I32Const(CELL_SIZE as i32))
@@ -89,7 +89,7 @@ fn dsp_dec(f: &mut Function) {
.instruction(&Instruction::GlobalSet(DSP));
}
/// Increment `$dsp` by CELL_SIZE.
/// Increment `$dsp` by `CELL_SIZE`.
fn dsp_inc(f: &mut Function) {
f.instruction(&Instruction::GlobalGet(DSP))
.instruction(&Instruction::I32Const(CELL_SIZE as i32))
+5 -5
View File
@@ -5,7 +5,7 @@
//! - Flags + name length (1 byte)
//! - Name string (N bytes, padded to cell alignment)
//! - Code field: function table index (4 bytes)
//! - Parameter field: data for CREATEd words, DOES> action, etc.
//! - Parameter field: data for `CREATEd` words, DOES> action, etc.
use crate::error::{WaferError, WaferResult};
use crate::memory::{DICTIONARY_BASE, INITIAL_PAGES, PAGE_SIZE};
@@ -57,7 +57,7 @@ impl Dictionary {
}
/// Create a new dictionary entry (like Forth's CREATE).
/// Returns the WordId (function table index) assigned to this word.
/// Returns the `WordId` (function table index) assigned to this word.
/// The word starts HIDDEN (will be revealed when compilation completes).
pub fn create(&mut self, name: &str, immediate: bool) -> WaferResult<WordId> {
let name_upper = name.to_ascii_uppercase();
@@ -139,7 +139,7 @@ impl Dictionary {
}
}
/// Look up a word by name. Returns (word_address, word_id, is_immediate).
/// Look up a word by name. Returns (`word_address`, `word_id`, `is_immediate`).
/// Searches from LATEST backward through the linked list.
/// Skips HIDDEN words.
pub fn find(&self, name: &str) -> Option<(u32, WordId, bool)> {
@@ -347,7 +347,7 @@ impl Dictionary {
}
/// Write a u32 in little-endian without bounds checking.
/// Caller must ensure addr + 4 <= memory.len().
/// Caller must ensure addr + 4 <= `memory.len()`.
fn write_u32_unchecked(&mut self, addr: u32, value: u32) {
let a = addr as usize;
let bytes = value.to_le_bytes();
@@ -355,7 +355,7 @@ impl Dictionary {
}
/// Read a u32 in little-endian without bounds checking.
/// Caller must ensure addr + 4 <= memory.len().
/// Caller must ensure addr + 4 <= `memory.len()`.
fn read_u32_unchecked(&self, addr: u32) -> u32 {
let a = addr as usize;
u32::from_le_bytes([
+1 -1
View File
@@ -93,7 +93,7 @@ pub enum IrOp {
test: Vec<IrOp>,
body: Vec<IrOp>,
},
/// BEGIN test1 WHILE test2 WHILE body REPEAT after_repeat ELSE else_body THEN
/// BEGIN test1 WHILE test2 WHILE body REPEAT `after_repeat` ELSE `else_body` THEN
///
/// Two nested WHILEs in a single BEGIN loop. When the first WHILE fails,
/// control goes to `else_body`. When the second WHILE fails, control goes
+1536 -125
View File
File diff suppressed because it is too large Load Diff