Skip to content

Commit

Permalink
Basic implementation for handling variable declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
Glyphack committed Jul 30, 2023
1 parent e5a0230 commit a74ea67
Show file tree
Hide file tree
Showing 11 changed files with 414 additions and 91 deletions.
69 changes: 69 additions & 0 deletions parser/src/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ impl Node {
}
}

trait GetNode {
fn get_node(&self) -> Node;
}

impl From<Node> for SourceSpan {
fn from(val: Node) -> Self {
Self::new(
Expand Down Expand Up @@ -64,6 +68,37 @@ pub enum Statement {
Match(Match),
}

impl GetNode for Statement {
fn get_node(&self) -> Node {
match self {
Statement::AssignStatement(s) => s.node,
Statement::AnnAssignStatement(s) => s.node,
Statement::AugAssignStatement(s) => s.node,
Statement::ExpressionStatement(s) => s.get_node(),
Statement::Assert(s) => s.node,
Statement::Pass(s) => s.node,
Statement::Delete(s) => s.node,
Statement::Return(s) => s.node,
Statement::Raise(s) => s.node,
Statement::Break(s) => s.node,
Statement::Continue(s) => s.node,
Statement::Import(s) => s.node,
Statement::ImportFrom(s) => s.node,
Statement::Global(s) => s.node,
Statement::Nonlocal(s) => s.node,
Statement::IfStatement(s) => s.node,
Statement::WhileStatement(s) => s.node,
Statement::ForStatement(s) => s.node,
Statement::WithStatement(s) => s.node,
Statement::TryStatement(s) => s.node,
Statement::TryStarStatement(s) => s.node,
Statement::FunctionDef(s) => s.node,
Statement::ClassDef(s) => s.node,
Statement::Match(s) => s.node,
}
}
}

#[derive(Debug, Clone)]
pub struct Assign {
pub node: Node,
Expand Down Expand Up @@ -218,6 +253,40 @@ pub enum Expression {
FormattedValue(Box<FormattedValue>),
}

impl GetNode for Expression {
fn get_node(&self) -> Node {
match self {
Expression::Constant(c) => c.node,
Expression::List(l) => l.node,
Expression::Tuple(t) => t.node,
Expression::Dict(d) => d.node,
Expression::Set(s) => s.node,
Expression::Name(n) => n.node,
Expression::BoolOp(b) => b.node,
Expression::UnaryOp(u) => u.node,
Expression::BinOp(b) => b.node,
Expression::NamedExpr(n) => n.node,
Expression::Yield(y) => y.node,
Expression::YieldFrom(y) => y.node,
Expression::Starred(s) => s.node,
Expression::Generator(g) => g.node,
Expression::ListComp(l) => l.node,
Expression::SetComp(s) => s.node,
Expression::DictComp(d) => d.node,
Expression::Attribute(a) => a.node,
Expression::Subscript(s) => s.node,
Expression::Slice(s) => s.node,
Expression::Call(c) => c.node,
Expression::Await(a) => a.node,
Expression::Compare(c) => c.node,
Expression::Lambda(l) => l.node,
Expression::IfExp(i) => i.node,
Expression::JoinedStr(j) => j.node,
Expression::FormattedValue(f) => f.node,
}
}
}

// https://docs.python.org/3/reference/expressions.html#atom-identifiers
#[derive(Debug, Clone)]
pub struct Name {
Expand Down
4 changes: 1 addition & 3 deletions typechecker/src/ast_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,7 @@ pub trait TraversalVisitor {
fn visit_set(&mut self, s: &Set) {
todo!()
}
fn visit_name(&mut self, n: &Name) {
todo!()
}
fn visit_name(&mut self, n: &Name) {}
fn visit_bool_op(&mut self, b: &BoolOperation) {
todo!()
}
Expand Down
48 changes: 28 additions & 20 deletions typechecker/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,25 +104,33 @@ mod tests {
}

#[test]
fn create_symbol_table() {
let source = "a = 'hello world'\nb = a + 1";
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 => "simple assignment", // the template source code
omit_expression => true // do not include the default expression
}, {
assert_debug_snapshot!(module.symbol_table);
});
fn assign_stmt() {
let sources = vec![
"a = 'hello world'",
"b = a + 1",
"c,d = 1,2",
"a: int = 1",
"a += b",
];
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);
});
}
}
}
7 changes: 7 additions & 0 deletions typechecker/src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ impl<'a> TraversalVisitor for EnderpyFile {
self.defs.push(Statement::AssignStatement(stmt));
}

fn visit_ann_assign(&mut self, a: &parser::ast::AnnAssign) {
let stmt = a.clone();
self.defs.push(Statement::AnnAssignStatement(stmt));
}

fn visit_aug_assign(&mut self, a: &parser::ast::AugAssign) {}

fn visit_import(&mut self, i: &Import) {
let import = i.clone();
self.imports.push(ImportKinds::Import(import));
Expand Down
86 changes: 64 additions & 22 deletions typechecker/src/semantic_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl SemanticAnalyzer {
};
}

