Move everything symbol-table-related into a separate module

This commit is contained in:
greg 2018-05-20 20:36:57 -07:00
parent cea7427847
commit 642e9da8ee
4 changed files with 92 additions and 86 deletions

View File

@ -7,11 +7,11 @@ use itertools::Itertools;
use util::StateStack; use util::StateStack;
use ast_reducing::{ReducedAST, Stmt, Expr, Lit, Func}; use ast_reducing::{ReducedAST, Stmt, Expr, Lit, Func};
use typechecking::{TypeContext, SymbolSpec, Symbol}; use symbol_table::{SymbolSpec, Symbol, SymbolTable};
pub struct State<'a> { pub struct State<'a> {
values: StateStack<'a, Rc<String>, ValueEntry>, values: StateStack<'a, Rc<String>, ValueEntry>,
type_context_handle: Rc<RefCell<TypeContext>>, symbol_table_handle: Rc<RefCell<SymbolTable>>,
} }
macro_rules! builtin_binding { macro_rules! builtin_binding {
@ -21,12 +21,12 @@ macro_rules! builtin_binding {
} }
impl<'a> State<'a> { impl<'a> State<'a> {
pub fn new(type_context_handle: Rc<RefCell<TypeContext>>) -> State<'a> { pub fn new(symbol_table_handle: Rc<RefCell<SymbolTable>>) -> State<'a> {
let mut values = StateStack::new(Some(format!("global"))); let mut values = StateStack::new(Some(format!("global")));
builtin_binding!("print", values); builtin_binding!("print", values);
builtin_binding!("println", values); builtin_binding!("println", values);
builtin_binding!("getline", values); builtin_binding!("getline", values);
State { values, type_context_handle } State { values, symbol_table_handle }
} }
pub fn debug_print(&self) -> String { pub fn debug_print(&self) -> String {
@ -181,7 +181,7 @@ impl<'a> State<'a> {
} }
let mut func_state = State { let mut func_state = State {
values: self.values.new_frame(name.map(|n| format!("{}", n))), values: self.values.new_frame(name.map(|n| format!("{}", n))),
type_context_handle: self.type_context_handle.clone(), symbol_table_handle: self.symbol_table_handle.clone(),
}; };
for (param, val) in params.into_iter().zip(args.into_iter()) { for (param, val) in params.into_iter().zip(args.into_iter()) {
let val = func_state.expression(val)?; let val = func_state.expression(val)?;
@ -264,8 +264,8 @@ impl<'a> State<'a> {
//TODO add a layer of indirection here to talk to the symbol table first, and only then look up //TODO add a layer of indirection here to talk to the symbol table first, and only then look up
//in the values table //in the values table
let type_context = self.type_context_handle.borrow(); let symbol_table = self.symbol_table_handle.borrow();
Ok(match type_context.symbol_table.values.get(&name) { Ok(match symbol_table.values.get(&name) {
Some(Symbol { name, spec }) => match spec { Some(Symbol { name, spec }) => match spec {
SymbolSpec::Custom(_typename) => { SymbolSpec::Custom(_typename) => {
Expr::Lit(Lit::Custom(name.clone())) Expr::Lit(Lit::Custom(name.clone()))
@ -290,15 +290,15 @@ impl<'a> State<'a> {
mod eval_tests { mod eval_tests {
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use typechecking::TypeContext; use symbol_table::SymbolTable;
use tokenizing::tokenize; use tokenizing::tokenize;
use parsing::parse; use parsing::parse;
use eval::State; use eval::State;
macro_rules! fresh_env { macro_rules! fresh_env {
($string:expr, $correct:expr) => { ($string:expr, $correct:expr) => {
let type_context = Rc::new(RefCell::new(TypeContext::new())); let symbol_table = Rc::new(RefCell::new(SymbolTable::new()));
let mut state = State::new(type_context); let mut state = State::new(symbol_table);
let all_output = state.evaluate(parse(tokenize($string)).0.unwrap().reduce(), true); let all_output = state.evaluate(parse(tokenize($string)).0.unwrap().reduce(), true);
let ref output = all_output.last().unwrap(); let ref output = all_output.last().unwrap();
assert_eq!(**output, Ok($correct.to_string())); assert_eq!(**output, Ok($correct.to_string()));

View File

@ -24,6 +24,7 @@ mod util;
mod builtin; mod builtin;
mod tokenizing; mod tokenizing;
mod parsing; mod parsing;
mod symbol_table;
mod typechecking; mod typechecking;
mod ast_reducing; mod ast_reducing;
mod eval; mod eval;
@ -34,15 +35,16 @@ mod eval;
#[PipelineSteps(tokenizing, parsing, symbol_table, typechecking, ast_reducing, eval)] #[PipelineSteps(tokenizing, parsing, symbol_table, typechecking, ast_reducing, eval)]
pub struct Schala { pub struct Schala {
state: eval::State<'static>, state: eval::State<'static>,
type_context: Rc<RefCell<typechecking::TypeContext>>, symbol_table: Rc<RefCell<symbol_table::SymbolTable>>,
//type_context
} }
impl Schala { impl Schala {
pub fn new() -> Schala { pub fn new() -> Schala {
let type_context = Rc::new(RefCell::new(typechecking::TypeContext::new())); let symbols = Rc::new(RefCell::new(symbol_table::SymbolTable::new()));
Schala { Schala {
type_context: type_context.clone(), symbol_table: symbols.clone(),
state: eval::State::new(type_context), state: eval::State::new(symbols),
} }
} }
} }
@ -74,10 +76,10 @@ fn parsing(_handle: &mut Schala, input: Vec<tokenizing::Token>, comp: Option<&mu
} }
fn symbol_table(handle: &mut Schala, input: parsing::AST, comp: Option<&mut UnfinishedComputation>) -> Result<parsing::AST, String> { fn symbol_table(handle: &mut Schala, input: parsing::AST, comp: Option<&mut UnfinishedComputation>) -> Result<parsing::AST, String> {
let add = handle.type_context.borrow_mut().add_top_level_types(&input); let add = handle.symbol_table.borrow_mut().add_top_level_symbols(&input);
match add { match add {
Ok(()) => { Ok(()) => {
let artifact = TraceArtifact::new("symbol_table", handle.type_context.borrow().debug_symbol_table()); let artifact = TraceArtifact::new("symbol_table", handle.symbol_table.borrow().debug_symbol_table());
comp.map(|comp| comp.add_artifact(artifact)); comp.map(|comp| comp.add_artifact(artifact));
Ok(input) Ok(input)
}, },
@ -86,6 +88,7 @@ fn symbol_table(handle: &mut Schala, input: parsing::AST, comp: Option<&mut Unfi
} }
fn typechecking(handle: &mut Schala, input: parsing::AST, comp: Option<&mut UnfinishedComputation>) -> Result<parsing::AST, String> { fn typechecking(handle: &mut Schala, input: parsing::AST, comp: Option<&mut UnfinishedComputation>) -> Result<parsing::AST, String> {
/*
match handle.type_context.borrow_mut().type_check_ast(&input) { match handle.type_context.borrow_mut().type_check_ast(&input) {
Ok(ty) => { Ok(ty) => {
comp.map(|comp| comp.add_artifact(TraceArtifact::new("type_check", format!("{:?}", ty)))); comp.map(|comp| comp.add_artifact(TraceArtifact::new("type_check", format!("{:?}", ty))));
@ -96,6 +99,8 @@ fn typechecking(handle: &mut Schala, input: parsing::AST, comp: Option<&mut Unfi
Ok(input) Ok(input)
} }
} }
*/
Ok(input)
} }
fn ast_reducing(_handle: &mut Schala, input: parsing::AST, comp: Option<&mut UnfinishedComputation>) -> Result<ast_reducing::ReducedAST, String> { fn ast_reducing(_handle: &mut Schala, input: parsing::AST, comp: Option<&mut UnfinishedComputation>) -> Result<ast_reducing::ReducedAST, String> {

View File

@ -0,0 +1,70 @@
use std::collections::HashMap;
use std::rc::Rc;
use std::fmt;
use std::fmt::Write;
use parsing;
//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
}
impl SymbolTable {
pub fn new() -> SymbolTable {
SymbolTable { values: HashMap::new() }
}
}
#[derive(Debug)]
pub struct Symbol {
pub name: Rc<String>,
pub spec: SymbolSpec,
}
#[derive(Debug)]
pub enum SymbolSpec {
Func, Custom(String)
}
impl SymbolTable {
/* note: this adds names for *forward reference* but doesn't actually create any types. solve that problem
* later */
pub fn add_top_level_symbols(&mut self, ast: &parsing::AST) -> Result<(), String> {
use self::parsing::{Statement, TypeName, Variant, TypeSingletonName, TypeBody};
use self::parsing::Declaration::*;
for statement in ast.0.iter() {
if let Statement::Declaration(decl) = statement {
match decl {
FuncSig(signature) | FuncDecl(signature, _) => {
self.values.insert(
signature.name.clone(),
Symbol { name: signature.name.clone(), spec: SymbolSpec::Func }
);
},
TypeDecl(TypeSingletonName { name, ..}, TypeBody(variants)) => {
for var in variants {
match var {
Variant::UnitStruct(variant_name) => {
//TODO will have to make this a function to this type eventually
let spec = SymbolSpec::Custom(format!("{}", name));
self.values.insert(variant_name.clone(), Symbol { name: variant_name.clone(), spec });
},
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");
for (sym, ty) in &self.values {
write!(output, "{} -> {:?}\n", sym, ty).unwrap();
}
output
}
}

View File

@ -8,7 +8,6 @@ use std::fmt::Write;
use itertools::Itertools; use itertools::Itertools;
/* GIANT TODO - use the rust im crate, unless I make this code way less haskell-ish after it's done /* GIANT TODO - use the rust im crate, unless I make this code way less haskell-ish after it's done
*/ */
@ -16,32 +15,8 @@ use parsing;
pub struct TypeContext { pub struct TypeContext {
environment: TypeEnvironment, environment: TypeEnvironment,
pub symbol_table: SymbolTable
} }
//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
}
impl SymbolTable {
fn new() -> SymbolTable {
SymbolTable { values: HashMap::new() }
}
}
#[derive(Debug)]
pub struct Symbol {
pub name: Rc<String>,
pub spec: SymbolSpec,
}
#[derive(Debug)]
pub enum SymbolSpec {
Func, Custom(String)
}
/* real meat of type stuff here */ /* real meat of type stuff here */
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
@ -214,53 +189,9 @@ pub type TypeResult<T> = Result<T, String>;
impl TypeContext { impl TypeContext {
pub fn new() -> TypeContext { pub fn new() -> TypeContext {
TypeContext { environment: TypeEnvironment::default(), /*type_var_count: 0*/ symbol_table: SymbolTable::new() } TypeContext { environment: TypeEnvironment::default(), /*type_var_count: 0*/ }
} }
/* note: this adds names for *forward reference* but doesn't actually create any types. solve that problem
* later */
pub fn add_top_level_types(&mut self, ast: &parsing::AST) -> TypeResult<()> {
use self::parsing::{Statement, TypeName, Variant, TypeSingletonName, TypeBody};
use self::parsing::Declaration::*;
use self::Type::*;
for statement in ast.0.iter() {
if let Statement::Declaration(decl) = statement {
match decl {
FuncSig(signature) | FuncDecl(signature, _) => {
self.symbol_table.values.insert(
signature.name.clone(),
Symbol { name: signature.name.clone(), spec: SymbolSpec::Func }
);
},
TypeDecl(TypeSingletonName { name, ..}, TypeBody(variants)) => {
for var in variants {
match var {
Variant::UnitStruct(variant_name) => {
//TODO will have to make this a function to this type eventually
let spec = SymbolSpec::Custom(format!("{}", name));
self.symbol_table.values.insert(variant_name.clone(), Symbol { name: variant_name.clone(), spec });
},
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");
for (sym, ty) in &self.symbol_table.values {
write!(output, "{} -> {:?}\n", sym, ty).unwrap();
}
write!(output, "\nType Env\n").unwrap();
for (sym, ty) in &self.environment.map {
write!(output, "{} : {:?}\n", sym, ty).unwrap();
}
output
}
pub fn type_check_ast(&mut self, ast: &parsing::AST) -> TypeResult<String> { pub fn type_check_ast(&mut self, ast: &parsing::AST) -> TypeResult<String> {
let ref block = ast.0; let ref block = ast.0;