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:
@@ -101,7 +101,7 @@ tests/ Forth 2012 compliance suite (gerryjackson/forth2012-test-suite sub
|
|||||||
### Core (Forth 2012 Section 6.1) -- In Progress
|
### Core (Forth 2012 Section 6.1) -- In Progress
|
||||||
|
|
||||||
| Category | Words |
|
| Category | Words |
|
||||||
| ------------ | ---------------------------------------------------------------------------------------------------- |
|
| ------------ | --------------------------------------------------------------------------------------------------------------- |
|
||||||
| Stack | `DUP DROP SWAP OVER ROT NIP TUCK 2DUP 2DROP 2SWAP 2OVER ?DUP PICK DEPTH` |
|
| Stack | `DUP DROP SWAP OVER ROT NIP TUCK 2DUP 2DROP 2SWAP 2OVER ?DUP PICK DEPTH` |
|
||||||
| Arithmetic | `+ - * / MOD /MOD NEGATE ABS MIN MAX 1+ 1- 2* 2/ */ */MOD M* UM* UM/MOD FM/MOD SM/REM S>D <# # #S #> HOLD SIGN` |
|
| Arithmetic | `+ - * / MOD /MOD NEGATE ABS MIN MAX 1+ 1- 2* 2/ */ */MOD M* UM* UM/MOD FM/MOD SM/REM S>D <# # #S #> HOLD SIGN` |
|
||||||
| Comparison | `= <> < > U< 0= 0< 0<> 0> WITHIN` |
|
| Comparison | `= <> < > U< 0= 0< 0<> 0> WITHIN` |
|
||||||
@@ -124,7 +124,7 @@ All Core and Core Extension words implemented. Exception word set (CATCH/THROW)
|
|||||||
Targeting 100% Forth 2012 compliance via [Gerry Jackson's test suite](https://github.com/gerryjackson/forth2012-test-suite).
|
Targeting 100% Forth 2012 compliance via [Gerry Jackson's test suite](https://github.com/gerryjackson/forth2012-test-suite).
|
||||||
|
|
||||||
| Word Set | Status |
|
| Word Set | Status |
|
||||||
| ------------------ | ------------------ |
|
| ------------------ | --------------------------------- |
|
||||||
| Core | **100%** (0 errors on test suite) |
|
| Core | **100%** (0 errors on test suite) |
|
||||||
| Core Extensions | **100%** (0 errors on test suite) |
|
| Core Extensions | **100%** (0 errors on test suite) |
|
||||||
| Double-Number | Pending |
|
| Double-Number | Pending |
|
||||||
|
|||||||
@@ -41,14 +41,14 @@ const TYPE_I32: u32 = 1; // (i32) -> ()
|
|||||||
const EMIT_FUNC: u32 = 0;
|
const EMIT_FUNC: u32 = 0;
|
||||||
const WORD_FUNC: u32 = 1;
|
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 {
|
const MEM4: MemArg = MemArg {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
align: 2, // 2^2 = 4
|
align: 2, // 2^2 = 4
|
||||||
memory_index: MEMORY_INDEX,
|
memory_index: MEMORY_INDEX,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// MemArg for single-byte operations.
|
/// `MemArg` for single-byte operations.
|
||||||
const MEM1: MemArg = MemArg {
|
const MEM1: MemArg = MemArg {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
align: 0, // 2^0 = 1
|
align: 0, // 2^0 = 1
|
||||||
@@ -81,7 +81,7 @@ pub struct CompiledModule {
|
|||||||
// Instruction-level helpers (free functions that take &mut Function)
|
// 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) {
|
fn dsp_dec(f: &mut Function) {
|
||||||
f.instruction(&Instruction::GlobalGet(DSP))
|
f.instruction(&Instruction::GlobalGet(DSP))
|
||||||
.instruction(&Instruction::I32Const(CELL_SIZE as i32))
|
.instruction(&Instruction::I32Const(CELL_SIZE as i32))
|
||||||
@@ -89,7 +89,7 @@ fn dsp_dec(f: &mut Function) {
|
|||||||
.instruction(&Instruction::GlobalSet(DSP));
|
.instruction(&Instruction::GlobalSet(DSP));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increment `$dsp` by CELL_SIZE.
|
/// Increment `$dsp` by `CELL_SIZE`.
|
||||||
fn dsp_inc(f: &mut Function) {
|
fn dsp_inc(f: &mut Function) {
|
||||||
f.instruction(&Instruction::GlobalGet(DSP))
|
f.instruction(&Instruction::GlobalGet(DSP))
|
||||||
.instruction(&Instruction::I32Const(CELL_SIZE as i32))
|
.instruction(&Instruction::I32Const(CELL_SIZE as i32))
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
//! - Flags + name length (1 byte)
|
//! - Flags + name length (1 byte)
|
||||||
//! - Name string (N bytes, padded to cell alignment)
|
//! - Name string (N bytes, padded to cell alignment)
|
||||||
//! - Code field: function table index (4 bytes)
|
//! - 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::error::{WaferError, WaferResult};
|
||||||
use crate::memory::{DICTIONARY_BASE, INITIAL_PAGES, PAGE_SIZE};
|
use crate::memory::{DICTIONARY_BASE, INITIAL_PAGES, PAGE_SIZE};
|
||||||
@@ -57,7 +57,7 @@ impl Dictionary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new dictionary entry (like Forth's CREATE).
|
/// 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).
|
/// The word starts HIDDEN (will be revealed when compilation completes).
|
||||||
pub fn create(&mut self, name: &str, immediate: bool) -> WaferResult<WordId> {
|
pub fn create(&mut self, name: &str, immediate: bool) -> WaferResult<WordId> {
|
||||||
let name_upper = name.to_ascii_uppercase();
|
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.
|
/// Searches from LATEST backward through the linked list.
|
||||||
/// Skips HIDDEN words.
|
/// Skips HIDDEN words.
|
||||||
pub fn find(&self, name: &str) -> Option<(u32, WordId, bool)> {
|
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.
|
/// 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) {
|
fn write_u32_unchecked(&mut self, addr: u32, value: u32) {
|
||||||
let a = addr as usize;
|
let a = addr as usize;
|
||||||
let bytes = value.to_le_bytes();
|
let bytes = value.to_le_bytes();
|
||||||
@@ -355,7 +355,7 @@ impl Dictionary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read a u32 in little-endian without bounds checking.
|
/// 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 {
|
fn read_u32_unchecked(&self, addr: u32) -> u32 {
|
||||||
let a = addr as usize;
|
let a = addr as usize;
|
||||||
u32::from_le_bytes([
|
u32::from_le_bytes([
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ pub enum IrOp {
|
|||||||
test: Vec<IrOp>,
|
test: Vec<IrOp>,
|
||||||
body: 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,
|
/// 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
|
/// control goes to `else_body`. When the second WHILE fails, control goes
|
||||||
|
|||||||
+1522
-111
File diff suppressed because it is too large
Load Diff
@@ -25,8 +25,22 @@ allow = [
|
|||||||
confidence-threshold = 0.8
|
confidence-threshold = 0.8
|
||||||
|
|
||||||
[bans]
|
[bans]
|
||||||
multiple-versions = "warn"
|
multiple-versions = "deny"
|
||||||
wildcards = "deny"
|
wildcards = "deny"
|
||||||
|
# Transitive duplicates from wasmtime v31 -- will resolve when upgrading
|
||||||
|
skip = [
|
||||||
|
"getrandom",
|
||||||
|
"hashbrown",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"object",
|
||||||
|
"rustix",
|
||||||
|
"thiserror",
|
||||||
|
"thiserror-impl",
|
||||||
|
"wasm-encoder",
|
||||||
|
"wasmparser",
|
||||||
|
"wast",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[sources]
|
[sources]
|
||||||
unknown-registry = "deny"
|
unknown-registry = "deny"
|
||||||
|
|||||||
Reference in New Issue
Block a user