Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add class definition to symbol table #158

Merged
merged 3 commits into from
Aug 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions scripts/print_symbol_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import symtable

def print_symbol_table_info(symbol_table: symtable.SymbolTable, indent=0):
# Print the information of the current symbol table
print(" " * indent + f"Symbol Table: {symbol_table.get_name()}")
print(" " * (indent + 2) + f"Type: {symbol_table.get_type()}")
print(" " * (indent + 2) + f"Identifier: {symbol_table.get_id()}")
print(" " * (indent + 2) + f"First Line Number: {symbol_table.get_lineno()}")

# Print information specific to Function symbol table
if symbol_table.get_type() == 'function':
function_info = symbol_table.get_parameters(), symbol_table.get_locals(), \
symbol_table.get_globals(), symbol_table.get_nonlocals(), \
symbol_table.get_frees()
print(" " * (indent + 2) + f"Function Info: {function_info}")

# Print information specific to Class symbol table
if symbol_table.get_type() == 'class':
class_methods = symbol_table.get_methods()
print(" " * (indent + 2) + f"Class Methods: {class_methods}")

# Print information about each symbol in the symbol table
for symbol in symbol_table.get_symbols():
print(" " * (indent + 2) + f"Symbol: {symbol.get_name()}")
print(" " * (indent + 4) + f"Referenced: {symbol.is_referenced()}")
print(" " * (indent + 4) + f"Imported: {symbol.is_imported()}")
print(" " * (indent + 4) + f"Parameter: {symbol.is_parameter()}")
print(" " * (indent + 4) + f"Global: {symbol.is_global()}")
print(" " * (indent + 4) + f"Nonlocal: {symbol.is_nonlocal()}")
print(" " * (indent + 4) + f"Declared Global: {symbol.is_declared_global()}")
print(" " * (indent + 4) + f"Local: {symbol.is_local()}")
print(" " * (indent + 4) + f"Annotated: {symbol.is_annotated()}")
print(" " * (indent + 4) + f"Free: {symbol.is_free()}")
print(" " * (indent + 4) + f"Assigned: {symbol.is_assigned()}")
print(" " * (indent + 4) + f"Namespace: {symbol.is_namespace()}")
print(" " * (indent + 4) + f"Namespaces: {symbol.get_namespaces()}")
# print namespaces (redundant because repeated in children)
# for namespace in symbol.get_namespaces():
# print(" " * (indent + 6) + f"Namespace: {namespace}")
# print_symbol_table_info(namespace, indent + 8)

# Recursively print information of child symbol tables
for child_table in symbol_table.get_children():
print_symbol_table_info(child_table, indent + 2)

# Example usage:
code = """
a = 1
"""
symbol_table = symtable.symtable(code, "example", "exec")
print_symbol_table_info(symbol_table)

30 changes: 30 additions & 0 deletions typechecker/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,36 @@ mod tests {
"def f():
a = 1
return
",
];
for source in sources {
let path = write_temp_source(source);
let mut manager = BuildManager::new(
vec![BuildSource {
path,
module: String::from("test"),
source: source.to_string(),
followed: false,
}],
Settings::test_settings(),
);
manager.build();
let module = manager.modules.values().last().unwrap();
insta::with_settings!({
description => source, // the template source code
omit_expression => true // do not include the default expression
}, {
assert_debug_snapshot!(module.symbol_table);
});
}
}

#[test]
fn test_class_def() {
let sources = vec![
"class c:
def __init__(self):
b = 1
",
];
for source in sources {
Expand Down
5 changes: 5 additions & 0 deletions typechecker/src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,9 @@ impl<'a> TraversalVisitor for EnderpyFile {
let func = f.clone();
self.defs.push(Statement::FunctionDef(func));
}

fn visit_class_def(&mut self, c: &parser::ast::ClassDef) {
let class = c.clone();
self.defs.push(Statement::ClassDef(class));
}
}
31 changes: 27 additions & 4 deletions typechecker/src/semantic_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
ast_visitor::TraversalVisitor,
nodes::EnderpyFile,
symbol_table::{
Declaration, DeclarationPath, Function, SymbolScope, SymbolTable, SymbolTableNode,
Class, Declaration, DeclarationPath, Function, SymbolScope, SymbolTable, SymbolTableNode,
SymbolTableScope, SymbolTableType, Variable,
},
};
Expand Down Expand Up @@ -36,9 +36,6 @@ impl SemanticAnalyzer {
let symbol_node = SymbolTableNode {
name,
declarations: vec![decl],
module_public: false,
module_hidden: false,
implicit: false,
};
self.globals.add_symbol(symbol_node)
}
Expand Down Expand Up @@ -85,6 +82,9 @@ impl SemanticAnalyzer {
)
}
}
Expression::Attribute(_) => print!(
"Ignoring attribute assingment. See https://github.com/Glyphack/enderpy/issues/157"
),
_ => panic!("cannot assign to {:?} is not supported", target),
}
}
Expand Down Expand Up @@ -237,6 +237,7 @@ impl TraversalVisitor for SemanticAnalyzer {
};
self.globals.enter_scope(SymbolTableScope::new(
crate::symbol_table::SymbolTableType::Function,
f.name.clone(),
));
let mut return_statements = vec![];
let mut yeild_statements = vec![];
Expand Down Expand Up @@ -267,9 +268,31 @@ impl TraversalVisitor for SemanticAnalyzer {
}