fn add_declaration_to_symbol_table(&mut self, name: String, decl: Declaration) {
fn create_symbol(&mut self, name: String, decl: Declaration) {
let symbol_node = SymbolTableNode {
name,
declarations: vec![decl],
Expand All @@ -49,11 +49,42 @@ impl SemanticAnalyzer {
fn current_scope(&self) -> SymbolScope {
SymbolScope::Global
}

fn create_variable_declaration_symbol(
&mut self,
target: &Expression,
value: Option<Expression>,
declaration_path: DeclarationPath,
type_annotation: Option<Expression>,
) {
match target {
Expression::Name(n) => {
let decl = Declaration::Variable(Box::new(Variable {
declaration_path,
scope: self.current_scope(),
type_annotation,
inferred_type_source: value,
is_constant: false,
}));
self.create_symbol(n.id.clone(), decl)
}
Expression::Tuple(t) => {
for elm in t.elements.iter() {
self.create_variable_declaration_symbol(
elm,
value.clone(),
declaration_path.clone(),
type_annotation.clone(),
)
}
}
_ => panic!("cannot assign to {:?} is not supported", target),
}
}
}

impl TraversalVisitor for SemanticAnalyzer {
fn visit_stmt(&mut self, s: &parser::ast::Statement) {
// map all statements and call visit
match s {
parser::ast::Statement::ExpressionStatement(e) => self.visit_expr(e),
parser::ast::Statement::Import(i) => self.visit_import(i),
Expand Down Expand Up @@ -219,7 +250,7 @@ impl TraversalVisitor for SemanticAnalyzer {
}

fn visit_tuple(&mut self, t: &parser::ast::Tuple) {
todo!()
return;
}

fn visit_dict(&mut self, d: &parser::ast::Dict) {
Expand Down Expand Up @@ -321,36 +352,47 @@ impl TraversalVisitor for SemanticAnalyzer {
}

fn visit_assign(&mut self, assign: &parser::ast::Assign) {
let value = &assign.value;
if assign.targets.len() > 1 {
panic!("assignment to multiple targets not implemented")
panic!("multiple assignment not suported");
}
let name_node = match assign.targets.last().unwrap() {
Expression::Name(n) => n,
_ => panic!("assignment to other than name node"),
let target = assign.targets.last().unwrap();
let declaration_path = DeclarationPath {
module_name: self.file.module_name.clone(),
node: assign.node,
};

let declared_name = name_node.id.clone();
let decl = Declaration::Variable(Box::new(Variable {
declaration_path: DeclarationPath {
module_name: self.file.module_name.clone(),
node: assign.node,
},
scope: self.current_scope(),
type_annotation: None,
inferred_type_source: Some(assign.value.clone()),
is_constant: false,
}));
self.add_declaration_to_symbol_table(declared_name, decl);
self.create_variable_declaration_symbol(
target,
Some(value.clone()),
declaration_path,
None,
);

self.visit_expr(&assign.value);
}

fn visit_ann_assign(&mut self, a: &parser::ast::AnnAssign) {
todo!()
let value = &a.value;
let target = &a.target;
let declaration_path = DeclarationPath {
module_name: self.file.module_name.clone(),
node: a.node,
};
self.create_variable_declaration_symbol(
target,
value.clone(),
declaration_path,
Some(a.annotation.clone()),
);

if let Some(val) = &a.value {
self.visit_expr(&val);
}
}

fn visit_aug_assign(&mut self, a: &parser::ast::AugAssign) {
todo!()
self.visit_expr(&a.target);
self.visit_expr(&a.value);
}

fn visit_assert(&mut self, a: &parser::ast::Assert) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,10 @@
---
source: typechecker/src/build.rs
description: simple assignment
description: b = a + 1
---
SymbolTable {
symbol_table_type: Module,
symbols: {
"a": SymbolTableNode {
name: "a",
declarations: [
Variable(
Variable {
declaration_path: DeclarationPath {
module_name: "test",
node: Node {
start: 0,
end: 17,
},
},
scope: Global,
type_annotation: None,
inferred_type_source: Some(
Constant(
Constant {
node: Node {
start: 4,
end: 17,
},
value: Str(
"hello world",
),
},
),
),
is_constant: false,
},
),
],
module_public: false,
module_hidden: false,
implicit: false,
scope: Global,
},
"b": SymbolTableNode {
name: "b",
declarations: [
Expand All @@ -49,8 +13,8 @@ SymbolTable {
declaration_path: DeclarationPath {
module_name: "test",
node: Node {
start: 18,
end: 27,
start: 0,
end: 9,
},
},
scope: Global,
Expand All @@ -59,24 +23,24 @@ SymbolTable {
BinOp(
BinOp {
node: Node {
start: 22,
end: 27,
start: 4,
end: 9,
},
op: Add,
left: Name(
Name {
node: Node {
start: 22,
end: 23,
start: 4,
end: 5,
},
id: "a",
},
),
right: Constant(
Constant {
node: Node {
start: 26,
end: 27,
start: 8,
end: 9,
},
value: Int(
"1",
Expand Down
Loading

0 comments on commit a74ea67

Please sign in to comment.