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())
|
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 {
|
pub fn is_empty(&self) -> bool {
|
||||||
let elements = self.0.read().unwrap();
|
let elements = self.0.read().unwrap();
|
||||||
elements.is_empty()
|
elements.is_empty()
|
||||||
|
@ -127,8 +136,8 @@ mod test {
|
||||||
fn set_name() {
|
fn set_name() {
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
let class = context.new_class("Marty McFly");
|
let class = context.new_class("Marty McFly");
|
||||||
assert_eq!(class.name(), context.get_identifier("Marty McFly"));
|
assert_eq!(class.name(), context.identifiers().get("Marty McFly"));
|
||||||
class.set_name(context.get_identifier("Doc Brown"));
|
class.set_name(context.identifiers().get("Doc Brown"));
|
||||||
assert_eq!(class.name(), context.get_identifier("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::class::{Class, ClassId, Classes};
|
||||||
|
use crate::constant::Constants;
|
||||||
use crate::identifier::{Identifier, Identifiers};
|
use crate::identifier::{Identifier, Identifiers};
|
||||||
use crate::r#trait::{Trait, TraitId, Traits};
|
use crate::r#trait::{Trait, TraitId, Traits};
|
||||||
|
|
||||||
|
@ -6,6 +7,7 @@ pub struct Context {
|
||||||
classes: Classes,
|
classes: Classes,
|
||||||
traits: Traits,
|
traits: Traits,
|
||||||
identifiers: Identifiers,
|
identifiers: Identifiers,
|
||||||
|
constants: Constants,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
|
@ -14,6 +16,7 @@ impl Context {
|
||||||
classes: Classes::new(),
|
classes: Classes::new(),
|
||||||
traits: Traits::new(),
|
traits: Traits::new(),
|
||||||
identifiers: Identifiers::new(),
|
identifiers: Identifiers::new(),
|
||||||
|
constants: Constants::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,10 +28,6 @@ impl Context {
|
||||||
self.classes.get(id).unwrap()
|
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 {
|
pub fn new_trait(&mut self, name: &str) -> Trait {
|
||||||
let name = self.identifiers.get(name);
|
let name = self.identifiers.get(name);
|
||||||
let id = self.traits.next_id();
|
let id = self.traits.next_id();
|
||||||
|
@ -37,22 +36,26 @@ impl Context {
|
||||||
self.traits.get(id).unwrap()
|
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 {
|
pub fn is_empty(&self) -> bool {
|
||||||
// Traits and Classes must be empty if identifiers is empty because
|
// Traits and Classes must be empty if identifiers is empty because
|
||||||
// classes and traits must be initialised with identifier names.
|
// 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() {
|
fn new() {
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
let class0 = context.new_class("Marty McFly");
|
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);
|
assert_eq!(class0, class1);
|
||||||
|
|
||||||
let tr0 = context.new_trait("Doc Brown");
|
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);
|
assert_eq!(tr0, tr1);
|
||||||
|
|
||||||
let id = context.get_identifier("Einstein Brown");
|
let id = context.identifiers().get("Einstein Brown");
|
||||||
assert_eq!(context.get_identifier_value(id).unwrap(), "Einstein Brown");
|
assert_eq!(context.identifiers().resolve(id).unwrap(), "Einstein Brown");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,32 @@
|
||||||
|
use std::sync::RwLock;
|
||||||
use string_interner::{StringInterner, Sym};
|
use string_interner::{StringInterner, Sym};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Identifier(Sym);
|
pub struct Identifier(Sym);
|
||||||
|
|
||||||
pub struct Identifiers(StringInterner<Sym>);
|
pub struct Identifiers(RwLock<StringInterner<Sym>>);
|
||||||
|
|
||||||
impl Identifiers {
|
impl Identifiers {
|
||||||
pub fn new() -> Identifiers {
|
pub fn new() -> Identifiers {
|
||||||
Identifiers(StringInterner::default())
|
Identifiers(RwLock::new(StringInterner::default()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&mut self, value: &str) -> Identifier {
|
pub fn get(&self, value: &str) -> Identifier {
|
||||||
let sym = self.0.get_or_intern(value);
|
let mut identifiers = self.0.write().unwrap();
|
||||||
|
let sym = identifiers.get_or_intern(value);
|
||||||
Identifier(sym)
|
Identifier(sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve(&self, identifier: Identifier) -> Option<&str> {
|
pub fn resolve(&self, identifier: Identifier) -> Option<String> {
|
||||||
self.0.resolve(identifier.0)
|
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 {
|
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;
|
extern crate wrc;
|
||||||
|
|
||||||
mod class;
|
mod class;
|
||||||
|
mod constant;
|
||||||
mod context;
|
mod context;
|
||||||
mod identifier;
|
mod identifier;
|
||||||
mod r#trait;
|
mod r#trait;
|
||||||
|
|
|
@ -44,6 +44,15 @@ impl Traits {
|
||||||
TraitId(elements.len())
|
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 {
|
pub fn is_empty(&self) -> bool {
|
||||||
let elements = self.0.read().unwrap();
|
let elements = self.0.read().unwrap();
|
||||||
elements.is_empty()
|
elements.is_empty()
|
||||||
|
@ -127,8 +136,8 @@ mod test {
|
||||||
fn set_name() {
|
fn set_name() {
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
let tr = context.new_trait("Marty McFly");
|
let tr = context.new_trait("Marty McFly");
|
||||||
assert_eq!(tr.name(), context.get_identifier("Marty McFly"));
|
assert_eq!(tr.name(), context.identifiers().get("Marty McFly"));
|
||||||
tr.set_name(context.get_identifier("Doc Brown"));
|
tr.set_name(context.identifiers().get("Doc Brown"));
|
||||||
assert_eq!(tr.name(), context.get_identifier("Doc Brown"));
|
assert_eq!(tr.name(), context.identifiers().get("Doc Brown"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue