Add constant values.

This commit is contained in:
James Harton 2019-02-22 23:08:15 +13:00
parent e85fb16707
commit 243eb426c8
6 changed files with 217 additions and 34 deletions

View file

@ -44,6 +44,15 @@ impl Classes {
ClassId(elements.len())
}
pub fn find(&self, name: Identifier) -> Option<ClassId> {
let elements = self.0.read().unwrap();
let class = elements.iter().find(|class| class.name() == name);
match class {
Some(class) => Some(class.id()),
None => None,
}
}
pub fn is_empty(&self) -> bool {
let elements = self.0.read().unwrap();
elements.is_empty()
@ -127,8 +136,8 @@ mod test {
fn set_name() {
let mut context = Context::new();
let class = context.new_class("Marty McFly");
assert_eq!(class.name(), context.get_identifier("Marty McFly"));
class.set_name(context.get_identifier("Doc Brown"));
assert_eq!(class.name(), context.get_identifier("Doc Brown"));
assert_eq!(class.name(), context.identifiers().get("Marty McFly"));
class.set_name(context.identifiers().get("Doc Brown"));
assert_eq!(class.name(), context.identifiers().get("Doc Brown"));
}
}

View file

@ -0,0 +1,155 @@
use crate::class::ClassId;
use string_interner::{StringInterner, Sym};
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct ConstantId(usize);
impl From<ConstantId> for usize {
fn from(data: ConstantId) -> usize {
data.0
}
}
impl From<usize> for ConstantId {
fn from(data: usize) -> ConstantId {
ConstantId(data)
}
}
pub struct Constants {
values: Vec<Constant>,
strings: StringInterner<Sym>,
}
impl Constants {
pub fn new() -> Constants {
Constants {
values: Vec::new(),
strings: StringInterner::default(),
}
}
pub fn get(&self, id: ConstantId) -> Option<&Constant> {
match self.values.iter().nth(id.0) {
Some(constant) => Some(&constant),
None => None,
}
}
pub fn new_i64(&mut self, class_id: ClassId, i: i64) -> ConstantId {
let value = ConstantInner::I64(i);
let constant = Constant { class_id, value };
let id = self.values.len();
self.values.push(constant);
ConstantId(id)
}
pub fn get_i64(&self, id: ConstantId) -> Option<i64> {
let idx = id.0;
let constant = self.values[idx].clone();
match constant.value {
ConstantInner::I64(i) => Some(i),
_ => None,
}
}
pub fn new_f64(&mut self, class_id: ClassId, f: f64) -> ConstantId {
let value = ConstantInner::F64(f);
let constant = Constant { class_id, value };
let id = self.values.len();
self.values.push(constant);
ConstantId(id)
}
pub fn get_f64(&self, id: ConstantId) -> Option<f64> {
let idx = id.0;
let constant = self.values[idx].clone();
match constant.value {
ConstantInner::F64(f) => Some(f),
_ => None,
}
}
pub fn new_string(&mut self, class_id: ClassId, s: &str) -> ConstantId {
let sym = self.strings.get_or_intern(s);
let value = ConstantInner::String(sym);
let constant = Constant { class_id, value };
let id = self.values.len();
self.values.push(constant);
ConstantId(id)
}
pub fn get_string(&self, id: ConstantId) -> Option<&str> {
let idx = id.0;
let constant = self.values[idx].clone();
match constant.value {
ConstantInner::String(s) => self.strings.resolve(s),
_ => None,
}
}
pub fn is_empty(&self) -> bool {
self.values.is_empty() && self.strings.is_empty()
}
}
#[derive(Debug, PartialEq, PartialOrd, Clone)]
pub struct Constant {
class_id: ClassId,
value: ConstantInner,
}
impl Constant {
pub fn is_i64(&self) -> bool {
match self.value {
ConstantInner::I64(_) => true,
_ => false,
}
}
pub fn is_f64(&self) -> bool {
match self.value {
ConstantInner::F64(_) => true,
_ => false,
}
}
pub fn is_string(&self) -> bool {
match self.value {
ConstantInner::String(_) => true,
_ => false,
}
}
}
#[derive(Debug, PartialEq, PartialOrd, Clone)]
enum ConstantInner {
I64(i64),
F64(f64),
String(Sym),
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test() {
let mut constants = Constants::new();
assert!(constants.is_empty());
let class_id = ClassId::from(0);
let i = constants.new_i64(class_id, 123);
assert!(constants.get(i).unwrap().is_i64());
assert_eq!(constants.get_i64(i).unwrap(), 123);
let f = constants.new_f64(class_id, 1.21);
assert!(constants.get(f).unwrap().is_f64());
assert_eq!(constants.get_f64(f).unwrap(), 1.21);
let s = constants.new_string(class_id, "Marty McFly");
assert!(constants.get(s).unwrap().is_string());
assert_eq!(constants.get_string(s).unwrap(), "Marty McFly");
}
}

View file

@ -1,4 +1,5 @@
use crate::class::{Class, ClassId, Classes};
use crate::constant::Constants;
use crate::identifier::{Identifier, Identifiers};
use crate::r#trait::{Trait, TraitId, Traits};
@ -6,6 +7,7 @@ pub struct Context {
classes: Classes,
traits: Traits,
identifiers: Identifiers,
constants: Constants,
}
impl Context {
@ -14,6 +16,7 @@ impl Context {
classes: Classes::new(),
traits: Traits::new(),
identifiers: Identifiers::new(),
constants: Constants::new(),
}
}
@ -25,10 +28,6 @@ impl Context {
self.classes.get(id).unwrap()
}
pub fn get_class(&self, id: ClassId) -> Option<Class> {
self.classes.get(id)
}
pub fn new_trait(&mut self, name: &str) -> Trait {
let name = self.identifiers.get(name);
let id = self.traits.next_id();
@ -37,22 +36,26 @@ impl Context {
self.traits.get(id).unwrap()
}
pub fn get_trait(&self, id: TraitId) -> Option<Trait> {
self.traits.get(id)
}
pub fn get_identifier(&mut self, value: &str) -> Identifier {
self.identifiers.get(value)
}
pub fn get_identifier_value(&self, identifier: Identifier) -> Option<&str> {
self.identifiers.resolve(identifier)
}
pub fn is_empty(&self) -> bool {
// Traits and Classes must be empty if identifiers is empty because
// classes and traits must be initialised with identifier names.
self.identifiers.is_empty()
self.identifiers.is_empty() && self.constants.is_empty()
}
pub fn identifiers(&self) -> &Identifiers {
&self.identifiers
}
pub fn constants(&self) -> &Constants {
&self.constants
}
pub fn classes(&self) -> &Classes {
&self.classes
}
pub fn traits(&self) -> &Traits {
&self.traits
}
}
@ -64,14 +67,14 @@ mod test {
fn new() {
let mut context = Context::new();
let class0 = context.new_class("Marty McFly");
let class1 = context.get_class(class0.id()).unwrap();
let class1 = context.classes().get(class0.id()).unwrap();
assert_eq!(class0, class1);
let tr0 = context.new_trait("Doc Brown");
let tr1 = context.get_trait(tr0.id()).unwrap();
let tr1 = context.traits().get(tr0.id()).unwrap();
assert_eq!(tr0, tr1);
let id = context.get_identifier("Einstein Brown");
assert_eq!(context.get_identifier_value(id).unwrap(), "Einstein Brown");
let id = context.identifiers().get("Einstein Brown");
assert_eq!(context.identifiers().resolve(id).unwrap(), "Einstein Brown");
}
}

View file

@ -1,26 +1,32 @@
use std::sync::RwLock;
use string_interner::{StringInterner, Sym};
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Identifier(Sym);
pub struct Identifiers(StringInterner<Sym>);
pub struct Identifiers(RwLock<StringInterner<Sym>>);
impl Identifiers {
pub fn new() -> Identifiers {
Identifiers(StringInterner::default())
Identifiers(RwLock::new(StringInterner::default()))
}
pub fn get(&mut self, value: &str) -> Identifier {
let sym = self.0.get_or_intern(value);
pub fn get(&self, value: &str) -> Identifier {
let mut identifiers = self.0.write().unwrap();
let sym = identifiers.get_or_intern(value);
Identifier(sym)
}
pub fn resolve(&self, identifier: Identifier) -> Option<&str> {
self.0.resolve(identifier.0)
pub fn resolve(&self, identifier: Identifier) -> Option<String> {
let identifiers = self.0.read().unwrap();
match identifiers.resolve(identifier.0) {
Some(s) => Some(s.to_string()),
None => None,
}
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
self.0.read().unwrap().is_empty()
}
}

View file

@ -3,6 +3,7 @@ extern crate string_interner;
extern crate wrc;
mod class;
mod constant;
mod context;
mod identifier;
mod r#trait;

View file

@ -44,6 +44,15 @@ impl Traits {
TraitId(elements.len())
}
pub fn find(&self, name: Identifier) -> Option<TraitId> {
let elements = self.0.read().unwrap();
let tr = elements.iter().find(|tr| tr.name() == name);
match tr {
Some(tr) => Some(tr.id()),
None => None,
}
}
pub fn is_empty(&self) -> bool {
let elements = self.0.read().unwrap();
elements.is_empty()
@ -127,8 +136,8 @@ mod test {
fn set_name() {
let mut context = Context::new();
let tr = context.new_trait("Marty McFly");
assert_eq!(tr.name(), context.get_identifier("Marty McFly"));
tr.set_name(context.get_identifier("Doc Brown"));
assert_eq!(tr.name(), context.get_identifier("Doc Brown"));
assert_eq!(tr.name(), context.identifiers().get("Marty McFly"));
tr.set_name(context.identifiers().get("Doc Brown"));
assert_eq!(tr.name(), context.identifiers().get("Doc Brown"));
}
}