Add constant values.
This commit is contained in:
parent
e85fb16707
commit
243eb426c8
6 changed files with 217 additions and 34 deletions
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
155
huia-compiler/src/constant.rs
Normal file
155
huia-compiler/src/constant.rs
Normal 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");
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ extern crate string_interner;
|
|||
extern crate wrc;
|
||||
|
||||
mod class;
|
||||
mod constant;
|
||||
mod context;
|
||||
mod identifier;
|
||||
mod r#trait;
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
Reference in a new issue