1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright (c) 2018 Fabian Schuiki

//! Facilities to manage declarations and resolve names.

#![deny(missing_docs)]

use std::collections::{HashMap, HashSet};

use crate::common::Verbosity;
use crate::common::errors::*;
use crate::common::score::Result;
use crate::common::source::Spanned;

use crate::score::{ScoreContext, ScopeRef, Def, ResolvableName};

/// A scope.
#[derive(Clone, Debug)]
pub struct Scope {
    /// The parent scope.
    pub parent: Option<ScopeRef>,

    /// The definitions made in this scope.
    pub defs: HashMap<ResolvableName, Vec<Spanned<Def>>>,

    /// The definitions imported from other scopes.
    pub imported_defs: HashMap<ResolvableName, Vec<Spanned<Def>>>,

    /// The explicitly imported scopes.
    pub imported_scopes: HashSet<ScopeRef>,
}

impl Scope {
    /// Create a new empty scope.
    pub fn new(parent: Option<ScopeRef>) -> Scope {
        Scope {
            parent: parent,
            defs: HashMap::new(),
            imported_defs: HashMap::new(),
            imported_scopes: HashSet::new(),
        }
    }
}

impl<'lazy, 'sb, 'ast, 'ctx> ScoreContext<'lazy, 'sb, 'ast, 'ctx> {
    /// Lookup a scope and perform an operation on it.
    pub fn with_scope<F,R>(&self, scope: ScopeRef, f: F) -> Result<R>
        where F: FnOnce(&mut Scope) -> Result<R>
    {
        let mut tbl = self.sb.scope2_table.borrow_mut();
        let scp = match tbl.get_mut(&scope) {
            Some(s) => s,
            None => {
                self.emit(
                    DiagBuilder2::bug(format!("scope {:?} does not exist`", scope))
                );
                return Err(());
            }
        };
        f(scp)
    }

    /// Create a subscope of another scope.
    pub fn subscope(&self, scope: ScopeRef, parent: ScopeRef) {
        self.sb.scope2_table.borrow_mut().insert(scope, Scope::new(Some(parent)));
    }

    /// Define a new name in a scope.
    pub fn define(&self, scope: ScopeRef, name: Spanned<ResolvableName>, def: Def) -> Result<()> {
        if self.sess.opts.verbosity.contains(Verbosity::NAMES) {
            debugln!("define `{}` as {:?} in scope {:?}", name.value, def, scope);
        }
        self.with_scope(scope, |scope| match def {
            // Handle overloadable cases.
            Def::Enum(_) => {
                scope.defs
                    .entry(name.value)
                    .or_insert_with(|| Vec::new())
                    .push(Spanned::new(def, name.span));
                Ok(())
            },

            // Handle unique cases.
            _ => {
                let ins = scope.defs.insert(name.value, vec![Spanned::new(def, name.span)]);
                if let Some(existing) = ins {
                    self.emit(
                        DiagBuilder2::error(format!("`{}` has already been declared", name.value))
                        .span(name.span)
                        .add_note("Previous declaration was here:")
                        .span(existing.last().unwrap().span)
                    );
                    Err(())
                } else {
                    Ok(())
                }
            }
        })
    }

    /// Import a definition into a scope.
    pub fn import_def(&self, scope: ScopeRef, name: Spanned<ResolvableName>, def: Def) -> Result<()> {
        self.with_scope(scope, |scope|{
            scope.imported_defs
                .entry(name.value)
                .or_insert_with(|| Vec::new())
                .push(Spanned::new(def, name.span));
            Ok(())
        })
    }

    /// Import an entire scope into another scope.
    pub fn import_scope(&self, scope: ScopeRef, into: ScopeRef) -> Result<()> {
        self.with_scope(into, |into|{
            into.imported_scopes.insert(scope);
            Ok(())
        })
    }
}