Compare commits

8 Commits

Author SHA1 Message Date
greg
e0df4bda86 Add block enter/exit methods 2019-11-14 18:09:11 -08:00
greg
5bbbcfa676 Add note 2019-11-13 18:47:27 -08:00
greg
ad385d2f4f rename function 2019-11-11 03:53:51 -08:00
greg
2d0f558415 remove comment 2019-11-11 03:32:40 -08:00
greg
a36be407ca Add tuple thing 2019-11-11 03:31:49 -08:00
greg
a7cad3b88e Try associated type 2019-11-11 02:55:00 -08:00
greg
4b8f1c35b6 ExpressionVisitor correctly normalizing code 2019-11-11 02:44:17 -08:00
greg
1bc684fa15 Starting to experiment with a returning-style visitor 2019-11-11 01:57:27 -08:00
5 changed files with 111 additions and 19 deletions

View File

@@ -16,9 +16,6 @@
}
```
-idea: what if there was something like React jsx syntas built in? i.e. a way to automatically transform some kind of markup
into a function call, cf. `<h1 prop="arg">` -> h1(prop=arg)
## General code cleanup
- I think I can restructure the parser to get rid of most instances of expect!, at least at the beginning of a rule
DONE -experiment with storing metadata via ItemIds on AST nodes (cf. https://rust-lang.github.io/rustc-guide/hir.html, https://github.com/rust-lang/rust/blob/master/src/librustc/hir/mod.rs )

View File

@@ -5,10 +5,9 @@ use crate::ast::*;
//or a tuple of (T, <that type>)
pub trait ASTVisitor: Sized {
type BlockHandler: BlockVisitor = ();
fn ast(&mut self, _ast: &AST) {}
fn block(&mut self) -> Self::BlockHandler { Self::BlockHandler::new() }
fn block_finished(&mut self, handler: Self::BlockHandler) {}
fn enter_block(&mut self, _statements: &Vec<Statement>) {}
fn exit_block(&mut self, _statements: &Vec<Statement>) {}
fn statement(&mut self, _statement: &Statement) {}
fn declaration(&mut self, _declaration: &Declaration) {}
fn signature(&mut self, _signature: &Signature) {}
@@ -42,14 +41,52 @@ pub trait ASTVisitor: Sized {
fn pattern(&mut self, _pat: &Pattern) {}
}
pub trait BlockVisitor {
fn new() -> Self;
fn pre_block(&mut self) {}
fn post_block(&mut self) {}
pub enum VisitorOutput<T, E> {
NotImplemented,
Ok(T),
Err(E)
}
impl BlockVisitor for () {
fn new() -> () { () }
//TODO - cf. the example about "Tree Construction Visitors", every enum type needs its own Visitor
//trait
pub trait ExpressionVisitor {
type Output;
fn type_anno(&mut self, _anno: &TypeIdentifier) -> Self::Output;
fn nat_literal(&mut self, _value: &u64) -> Self::Output;
fn string_literal(&mut self, _value: &Rc<String>) -> Self::Output;
fn binexp(&mut self, _op: &BinOp, _lhs_resul: Self::Output, _rhs_result: Self::Output) -> Self::Output;
fn tuple_literal(&mut self, _items: Vec<Self::Output>) -> Self::Output;
fn visit_statement(&mut self) -> StatementVisitor<Output=Self::Output>;
fn done(&mut self, kind: Self::Output, anno: Option<Self::Output>) -> Self::Output;
}
pub trait StatementVisitor {
type Output;
fn expression(&mut self) -> Self::Output;
fn declaration(&mut self, &Declaration) -> Self::Output;
}
pub fn dispatch_expression<T>(input: &Expression, visitor: &mut dyn ExpressionVisitor<Output=T>) -> Result<T, String> {
let output = match input.kind {
ExpressionKind::NatLiteral(ref n) => visitor.nat_literal(n),
ExpressionKind::StringLiteral(ref s) => visitor.string_literal(s),
ExpressionKind::BinExp(ref op, ref lhs, ref rhs) => {
let lhs = dispatch_expression(lhs, visitor)?;
let rhs = dispatch_expression(rhs, visitor)?;
visitor.binexp(op, lhs, rhs)
},
ExpressionKind::TupleLiteral(ref exprs) => {
let mut output = vec![];
for ex in exprs {
output.push(dispatch_expression(&ex, visitor)?);
}
visitor.tuple_literal(output)
},
_ => return Err(format!("Lol not done yet!")),
};
let type_output = input.type_anno.as_ref().map(|anno| visitor.type_anno(anno));
Ok(visitor.done(output, type_output))
}

View File

@@ -1,6 +1,7 @@
#![cfg(test)]
use crate::ast::visitor::ASTVisitor;
use crate::ast::*;
use crate::ast::visitor::*;
use crate::ast::walker;
use crate::util::quick_ast;
@@ -39,3 +40,61 @@ fn heh() {
assert_eq!(tester.count, 6);
assert_eq!(tester.float_count, 1);
}
struct ExprPrinter {
}
impl ExpressionVisitor for ExprPrinter {
type Output = String;
fn type_anno(&mut self, _anno: &TypeIdentifier) -> String {
"Any".to_string()
}
fn nat_literal(&mut self, n: &u64) -> String {
format!("{}", n)
}
fn string_literal(&mut self, s: &Rc<String>) -> String {
format!("\"{}\"", s)
}
fn binexp(&mut self, op: &BinOp, lhs_result: String, rhs_result: String) -> String {
format!("{} {} {}", lhs_result, op.sigil().to_string(), rhs_result)
}
fn tuple_literal(&mut self, items: Vec<String>) -> String {
let mut buf = String::new();
buf.push('(');
for item in items {
buf.push_str(item.as_str());
buf.push_str(", ");
}
buf.push(')');
buf
}
fn done(&mut self, kind: String, anno: Option<String>) -> String {
match anno {
Some(anno) => format!("{}: {}", kind, anno),
None => format!("{}", kind),
}
}
}
fn make_expr(input: &str) -> Expression {
let (ast, _) = quick_ast(input);
if ast.statements.len() != 1 {
panic!("One statement only!");
}
let expr = match ast.statements[0].kind {
StatementKind::Expression(ref expr) => expr,
_ => panic!("Single statement needs to be an expr!"),
};
expr.clone()
}
#[test]
fn new_visitor() {
let expr: Expression = make_expr("7+\"nueces\"*(33,32)");
let mut printer = ExprPrinter { };
let s = dispatch_expression(&expr, &mut printer).unwrap();
assert_eq!(s, r#"7 + "nueces" * (33, 32, )"#);
}

View File

@@ -1,7 +1,7 @@
#![allow(dead_code)]
use std::rc::Rc;
use crate::ast::*;
use crate::ast::visitor::{ASTVisitor, BlockVisitor};
use crate::ast::visitor::{ASTVisitor, BlockEntry};
use crate::util::deref_optional_box;
pub fn walk_ast<V: ASTVisitor>(v: &mut V, ast: &AST) {
@@ -10,14 +10,12 @@ pub fn walk_ast<V: ASTVisitor>(v: &mut V, ast: &AST) {
}
fn walk_block<V: ASTVisitor>(v: &mut V, block: &Vec<Statement>) {
let mut block_handler = v.block();
block_handler.pre_block();
v.enter_block(&block);
for s in block {
v.statement(s);
statement(v, s);
}
block_handler.post_block();
v.block_finished(block_handler);
v.exit_block(&block);
}
fn statement<V: ASTVisitor>(v: &mut V, statement: &Statement) {

View File

@@ -1,5 +1,6 @@
#![feature(associated_type_defaults)] //needed for Visitor trait
#![feature(trace_macros)]
#![feature(custom_attribute)]
//#![feature(unrestricted_attribute_tokens)]
#![feature(slice_patterns, box_patterns, box_syntax)]
//! `schala-lang` is where the Schala programming language is actually implemented.