diff --git a/schala-lang/language/src/ast.rs b/schala-lang/language/src/ast.rs index 918ca72..5dbf79a 100644 --- a/schala-lang/language/src/ast.rs +++ b/schala-lang/language/src/ast.rs @@ -2,7 +2,9 @@ use std::rc::Rc; use crate::derivative::Derivative; +mod walker; mod visitor; +mod visitor_test; mod operators; pub use operators::*; diff --git a/schala-lang/language/src/ast/visitor.rs b/schala-lang/language/src/ast/visitor.rs index 0fdd0a8..c274379 100644 --- a/schala-lang/language/src/ast/visitor.rs +++ b/schala-lang/language/src/ast/visitor.rs @@ -1,33 +1,68 @@ +use std::rc::Rc; use std::error::Error; use crate::ast::*; +use crate::ast::walker; +//TODO maybe these functions should take closures that return a KeepRecursing | StopHere type, +//or a tuple of (T, ) -pub trait ASTVisitor { - fn visit(&mut self, ast: &mut AST) { - self.block(&ast.statements); +//TODO default implmentations should call walk methods - then I can test printing +pub trait ASTVisitor: Sized { + fn visit(&mut self, ast: &AST) { + println!("FUCK"); + walker::ast(self, ast); } fn block(&mut self, statements: &Vec) { - for statement in statements { - self.statement(statement); - } + println!("oi"); + walker::block(self, statements); } fn statement(&mut self, statement: &Statement) { - use StatementKind::*; - match statement.kind { - Expression(ref expr) => self.expression(expr), - Declaration(ref decl) => self.declaration(decl), - Import(ref import_spec) => self.import(import_spec), - } - } - - fn expression(&mut self, expression: &Expression) { + println!("stmt"); + walker::statement(self, statement); } fn declaration(&mut self, declaration: &Declaration) { + walker::declaration(self, declaration); + } + + fn signature(&mut self, signature: &Signature) { + } + + fn binding(&mut self, name: &Rc, constant: bool, type_anno: Option<&TypeIdentifier>, expr: &Expression) { + walker::maybe_type_identifier(self, type_anno); + walker::expression(self, expr); + } + + fn expression(&mut self, expression: &Expression) { + println!("expr yo"); + walker::expression(self, expression); + } + + fn expression_kind(&mut self, kind: &ExpressionKind) { + walker::expression_kind(self, kind); + } + + fn maybe_type_identifier(&mut self, type_anno: Option<&TypeIdentifier>) { + walker::maybe_type_identifier(self, type_anno); } fn import(&mut self, import: &ImportSpecifier) { } + + fn nat_literal(&mut self, n: u64) {} + fn float_literal(&mut self, f: f64) {} + fn string_literal(&mut self, s: &Rc) {} + fn bool_literal(&mut self, b: bool) {} + fn binexp(&mut self, op: &BinOp, lhs: &Expression, rhs: &Expression) { + walker::expression(self, lhs); + walker::expression(self, rhs); + } + + fn prefix_exp(&mut self, op: &PrefixOp, arg: &Expression) { + walker::expression(self, arg); + } } + + diff --git a/schala-lang/language/src/ast/visitor_test.rs b/schala-lang/language/src/ast/visitor_test.rs new file mode 100644 index 0000000..bda48ad --- /dev/null +++ b/schala-lang/language/src/ast/visitor_test.rs @@ -0,0 +1,36 @@ +#![cfg(test)] + +use crate::ast::visitor::ASTVisitor; +use crate::ast::walker; +use crate::util::quick_ast; + +struct Tester { + count: u64, + float_count: u64 +} + +impl ASTVisitor for Tester { + fn nat_literal(&mut self, _n: u64) { + self.count += 1; + } + fn float_literal(&mut self, _f: f64) { + self.float_count += 1; + } +} + + +#[test] +fn foo() { + let mut tester = Tester { count: 0, float_count: 0 }; + let ast = quick_ast(r#" +import gragh + +let a = 20 + 84 +let b = 28 + 1 + 2 + 2.0 +"#); + + tester.visit(&ast); + + assert_eq!(tester.count, 5); + assert_eq!(tester.float_count, 1); +} diff --git a/schala-lang/language/src/ast/walker.rs b/schala-lang/language/src/ast/walker.rs new file mode 100644 index 0000000..bd1da10 --- /dev/null +++ b/schala-lang/language/src/ast/walker.rs @@ -0,0 +1,112 @@ +use std::rc::Rc; +use crate::ast::*; +use crate::ast::visitor::ASTVisitor; + +pub fn ast(v: &mut V, ast: &AST) { + v.block(&ast.statements); +} + +pub fn block(v: &mut V, block: &Vec) { + for statement in block { + v.statement(statement); + } +} + +pub fn statement(v: &mut V, statement: &Statement) { + use StatementKind::*; + match statement.kind { + Expression(ref expr) => v.expression(expr), + Declaration(ref decl) => v.declaration(decl), + Import(ref import_spec) => v.import(import_spec), + } +} + +pub fn declaration(v: &mut V, decl: &Declaration) { + use Declaration::*; + match decl { + FuncSig(sig) => { + v.signature(&sig); + }, + FuncDecl(sig, block) => { + v.signature(&sig); + v.block(&block); + }, + TypeDecl { .. } => unimplemented!(), + TypeAlias(_, _) => unimplemented!(), + Binding { name, constant, type_anno, expr } => { + v.binding(name, *constant, type_anno.as_ref(), expr); + }, + /* + Impl { + type_name: TypeIdentifier, + interface_name: Option, + block: Vec, + }, + Interface { + name: Rc, + signatures: Vec + } + */ + _ => (), + } +} + +pub fn expression(v: &mut V, expression: &Expression) { + v.expression_kind(&expression.kind); + v.maybe_type_identifier(expression.type_anno.as_ref()); +} + +pub fn maybe_type_identifier(v: &mut V, maybe_ty_identifier: Option<&TypeIdentifier>) { + +} + +pub fn expression_kind(v: &mut V, expression_kind: &ExpressionKind) { + use ExpressionKind::*; + match expression_kind { + NatLiteral(n) => v.nat_literal(*n), + FloatLiteral(f) => v.float_literal(*f), + StringLiteral(s) => v.string_literal(s), + BoolLiteral(b) => v.bool_literal(*b), + BinExp(op, lhs, rhs) => v.binexp(op, lhs, rhs), + PrefixExp(op, arg) => v.prefix_exp(op, arg), + _ => (), + } + /* + TupleLiteral(Vec), + Value(QualifiedName), + NamedStruct { + name: QualifiedName, + fields: Vec<(Rc, Expression)>, + }, + Call { + f: Box, + arguments: Vec, + }, + Index { + indexee: Box, + indexers: Vec, + }, + IfExpression { + discriminator: Box, + body: Box, + }, + WhileExpression { + condition: Option>, + body: Block, + }, + ForExpression { + enumerators: Vec, + body: Box, + }, + Lambda { + params: Vec, + type_anno: Option, + body: Block, + }, + ListLiteral(Vec), + + } + */ +} + +