Move everything symbol-table-related into a separate module
This commit is contained in:
parent
cea7427847
commit
642e9da8ee
@ -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()));
|
||||||
|
@ -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> {
|
||||||
|
70
schala-lang/src/symbol_table.rs
Normal file
70
schala-lang/src/symbol_table.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user