schala/schala-lang/src/symbol_table.rs

127 lines
4.1 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
use std::rc::Rc;
use std::fmt;
use std::fmt::Write;
2018-06-04 19:25:40 -07:00
use ast;
2018-06-03 02:39:49 -07:00
use typechecking::TypeName;
//cf. p. 150 or so of Language Implementation Patterns
pub struct SymbolTable {
pub values: HashMap<Rc<String>, Symbol> //TODO this will eventually have real type information
}
2018-08-05 18:01:42 -07:00
//TODO add various types of lookups here, maybe multiple hash tables internally? also make values
//non-public
impl SymbolTable {
pub fn new() -> SymbolTable {
SymbolTable { values: HashMap::new() }
}
}
#[derive(Debug)]
pub struct Symbol {
pub name: Rc<String>,
pub spec: SymbolSpec,
}
2018-06-03 23:04:07 -07:00
impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<Name: {}, Spec: {}>", self.name, self.spec)
}
}
#[derive(Debug)]
pub enum SymbolSpec {
2018-06-03 02:39:49 -07:00
Func(Vec<TypeName>),
2018-05-30 23:54:24 -07:00
DataConstructor {
index: usize,
2018-05-30 23:54:24 -07:00
type_name: Rc<String>,
type_args: Vec<Rc<String>>,
},
}
2018-06-03 23:04:07 -07:00
impl fmt::Display for SymbolSpec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::SymbolSpec::*;
match self {
Func(type_names) => write!(f, "Func({:?})", type_names),
DataConstructor { index, type_name, type_args } => write!(f, "DataConstructor({})({:?} -> {})", index, type_args, type_name),
2018-06-03 23:04:07 -07:00
}
}
}
impl SymbolTable {
/* note: this adds names for *forward reference* but doesn't actually create any types. solve that problem
* later */
2018-06-04 19:25:40 -07:00
pub fn add_top_level_symbols(&mut self, ast: &ast::AST) -> Result<(), String> {
use self::ast::{Statement, TypeName, Variant, TypeSingletonName, TypeBody};
use self::ast::Declaration::*;
for statement in ast.0.iter() {
if let Statement::Declaration(decl) = statement {
match decl {
FuncSig(signature) | FuncDecl(signature, _) => {
2018-06-03 02:39:49 -07:00
let mut ch: char = 'a';
let mut types = vec![];
for param in signature.params.iter() {
match param {
(_, Some(ty)) => {
//TODO eventually handle this case different
types.push(Rc::new(format!("{}", ch)));
ch = ((ch as u8) + 1) as char;
},
(_, None) => {
types.push(Rc::new(format!("{}", ch)));
ch = ((ch as u8) + 1) as char;
}
}
}
let spec = SymbolSpec::Func(types);
self.values.insert(
signature.name.clone(),
2018-06-03 02:39:49 -07:00
Symbol { name: signature.name.clone(), spec }
);
},
TypeDecl { name: TypeSingletonName { name, params}, body: TypeBody(variants), mutable, } => {
for (index, var) in variants.iter().enumerate() {
match var {
Variant::UnitStruct(variant_name) => {
2018-05-30 23:54:24 -07:00
let spec = SymbolSpec::DataConstructor {
index,
2018-05-30 23:54:24 -07:00
type_name: name.clone(),
type_args: vec![],
};
self.values.insert(variant_name.clone(), Symbol { name: variant_name.clone(), spec });
},
2018-05-30 23:54:24 -07:00
Variant::TupleStruct(variant_name, tuple_members) => {
2018-06-04 19:04:51 -07:00
let type_args = tuple_members.iter().map(|type_name| match type_name {
TypeName::Singleton(TypeSingletonName { name, ..}) => name.clone(),
TypeName::Tuple(_) => unimplemented!(),
}).collect();
let spec = SymbolSpec::DataConstructor {
index,
2018-05-30 23:54:24 -07:00
type_name: name.clone(),
type_args
};
let symbol = Symbol { name: variant_name.clone(), spec };
self.values.insert(variant_name.clone(), symbol);
},
e => return Err(format!("{:?} not supported in typing yet", e)),
}
}
},
_ => ()
}
}
}
Ok(())
}
pub fn debug_symbol_table(&self) -> String {
let mut output = format!("Symbol table\n");
2018-06-03 23:04:07 -07:00
for (name, sym) in &self.values {
write!(output, "{} -> {}\n", name, sym).unwrap();
}
output
}
}