diff --git a/schala-lang/src/eval.rs b/schala-lang/src/eval.rs index 6643fc6..76c41b5 100644 --- a/schala-lang/src/eval.rs +++ b/schala-lang/src/eval.rs @@ -7,11 +7,11 @@ use itertools::Itertools; use util::StateStack; use ast_reducing::{ReducedAST, Stmt, Expr, Lit, Func}; -use typechecking::{TypeContext, SymbolSpec, Symbol}; +use symbol_table::{SymbolSpec, Symbol, SymbolTable}; pub struct State<'a> { values: StateStack<'a, Rc, ValueEntry>, - type_context_handle: Rc>, + symbol_table_handle: Rc>, } macro_rules! builtin_binding { @@ -21,12 +21,12 @@ macro_rules! builtin_binding { } impl<'a> State<'a> { - pub fn new(type_context_handle: Rc>) -> State<'a> { + pub fn new(symbol_table_handle: Rc>) -> State<'a> { let mut values = StateStack::new(Some(format!("global"))); builtin_binding!("print", values); builtin_binding!("println", values); builtin_binding!("getline", values); - State { values, type_context_handle } + State { values, symbol_table_handle } } pub fn debug_print(&self) -> String { @@ -181,7 +181,7 @@ impl<'a> State<'a> { } let mut func_state = State { 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()) { 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 //in the values table - let type_context = self.type_context_handle.borrow(); - Ok(match type_context.symbol_table.values.get(&name) { + let symbol_table = self.symbol_table_handle.borrow(); + Ok(match symbol_table.values.get(&name) { Some(Symbol { name, spec }) => match spec { SymbolSpec::Custom(_typename) => { Expr::Lit(Lit::Custom(name.clone())) @@ -290,15 +290,15 @@ impl<'a> State<'a> { mod eval_tests { use std::cell::RefCell; use std::rc::Rc; - use typechecking::TypeContext; + use symbol_table::SymbolTable; use tokenizing::tokenize; use parsing::parse; use eval::State; macro_rules! fresh_env { ($string:expr, $correct:expr) => { - let type_context = Rc::new(RefCell::new(TypeContext::new())); - let mut state = State::new(type_context); + let symbol_table = Rc::new(RefCell::new(SymbolTable::new())); + let mut state = State::new(symbol_table); let all_output = state.evaluate(parse(tokenize($string)).0.unwrap().reduce(), true); let ref output = all_output.last().unwrap(); assert_eq!(**output, Ok($correct.to_string())); diff --git a/schala-lang/src/lib.rs b/schala-lang/src/lib.rs index c9cb951..e27b2e6 100644 --- a/schala-lang/src/lib.rs +++ b/schala-lang/src/lib.rs @@ -24,6 +24,7 @@ mod util; mod builtin; mod tokenizing; mod parsing; +mod symbol_table; mod typechecking; mod ast_reducing; mod eval; @@ -34,15 +35,16 @@ mod eval; #[PipelineSteps(tokenizing, parsing, symbol_table, typechecking, ast_reducing, eval)] pub struct Schala { state: eval::State<'static>, - type_context: Rc>, + symbol_table: Rc>, + //type_context } impl 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 { - type_context: type_context.clone(), - state: eval::State::new(type_context), + symbol_table: symbols.clone(), + state: eval::State::new(symbols), } } } @@ -74,10 +76,10 @@ fn parsing(_handle: &mut Schala, input: Vec, comp: Option<&mu } fn symbol_table(handle: &mut Schala, input: parsing::AST, comp: Option<&mut UnfinishedComputation>) -> Result { - 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 { 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)); 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 { + /* match handle.type_context.borrow_mut().type_check_ast(&input) { Ok(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) } fn ast_reducing(_handle: &mut Schala, input: parsing::AST, comp: Option<&mut UnfinishedComputation>) -> Result { diff --git a/schala-lang/src/symbol_table.rs b/schala-lang/src/symbol_table.rs new file mode 100644 index 0000000..4aa9672 --- /dev/null +++ b/schala-lang/src/symbol_table.rs @@ -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, 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, + 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 + } +} diff --git a/schala-lang/src/typechecking.rs b/schala-lang/src/typechecking.rs index de012a9..1553ac3 100644 --- a/schala-lang/src/typechecking.rs +++ b/schala-lang/src/typechecking.rs @@ -8,7 +8,6 @@ use std::fmt::Write; use itertools::Itertools; - /* 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 { environment: TypeEnvironment, - pub symbol_table: SymbolTable } -//cf. p. 150 or so of Language Implementation Patterns -pub struct SymbolTable { - pub values: HashMap, 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, - pub spec: SymbolSpec, -} - -#[derive(Debug)] -pub enum SymbolSpec { - Func, Custom(String) -} - - /* real meat of type stuff here */ #[derive(Debug, PartialEq, Clone)] @@ -214,53 +189,9 @@ pub type TypeResult = Result; impl 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 { let ref block = ast.0;