fn visit_class_def(&mut self, c: &parser::ast::ClassDef) {
let declaration_path = DeclarationPath {
module_name: self.file.module_name.clone(),
node: c.node,
};
self.globals.enter_scope(SymbolTableScope::new(
SymbolTableType::Class,
c.name.clone(),
));
let mut methods = vec![];
for stmt in &c.body {
match stmt {
parser::ast::Statement::FunctionDef(f) => {
methods.push(f.name.clone());
}
_ => (),
}
self.visit_stmt(&stmt);
}
self.globals.exit_scope();

let class_declaration = Declaration::Class(Box::new(Class {
declaration_path,
methods,
}));
self.create_symbol(c.name.clone(), class_declaration);
}

fn visit_match(&mut self, m: &parser::ast::Match) {
Expand Down
4 changes: 0 additions & 4 deletions typechecker/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,11 @@ pub struct Settings {
impl Settings {
pub fn new() -> Result<Self, ConfigError> {
let run_mode = env::var("RUN_MODE").unwrap_or_else(|_| "development".into());

let s = Config::builder()
// Start off by merging in the "default" configuration file
.add_source(File::with_name("examples/hierarchical-env/config/default"))
.build()?;

// Now that we're done, let's access our configuration
println!("debug: {:?}", s.get_bool("debug"));

s.try_deserialize()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ SymbolTable {
SymbolTableScope {
symbol_table_type: Module,
symbols: {
"d": SymbolTableNode {
name: "d",
"c": SymbolTableNode {
name: "c",
declarations: [
Variable(
Variable {
Expand Down Expand Up @@ -63,8 +63,8 @@ SymbolTable {
module_hidden: false,
implicit: false,
},
"c": SymbolTableNode {
name: "c",
"d": SymbolTableNode {
name: "d",
declarations: [
Variable(
Variable {
Expand Down
100 changes: 100 additions & 0 deletions typechecker/src/snapshots/typechecker__build__tests__class_def.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
source: typechecker/src/build.rs
description: "class c:\n def __init__(self):\n b = 1\n"
---
SymbolTable {
scopes: [
SymbolTableScope {
symbol_table_type: Module,
name: "global",
symbols: {
"c": SymbolTableNode {
name: "c",
declarations: [
Class(
Class {
declaration_path: DeclarationPath {
module_name: "test",
node: Node {
start: 0,
end: 46,
},
},
methods: [
"__init__",
],
},
),
],
},
},
},
],
all_scopes: [
SymbolTableScope {
symbol_table_type: Function,
name: "__init__",
symbols: {
"b": SymbolTableNode {
name: "b",
declarations: [
Variable(
Variable {
declaration_path: DeclarationPath {
module_name: "test",
node: Node {
start: 40,
end: 45,
},
},
scope: Global,
type_annotation: None,
inferred_type_source: Some(
Constant(
Constant {
node: Node {
start: 44,
end: 45,
},
value: Int(
"1",
),
},
),
),
is_constant: false,
},
),
],
},
},
},
SymbolTableScope {
symbol_table_type: Class,
name: "c",
symbols: {
"__init__": SymbolTableNode {
name: "__init__",
declarations: [
Function(
Function {
declaration_path: DeclarationPath {
module_name: "test",
node: Node {
start: 12,
end: 46,
},
},
is_method: true,
is_generator: false,
return_statements: [],
yeild_statements: [],
raise_statements: [],
},
),
],
},
},
},
],
}
18 changes: 14 additions & 4 deletions typechecker/src/symbol_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ pub struct SymbolTable {
#[derive(Debug)]
pub struct SymbolTableScope {
pub symbol_table_type: SymbolTableType,
pub name: String,
symbols: HashMap<String, SymbolTableNode>,
}

impl SymbolTableScope {
pub fn new(symbol_table_type: SymbolTableType) -> Self {
pub fn new(symbol_table_type: SymbolTableType, name: String) -> Self {
SymbolTableScope {
symbol_table_type,
name,
symbols: HashMap::new(),
}
}
Expand All @@ -35,9 +37,6 @@ pub enum SymbolTableType {
pub struct SymbolTableNode {
pub name: String,
pub declarations: Vec<Declaration>,
pub module_public: bool,
pub module_hidden: bool,
pub implicit: bool,
}

#[derive(Debug, Clone)]
Expand All @@ -50,6 +49,7 @@ pub struct DeclarationPath {
pub enum Declaration {
Variable(Box<Variable>),
Function(Box<Function>),
Class(Box<Class>),
}

#[derive(Debug)]
Expand All @@ -72,6 +72,14 @@ pub struct Function {
pub raise_statements: Vec<ast::Raise>,
}

#[derive(Debug)]
pub struct Class {
pub declaration_path: DeclarationPath,
// Method names, can be used to look up the function in the symbol table
// of the class
pub methods: Vec<String>,
}

#[derive(Debug, Clone, Copy)]
pub enum SymbolScope {
Global,
Expand All @@ -85,6 +93,7 @@ impl SymbolTable {
let global_scope = SymbolTableScope {
symbol_table_type,
symbols: HashMap::new(),
name: String::from("global"),
};
SymbolTable {
scopes: vec![global_scope],
Expand Down Expand Up @@ -119,6 +128,7 @@ impl SymbolTable {
Some(scope) => self.all_scopes.push(scope),
None => panic!("tried to exit non-existent scope"),
}

}

pub fn add_symbol(&mut self, symbol_node: SymbolTableNode) {
Expand Down
Loading