introduce tags, structs, and reticles
this was meant to be split into smaller changes, but I realised I edited my existing revision too late.
This commit is contained in:
parent
8356b6c750
commit
5b7d9586ea
26 changed files with 1113 additions and 351 deletions
|
@ -12,6 +12,7 @@ pub enum Opcode {
|
|||
Nil,
|
||||
False,
|
||||
True,
|
||||
Tag,
|
||||
Number, // (float: f32)
|
||||
Rgba, // (r: u8, g: u8, b: u8, a: u8)
|
||||
|
||||
|
@ -36,6 +37,7 @@ pub enum Opcode {
|
|||
// Control flow.
|
||||
Jump, // (offset: u16)
|
||||
JumpIfNot, // (offset: u16)
|
||||
Field, // (count: u8, tags: [u16; count])
|
||||
|
||||
// Function calls.
|
||||
Call, // (argc: u8)
|
||||
|
@ -157,6 +159,12 @@ impl Chunk {
|
|||
}
|
||||
}
|
||||
|
||||
impl Offset {
|
||||
pub fn to_u16(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ChunkSizeError;
|
||||
|
||||
|
@ -193,21 +201,48 @@ impl DefId {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||
pub struct TagId(u16);
|
||||
|
||||
impl TagId {
|
||||
pub(crate) fn from_u16(x: u16) -> Self {
|
||||
Self(x)
|
||||
}
|
||||
|
||||
pub fn to_u16(self) -> u16 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Defs {
|
||||
defs: Vec<String>,
|
||||
tags: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct DefsLimits {
|
||||
pub max_defs: usize,
|
||||
pub max_tags: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct DefsImage {
|
||||
defs: usize,
|
||||
tags: usize,
|
||||
}
|
||||
|
||||
impl Defs {
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
assert!(capacity < u16::MAX as usize + 1);
|
||||
pub fn new(limits: &DefsLimits) -> Self {
|
||||
assert!(limits.max_defs < u16::MAX as usize + 1);
|
||||
assert!(limits.max_tags < u16::MAX as usize + 1);
|
||||
|
||||
let mut tags = Vec::with_capacity(limits.max_tags);
|
||||
add_well_known_tags(&mut tags);
|
||||
|
||||
Self {
|
||||
defs: Vec::with_capacity(capacity),
|
||||
defs: Vec::with_capacity(limits.max_defs),
|
||||
tags,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,14 +254,14 @@ impl Defs {
|
|||
self.len() != 0
|
||||
}
|
||||
|
||||
pub fn get(&mut self, name: &str) -> Option<DefId> {
|
||||
pub fn get_def(&mut self, name: &str) -> Option<DefId> {
|
||||
self.defs
|
||||
.iter()
|
||||
.position(|n| *n == name)
|
||||
.map(|index| DefId(index as u16))
|
||||
}
|
||||
|
||||
pub fn add(&mut self, name: &str) -> Result<DefId, DefError> {
|
||||
pub fn add_def(&mut self, name: &str) -> Result<DefId, DefError> {
|
||||
if self.defs.iter().any(|n| n == name) {
|
||||
Err(DefError::Exists)
|
||||
} else {
|
||||
|
@ -239,9 +274,27 @@ impl Defs {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_tag(tags: &mut Vec<String>, name: &str) -> Result<TagId, TagError> {
|
||||
if tags.len() >= tags.capacity() {
|
||||
return Err(TagError::OutOfSpace);
|
||||
}
|
||||
let id = TagId(tags.len() as u16);
|
||||
tags.push(name.to_owned());
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn get_or_add_tag(&mut self, name: &str) -> Result<TagId, TagError> {
|
||||
if let Some(index) = self.tags.iter().position(|n| n == name) {
|
||||
Ok(TagId(index as u16))
|
||||
} else {
|
||||
Self::add_tag(&mut self.tags, name)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image(&self) -> DefsImage {
|
||||
DefsImage {
|
||||
defs: self.defs.len(),
|
||||
tags: self.tags.len(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,6 +302,9 @@ impl Defs {
|
|||
self.defs.resize_with(image.defs, || {
|
||||
panic!("image must be a subset of the current defs")
|
||||
});
|
||||
self.tags.resize_with(image.tags, || {
|
||||
panic!("image must be a subset of the current defs")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,3 +322,45 @@ impl Display for DefError {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum TagError {
|
||||
OutOfSpace,
|
||||
}
|
||||
|
||||
impl Display for TagError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
TagError::OutOfSpace => "too many tags",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! well_known_tags {
|
||||
($($ident:tt = $value:tt),* $(,)?) => {
|
||||
impl TagId {
|
||||
$(
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $ident: Self = Self($value);
|
||||
)*
|
||||
}
|
||||
|
||||
fn add_well_known_tags(tags: &mut Vec<String>) {
|
||||
$(
|
||||
let id = Defs::add_tag(tags, stringify!($ident)).unwrap();
|
||||
assert_eq!(id, TagId::from_u16($value));
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
well_known_tags! {
|
||||
// NOTE: The numbers must be sorted from 0 to N, due to limitations of Rust's macro system.
|
||||
// https://github.com/rust-lang/rust/issues/83527
|
||||
|
||||
Nil = 0,
|
||||
|
||||
From = 1,
|
||||
To = 2,
|
||||
Num = 3,
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue