Skip to content

Commit

Permalink
feat: Add the SymbolRef type
Browse files Browse the repository at this point in the history
`SymbolRef` is a borrowed version of the symbol type and allows the builtin types to each have a `SymbolRef` which uniquely references them.
  • Loading branch information
Marwes committed Jul 17, 2016
1 parent 452d3fd commit 908bab1
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 61 deletions.
11 changes: 9 additions & 2 deletions base/src/scoped_map.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! A map data type which allows the same key to exist at multiple scope levels
use std::borrow::Borrow;
use std::collections::HashMap;
use std::collections::hash_map;
use std::collections::hash_map::{Entry, IterMut};
Expand Down Expand Up @@ -75,12 +76,18 @@ impl<K: Eq + Hash + Clone, V> ScopedMap<K, V> {
}

/// Returns a reference to the last inserted value corresponding to the key
pub fn get<'a>(&'a self, k: &K) -> Option<&'a V> {
pub fn get<'a, Q: ?Sized>(&'a self, k: &Q) -> Option<&'a V>
where K: Borrow<Q>,
Q: Eq + Hash
{
self.map.get(k).and_then(|x| x.last())
}

/// Returns a reference to the all inserted value corresponding to the key
pub fn get_all<'a>(&'a self, k: &K) -> Option<&'a [V]> {
pub fn get_all<'a, Q: ?Sized>(&'a self, k: &Q) -> Option<&'a [V]>
where K: Borrow<Q>,
Q: Eq + Hash
{
self.map.get(k).map(|x| &x[..])
}

Expand Down
80 changes: 73 additions & 7 deletions base/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,117 @@ use ast::{AstId, DisplayEnv, IdentEnv, ASTType};
#[derive(Clone, Eq)]
pub struct Symbol(Arc<NameBuf>);

impl Deref for Symbol {
type Target = SymbolRef;
fn deref(&self) -> &SymbolRef {
let s: &str = self.0.as_str();
unsafe { ::std::mem::transmute::<&str, &SymbolRef>(s) }
}
}

impl Borrow<SymbolRef> for Symbol {
fn borrow(&self) -> &SymbolRef {
&**self
}
}

impl AsRef<str> for Symbol {
fn as_ref(&self) -> &str {
self.0.as_str()
}
}


impl fmt::Debug for Symbol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:p}:{}", &*self.0, self.0)
write!(f, "{:?}", &**self)
}
}

impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
write!(f, "{}", &**self)
}
}

impl PartialEq for Symbol {
fn eq(&self, other: &Symbol) -> bool {
&*self.0 as *const NameBuf == &*other.0 as *const NameBuf
&**self == &**other
}
}

impl PartialOrd for Symbol {
fn partial_cmp(&self, other: &Symbol) -> Option<Ordering> {
(&*self.0 as *const NameBuf).partial_cmp(&(&*other.0 as *const NameBuf))
(**self).partial_cmp(other)
}
}

impl Ord for Symbol {
fn cmp(&self, other: &Symbol) -> Ordering {
(&*self.0 as *const NameBuf).cmp(&(&*other.0 as *const NameBuf))
(**self).cmp(other)
}
}

impl Hash for Symbol {
fn hash<H: Hasher>(&self, h: &mut H) {
(&*self.0 as *const NameBuf).hash(h)
(**self).hash(h)
}
}

impl Symbol {
pub fn new(name: &str) -> Symbol {
Symbol(Arc::new(NameBuf(String::from(name))))
}
}

#[derive(Eq)]
pub struct SymbolRef(str);

impl fmt::Debug for SymbolRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:p}:{}", self, &self.0)
}
}

impl fmt::Display for SymbolRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self.0)
}
}

impl PartialEq for SymbolRef {
fn eq(&self, other: &SymbolRef) -> bool {
self.ptr() == other.ptr()
}
}

impl PartialOrd for SymbolRef {
fn partial_cmp(&self, other: &SymbolRef) -> Option<Ordering> {
self.ptr().partial_cmp(&other.ptr())
}
}

impl Ord for SymbolRef {
fn cmp(&self, other: &SymbolRef) -> Ordering {
self.ptr().cmp(&other.ptr())
}
}

impl Hash for SymbolRef {
fn hash<H: Hasher>(&self, h: &mut H) {
self.ptr().hash(h)
}
}

impl AsRef<str> for SymbolRef {
fn as_ref(&self) -> &str {
&self.0
}
}

impl SymbolRef {
/// Checks whether the names of two symbols are equal
pub fn name_eq(&self, other: &Symbol) -> bool {
pub fn name_eq(&self, other: &SymbolRef) -> bool {
self == other || self.0 == other.0
}

Expand All @@ -70,6 +132,10 @@ impl Symbol {
let name = self.as_ref();
name.split(':').next().unwrap_or(name)
}

fn ptr(&self) -> *const () {
self.0.as_bytes().as_ptr() as *const ()
}
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
Expand Down
61 changes: 44 additions & 17 deletions base/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,59 +8,59 @@ use std::rc::Rc;

use ast;
use ast::{ASTType, DisplayEnv};
use symbol::Symbol;
use symbol::{Symbol, SymbolRef};

pub type TcType = ast::ASTType<Symbol>;
pub type TcIdent = ast::TcIdent<Symbol>;

/// Trait for values which contains kinded values which can be refered by name
pub trait KindEnv {
/// Returns the kind of the type `type_name`
fn find_kind(&self, type_name: &Symbol) -> Option<RcKind>;
fn find_kind(&self, type_name: &SymbolRef) -> Option<RcKind>;
}

impl KindEnv for () {
fn find_kind(&self, _type_name: &Symbol) -> Option<RcKind> {
fn find_kind(&self, _type_name: &SymbolRef) -> Option<RcKind> {
None
}
}

impl<'a, T: ?Sized + KindEnv> KindEnv for &'a T {
fn find_kind(&self, id: &Symbol) -> Option<RcKind> {
fn find_kind(&self, id: &SymbolRef) -> Option<RcKind> {
(**self).find_kind(id)
}
}

impl<T: KindEnv, U: KindEnv> KindEnv for (T, U) {
fn find_kind(&self, id: &Symbol) -> Option<RcKind> {
fn find_kind(&self, id: &SymbolRef) -> Option<RcKind> {
let &(ref outer, ref inner) = self;
inner.find_kind(id)
.or_else(|| outer.find_kind(id))
}
}

impl KindEnv for HashMap<String, TcType> {
fn find_kind(&self, _type_name: &Symbol) -> Option<RcKind> {
fn find_kind(&self, _type_name: &SymbolRef) -> Option<RcKind> {
None
}
}

/// Trait for values which contains typed values which can be refered by name
pub trait TypeEnv: KindEnv {
/// Returns the type of the value bound at `id`
fn find_type(&self, id: &Symbol) -> Option<&TcType>;
fn find_type(&self, id: &SymbolRef) -> Option<&TcType>;
/// Returns information about the type `id`
fn find_type_info(&self, id: &Symbol) -> Option<&Alias<Symbol, TcType>>;
fn find_type_info(&self, id: &SymbolRef) -> Option<&Alias<Symbol, TcType>>;
/// Returns a record which contains all `fields`. The first element is the record type and the
/// second is the alias type.
fn find_record(&self, fields: &[Symbol]) -> Option<(&TcType, &TcType)>;
}

impl TypeEnv for () {
fn find_type(&self, _id: &Symbol) -> Option<&TcType> {
fn find_type(&self, _id: &SymbolRef) -> Option<&TcType> {
None
}
fn find_type_info(&self, _id: &Symbol) -> Option<&Alias<Symbol, TcType>> {
fn find_type_info(&self, _id: &SymbolRef) -> Option<&Alias<Symbol, TcType>> {
None
}
fn find_record(&self, _fields: &[Symbol]) -> Option<(&TcType, &TcType)> {
Expand All @@ -69,10 +69,10 @@ impl TypeEnv for () {
}

impl<'a, T: ?Sized + TypeEnv> TypeEnv for &'a T {
fn find_type(&self, id: &Symbol) -> Option<&TcType> {
fn find_type(&self, id: &SymbolRef) -> Option<&TcType> {
(**self).find_type(id)
}
fn find_type_info(&self, id: &Symbol) -> Option<&Alias<Symbol, TcType>> {
fn find_type_info(&self, id: &SymbolRef) -> Option<&Alias<Symbol, TcType>> {
(**self).find_type_info(id)
}
fn find_record(&self, fields: &[Symbol]) -> Option<(&TcType, &TcType)> {
Expand All @@ -81,12 +81,12 @@ impl<'a, T: ?Sized + TypeEnv> TypeEnv for &'a T {
}

impl<T: TypeEnv, U: TypeEnv> TypeEnv for (T, U) {
fn find_type(&self, id: &Symbol) -> Option<&TcType> {
fn find_type(&self, id: &SymbolRef) -> Option<&TcType> {
let &(ref outer, ref inner) = self;
inner.find_type(id)
.or_else(|| outer.find_type(id))
}
fn find_type_info(&self, id: &Symbol) -> Option<&Alias<Symbol, TcType>> {
fn find_type_info(&self, id: &SymbolRef) -> Option<&Alias<Symbol, TcType>> {
let &(ref outer, ref inner) = self;
inner.find_type_info(id)
.or_else(|| outer.find_type_info(id))
Expand All @@ -99,10 +99,10 @@ impl<T: TypeEnv, U: TypeEnv> TypeEnv for (T, U) {
}

impl TypeEnv for HashMap<String, TcType> {
fn find_type(&self, id: &Symbol) -> Option<&TcType> {
fn find_type(&self, id: &SymbolRef) -> Option<&TcType> {
self.get(id.as_ref())
}
fn find_type_info(&self, _id: &Symbol) -> Option<&Alias<Symbol, TcType>> {
fn find_type_info(&self, _id: &SymbolRef) -> Option<&Alias<Symbol, TcType>> {
None
}
fn find_record(&self, _fields: &[Symbol]) -> Option<(&TcType, &TcType)> {
Expand Down Expand Up @@ -304,6 +304,12 @@ pub enum BuiltinType {
Function,
}

impl BuiltinType {
pub fn symbol(self) -> &'static SymbolRef {
unsafe { ::std::mem::transmute::<&'static str, &'static SymbolRef>(self.to_str()) }
}
}

impl ::std::str::FromStr for BuiltinType {
type Err = ();
fn from_str(x: &str) -> Result<BuiltinType, ()> {
Expand Down Expand Up @@ -568,17 +574,38 @@ impl<Id, T> Type<Id, T>
impl<Id, T> Type<Id, T>
where T: Deref<Target = Type<Id, T>>
{
pub fn as_alias(&self) -> Option<(&Id, &[T])> {
pub fn as_alias_symbol(&self) -> Option<&Id> {
match *self {
Type::Data(ref id, _) => {
match **id {
Type::Id(ref id) => Some(id),
Type::Alias(ref alias) => Some(&alias.name),
_ => None,
}
}
Type::Id(ref id) => Some(id),
Type::Alias(ref alias) => Some(&alias.name),
_ => None,
}
}
}

impl<T> Type<Symbol, T>
where T: Deref<Target = Type<Symbol, T>>
{
pub fn as_alias(&self) -> Option<(&SymbolRef, &[T])> {
match *self {
Type::Data(ref id, ref args) => {
match **id {
Type::Id(ref id) => Some((id, args)),
Type::Alias(ref alias) => Some((&alias.name, args)),
Type::Builtin(b) => Some((b.symbol(), args)),
_ => None,
}
}
Type::Id(ref id) => Some((id, &[][..])),
Type::Alias(ref alias) => Some((&alias.name, &[][..])),
Type::Builtin(b) => Some((b.symbol(), &[][..])),
_ => None,
}
}
Expand Down
2 changes: 1 addition & 1 deletion check/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn metadata(env: &MetadataEnv, expr: &mut ast::LExpr<TcIdent>) -> Metadata {
debug!("Lookup {}", id);
self.env
.stack
.get(&id)
.get(id)
.or_else(|| self.env.env.get_metadata(id))
}

Expand Down
10 changes: 5 additions & 5 deletions check/src/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt;
use base::ast;
use base::ast::{Typed, DisplayEnv, MutVisitor};
use base::scoped_map::ScopedMap;
use base::symbol::{Symbol, SymbolModule};
use base::symbol::{Symbol, SymbolRef, SymbolModule};
use base::types;
use base::types::{Alias, TcType, Type, TcIdent, RcKind, KindEnv, TypeEnv};
use base::error::Errors;
Expand Down Expand Up @@ -44,16 +44,16 @@ struct Environment<'b> {
}

impl<'a> KindEnv for Environment<'a> {
fn find_kind(&self, _type_name: &Symbol) -> Option<RcKind> {
fn find_kind(&self, _type_name: &SymbolRef) -> Option<RcKind> {
None
}
}

impl<'a> TypeEnv for Environment<'a> {
fn find_type(&self, id: &Symbol) -> Option<&TcType> {
fn find_type(&self, id: &SymbolRef) -> Option<&TcType> {
self.stack.get(id).map(|t| &t.1).or_else(|| self.env.find_type(id))
}
fn find_type_info(&self, id: &Symbol) -> Option<&types::Alias<Symbol, TcType>> {
fn find_type_info(&self, id: &SymbolRef) -> Option<&types::Alias<Symbol, TcType>> {
self.stack_types
.get(id)
.or_else(|| self.env.find_type_info(id))
Expand Down Expand Up @@ -160,7 +160,7 @@ pub fn rename(symbols: &mut SymbolModule,
fn rename(&self, id: &Symbol, expected: &TcType) -> Result<Option<Symbol>, RenameError> {
let locals = self.env
.stack
.get_all(&id);
.get_all(id);
let global = self.env.find_type(&id).map(|typ| (id, typ));
let candidates = || {
locals.iter()
Expand Down
Loading

0 comments on commit 908bab1

Please sign in to comment.