Compare commits

...

4 Commits

Author SHA1 Message Date
Greg Shuflin
60ddac9774 Rest of clippy lints 2021-10-19 22:29:41 -07:00
Greg Shuflin
ae6a79077f more clippy lints 2021-10-19 22:24:27 -07:00
Greg Shuflin
36f06b38de Automatically apply clippy to various util modules 2021-10-19 21:57:14 -07:00
Greg Shuflin
c9c65b050c Clippy for parsing 2021-10-19 21:55:51 -07:00
11 changed files with 115 additions and 111 deletions

View File

@ -15,7 +15,7 @@ struct RecursiveDescentFn {
impl Fold for RecursiveDescentFn { impl Fold for RecursiveDescentFn {
fn fold_item_fn(&mut self, mut i: syn::ItemFn) -> syn::ItemFn { fn fold_item_fn(&mut self, mut i: syn::ItemFn) -> syn::ItemFn {
let box block = i.block; let box block = i.block;
let ref ident = i.ident; let ident = &i.ident;
let new_block: syn::Block = parse_quote! { let new_block: syn::Block = parse_quote! {
{ {

View File

@ -1,5 +1,7 @@
use std::rc::Rc; #![allow(clippy::upper_case_acronyms)]
#![allow(clippy::enum_variant_names)]
use std::rc::Rc;
use crate::derivative::Derivative; use crate::derivative::Derivative;
mod walker; mod walker;

View File

@ -6,26 +6,28 @@ use crate::ast::*;
pub trait ASTVisitor: Sized { pub trait ASTVisitor: Sized {
fn ast(&mut self, _ast: &AST) {} fn ast(&mut self, _ast: &AST) {}
fn block(&mut self, _statements: &Vec<Statement>) {} fn block(&mut self, _statements: &[ Statement ]) {}
fn statement(&mut self, _statement: &Statement) {} fn statement(&mut self, _statement: &Statement) {}
fn declaration(&mut self, _declaration: &Declaration) {} fn declaration(&mut self, _declaration: &Declaration) {}
fn signature(&mut self, _signature: &Signature) {} fn signature(&mut self, _signature: &Signature) {}
fn type_declaration(&mut self, _name: &TypeSingletonName, _body: &TypeBody, _mutable: bool) {} fn type_declaration(&mut self, _name: &TypeSingletonName, _body: &TypeBody, _mutable: bool) {}
fn type_alias(&mut self, _alias: &Rc<String>, _original: &Rc<String>) {} fn type_alias(&mut self, _alias: &Rc<String>, _original: &Rc<String>) {}
fn binding(&mut self, _name: &Rc<String>, _constant: bool, _type_anno: Option<&TypeIdentifier>, _expr: &Expression) {} fn binding(&mut self, _name: &Rc<String>, _constant: bool, _type_anno: Option<&TypeIdentifier>, _expr: &Expression) {}
fn implemention(&mut self, _type_name: &TypeIdentifier, _interface_name: Option<&TypeSingletonName>, _block: &Vec<Declaration>) {} fn implemention(&mut self, _type_name: &TypeIdentifier, _interface_name: Option<&TypeSingletonName>, _block: &[ Declaration ]) {}
fn interface(&mut self, _name: &Rc<String>, _signatures: &Vec<Signature>) {} fn interface(&mut self, _name: &Rc<String>, _signatures: &[ Signature ]) {}
fn expression(&mut self, _expression: &Expression) {} fn expression(&mut self, _expression: &Expression) {}
fn expression_kind(&mut self, _kind: &ExpressionKind) {} fn expression_kind(&mut self, _kind: &ExpressionKind) {}
fn type_annotation(&mut self, _type_anno: Option<&TypeIdentifier>) {} fn type_annotation(&mut self, _type_anno: Option<&TypeIdentifier>) {}
fn named_struct(&mut self, _name: &QualifiedName, _fields: &Vec<(Rc<String>, Expression)>) {} fn named_struct(&mut self, _name: &QualifiedName, _fields: &[ (Rc<String>, Expression) ]) {}
fn call(&mut self, _f: &Expression, _arguments: &Vec<InvocationArgument>) {} fn call(&mut self, _f: &Expression, _arguments: &[ InvocationArgument ]) {}
fn index(&mut self, _indexee: &Expression, _indexers: &Vec<Expression>) {} fn index(&mut self, _indexee: &Expression, _indexers: &[ Expression ]) {}
fn if_expression(&mut self, _discrim: Option<&Expression>, _body: &IfExpressionBody) {} fn if_expression(&mut self, _discrim: Option<&Expression>, _body: &IfExpressionBody) {}
fn condition_arm(&mut self, _arm: &ConditionArm) {} fn condition_arm(&mut self, _arm: &ConditionArm) {}
#[allow(clippy::ptr_arg)]
fn while_expression(&mut self, _condition: Option<&Expression>, _body: &Block) {} fn while_expression(&mut self, _condition: Option<&Expression>, _body: &Block) {}
fn for_expression(&mut self, _enumerators: &Vec<Enumerator>, _body: &ForBody) {} fn for_expression(&mut self, _enumerators: &[ Enumerator ], _body: &ForBody) {}
fn lambda(&mut self, _params: &Vec<FormalParam>, _type_anno: Option<&TypeIdentifier>, _body: &Block) {} #[allow(clippy::ptr_arg)]
fn lambda(&mut self, _params: &[ FormalParam ], _type_anno: Option<&TypeIdentifier>, _body: &Block) {}
fn invocation_argument(&mut self, _arg: &InvocationArgument) {} fn invocation_argument(&mut self, _arg: &InvocationArgument) {}
fn formal_param(&mut self, _param: &FormalParam) {} fn formal_param(&mut self, _param: &FormalParam) {}
fn import(&mut self, _import: &ImportSpecifier) {} fn import(&mut self, _import: &ImportSpecifier) {}

View File

@ -9,6 +9,7 @@ pub fn walk_ast<V: ASTVisitor>(v: &mut V, ast: &AST) {
walk_block(v, &ast.statements); walk_block(v, &ast.statements);
} }
#[allow(clippy::ptr_arg)]
fn walk_block<V: ASTVisitor>(v: &mut V, block: &Vec<Statement>) { fn walk_block<V: ASTVisitor>(v: &mut V, block: &Vec<Statement>) {
for s in block { for s in block {
v.statement(s); v.statement(s);
@ -39,12 +40,12 @@ fn declaration<V: ASTVisitor>(v: &mut V, decl: &Declaration) {
use Declaration::*; use Declaration::*;
match decl { match decl {
FuncSig(sig) => { FuncSig(sig) => {
v.signature(&sig); v.signature(sig);
signature(v, &sig); signature(v, sig);
}, },
FuncDecl(sig, block) => { FuncDecl(sig, block) => {
v.signature(&sig); v.signature(sig);
v.block(&block); v.block(block);
walk_block(v, block); walk_block(v, block);
}, },
TypeDecl { name, body, mutable } => v.type_declaration(name, body, *mutable), TypeDecl { name, body, mutable } => v.type_declaration(name, body, *mutable),
@ -52,8 +53,8 @@ fn declaration<V: ASTVisitor>(v: &mut V, decl: &Declaration) {
Binding { name, constant, type_anno, expr } => { Binding { name, constant, type_anno, expr } => {
v.binding(name, *constant, type_anno.as_ref(), expr); v.binding(name, *constant, type_anno.as_ref(), expr);
v.type_annotation(type_anno.as_ref()); v.type_annotation(type_anno.as_ref());
v.expression(&expr); v.expression(expr);
expression(v, &expr); expression(v, expr);
}, },
Impl { type_name, interface_name, block } => { Impl { type_name, interface_name, block } => {
v.implemention(type_name, interface_name.as_ref(), block); v.implemention(type_name, interface_name.as_ref(), block);
@ -79,7 +80,7 @@ fn expression<V: ASTVisitor>(v: &mut V, expression: &Expression) {
} }
fn call<V: ASTVisitor>(v: &mut V, f: &Expression, args: &Vec<InvocationArgument>) { fn call<V: ASTVisitor>(v: &mut V, f: &Expression, args: &[ InvocationArgument ]) {
v.expression(f); v.expression(f);
expression(v, f); expression(v, f);
for arg in args.iter() { for arg in args.iter() {
@ -103,20 +104,21 @@ fn invocation_argument<V: ASTVisitor>(v: &mut V, arg: &InvocationArgument) {
} }
} }
fn index<V: ASTVisitor>(v: &mut V, indexee: &Expression, indexers: &Vec<Expression>) { fn index<V: ASTVisitor>(v: &mut V, indexee: &Expression, indexers: &[ Expression ]) {
v.expression(indexee); v.expression(indexee);
for i in indexers.iter() { for i in indexers.iter() {
v.expression(i); v.expression(i);
} }
} }
fn named_struct<V: ASTVisitor>(v: &mut V, n: &QualifiedName, fields: &Vec<(Rc<String>, Expression)>) { fn named_struct<V: ASTVisitor>(v: &mut V, n: &QualifiedName, fields: &[ (Rc<String>, Expression) ]) {
v.qualified_name(n); v.qualified_name(n);
for (_, expr) in fields.iter() { for (_, expr) in fields.iter() {
v.expression(expr); v.expression(expr);
} }
} }
#[allow(clippy::ptr_arg)]
fn lambda<V: ASTVisitor>(v: &mut V, params: &Vec<FormalParam>, type_anno: Option<&TypeIdentifier>, body: &Block) { fn lambda<V: ASTVisitor>(v: &mut V, params: &Vec<FormalParam>, type_anno: Option<&TypeIdentifier>, body: &Block) {
for param in params { for param in params {
v.formal_param(param); v.formal_param(param);
@ -128,11 +130,11 @@ fn lambda<V: ASTVisitor>(v: &mut V, params: &Vec<FormalParam>, type_anno: Option
} }
fn formal_param<V: ASTVisitor>(v: &mut V, param: &FormalParam) { fn formal_param<V: ASTVisitor>(v: &mut V, param: &FormalParam) {
param.default.as_ref().map(|p| { if let Some(p) = param.default.as_ref() {
v.expression(p); v.expression(p);
expression(v, p); expression(v, p);
}); };
v.type_annotation(param.anno.as_ref()); v.type_annotation(param.anno.as_ref());
} }
fn expression_kind<V: ASTVisitor>(v: &mut V, expression_kind: &ExpressionKind) { fn expression_kind<V: ASTVisitor>(v: &mut V, expression_kind: &ExpressionKind) {
@ -172,7 +174,7 @@ fn expression_kind<V: ASTVisitor>(v: &mut V, expression_kind: &ExpressionKind) {
}, },
IfExpression { discriminator, body } => { IfExpression { discriminator, body } => {
v.if_expression(deref_optional_box(discriminator), body); v.if_expression(deref_optional_box(discriminator), body);
discriminator.as_ref().map(|d| expression(v, d)); if let Some(d) = discriminator.as_ref() { expression(v, d) }
if_expression_body(v, body); if_expression_body(v, body);
}, },
WhileExpression { condition, body } => v.while_expression(deref_optional_box(condition), body), WhileExpression { condition, body } => v.while_expression(deref_optional_box(condition), body),
@ -195,13 +197,13 @@ fn if_expression_body<V: ASTVisitor>(v: &mut V, body: &IfExpressionBody) {
match body { match body {
SimpleConditional { then_case, else_case } => { SimpleConditional { then_case, else_case } => {
walk_block(v, then_case); walk_block(v, then_case);
else_case.as_ref().map(|block| walk_block(v, block)); if let Some(block) = else_case.as_ref() { walk_block(v, block) }
}, },
SimplePatternMatch { pattern, then_case, else_case } => { SimplePatternMatch { pattern, then_case, else_case } => {
v.pattern(pattern); v.pattern(pattern);
walk_pattern(v, pattern); walk_pattern(v, pattern);
walk_block(v, then_case); walk_block(v, then_case);
else_case.as_ref().map(|block| walk_block(v, block)); if let Some(block) = else_case.as_ref() { walk_block(v, block) }
}, },
CondList(arms) => { CondList(arms) => {
for arm in arms { for arm in arms {
@ -230,10 +232,10 @@ fn condition_arm<V: ASTVisitor>(v: &mut V, arm: &ConditionArm) {
}, },
_ => () _ => ()
} }
arm.guard.as_ref().map(|guard| { if let Some(guard) = arm.guard.as_ref() {
v.expression(guard); v.expression(guard);
expression(v, guard); expression(v, guard);
}); };
v.block(&arm.body); v.block(&arm.body);
walk_block(v, &arm.body); walk_block(v, &arm.body);
} }

View File

@ -13,15 +13,15 @@ fn evaluate_all_outputs(input: &str) -> Vec<Result<String, String>> {
let reduced = reduce(&ast, &symbol_table); let reduced = reduce(&ast, &symbol_table);
let mut state = State::new(); let mut state = State::new();
let all_output = state.evaluate(reduced, true);
all_output state.evaluate(reduced, true)
} }
macro_rules! test_in_fresh_env { macro_rules! test_in_fresh_env {
($string:expr, $correct:expr) => { ($string:expr, $correct:expr) => {
{ {
let all_output = evaluate_all_outputs($string); let all_output = evaluate_all_outputs($string);
let ref output = all_output.last().unwrap(); let output = &all_output.last().unwrap();
assert_eq!(**output, Ok($correct.to_string())); assert_eq!(**output, Ok($correct.to_string()));
} }
} }

View File

@ -1,3 +1,5 @@
#![allow(clippy::upper_case_acronyms)]
//! # Parsing //! # Parsing
//! This module is where the recursive-descent parsing methods live. //! This module is where the recursive-descent parsing methods live.
//! //!
@ -230,15 +232,15 @@ impl TokenHandler {
self.peek_n(n).kind self.peek_n(n).kind
} }
fn peek(&mut self) -> Token { fn peek(&mut self) -> Token {
self.tokens.get(self.idx).map(|t: &Token| { t.clone()}).unwrap_or(Token { kind: TokenKind::EOF, location: self.end_of_file }) self.tokens.get(self.idx).cloned().unwrap_or(Token { kind: TokenKind::EOF, location: self.end_of_file })
} }
/// calling peek_n(0) is the same thing as peek() /// calling peek_n(0) is the same thing as peek()
fn peek_n(&mut self, n: usize) -> Token { fn peek_n(&mut self, n: usize) -> Token {
self.tokens.get(self.idx + n).map(|t: &Token| { t.clone()}).unwrap_or(Token { kind: TokenKind::EOF, location: self.end_of_file }) self.tokens.get(self.idx + n).cloned().unwrap_or(Token { kind: TokenKind::EOF, location: self.end_of_file })
} }
fn next(&mut self) -> Token { fn next(&mut self) -> Token {
self.idx += 1; self.idx += 1;
self.tokens.get(self.idx - 1).map(|t: &Token| { t.clone() }).unwrap_or(Token { kind: TokenKind::EOF, location: self.end_of_file }) self.tokens.get(self.idx - 1).cloned().unwrap_or(Token { kind: TokenKind::EOF, location: self.end_of_file })
} }
} }
@ -371,11 +373,11 @@ impl Parser {
let kind = match tok.get_kind() { let kind = match tok.get_kind() {
Keyword(Type) => self.type_declaration().map(|decl| { StatementKind::Declaration(decl) }), Keyword(Type) => self.type_declaration().map(|decl| { StatementKind::Declaration(decl) }),
Keyword(Func)=> self.func_declaration().map(|func| { StatementKind::Declaration(func) }), Keyword(Func)=> self.func_declaration().map(|func| { StatementKind::Declaration(func) }),
Keyword(Let) => self.binding_declaration().map(|decl| StatementKind::Declaration(decl)), Keyword(Let) => self.binding_declaration().map(StatementKind::Declaration),
Keyword(Interface) => self.interface_declaration().map(|decl| StatementKind::Declaration(decl)), Keyword(Interface) => self.interface_declaration().map(StatementKind::Declaration),
Keyword(Impl) => self.impl_declaration().map(|decl| StatementKind::Declaration(decl)), Keyword(Impl) => self.impl_declaration().map(StatementKind::Declaration),
Keyword(Import) => self.import_declaration().map(|spec| StatementKind::Import(spec)), Keyword(Import) => self.import_declaration().map(StatementKind::Import),
Keyword(Module) => self.module_declaration().map(|spec| StatementKind::Module(spec)), Keyword(Module) => self.module_declaration().map(StatementKind::Module),
_ => self.expression().map(|expr| { StatementKind::Expression(expr) } ), _ => self.expression().map(|expr| { StatementKind::Expression(expr) } ),
}?; }?;
let id = self.id_store.fresh(); let id = self.id_store.fresh();
@ -417,15 +419,10 @@ impl Parser {
#[recursive_descent_method] #[recursive_descent_method]
fn type_body(&mut self) -> ParseResult<TypeBody> { fn type_body(&mut self) -> ParseResult<TypeBody> {
let mut variants = Vec::new(); let mut variants = vec![self.variant_specifier()?];
variants.push(self.variant_specifier()?); while let Pipe = self.token_handler.peek_kind() {
loop {
if let Pipe = self.token_handler.peek_kind() {
self.token_handler.next(); self.token_handler.next();
variants.push(self.variant_specifier()?); variants.push(self.variant_specifier()?);
} else {
break;
}
} }
Ok(TypeBody(variants)) Ok(TypeBody(variants))
} }
@ -472,7 +469,7 @@ impl Parser {
expect!(self, Keyword(Func)); expect!(self, Keyword(Func));
let (name, operator) = match self.token_handler.peek_kind() { let (name, operator) = match self.token_handler.peek_kind() {
Operator(s) => { Operator(s) => {
let name = s.clone(); let name = s;
self.token_handler.next(); self.token_handler.next();
(name, true) (name, true)
}, },
@ -582,7 +579,7 @@ impl Parser {
Colon => Some(self.type_anno()?), Colon => Some(self.type_anno()?),
_ => None _ => None
}; };
if let Some(_) = expr_body.type_anno { if expr_body.type_anno.is_some() {
return ParseError::new_with_token("Bad parse state encountered", self.token_handler.peek()); return ParseError::new_with_token("Bad parse state encountered", self.token_handler.peek());
} }
expr_body.type_anno = type_anno; expr_body.type_anno = type_anno;
@ -616,10 +613,11 @@ impl Parser {
} }
// this implements Pratt parsing, see http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ // this implements Pratt parsing, see http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/
#[allow(clippy::while_let_loop)]
fn precedence_expr(&mut self, precedence: i32) -> ParseResult<Expression> { fn precedence_expr(&mut self, precedence: i32) -> ParseResult<Expression> {
let record = ParseRecord { let record = ParseRecord {
production_name: "precedence_expr".to_string(), production_name: "precedence_expr".to_string(),
next_token: format!("{}", self.token_handler.peek().to_string_with_metadata()), next_token: self.token_handler.peek().to_string_with_metadata(),
level: self.parse_level, level: self.parse_level,
}; };
self.parse_level += 1; self.parse_level += 1;
@ -691,7 +689,7 @@ impl Parser {
self.token_handler.next(); self.token_handler.next();
self.token_handler.next(); self.token_handler.next();
let expr = self.expression()?; let expr = self.expression()?;
InvocationArgument::Keyword { name: s.clone(), expr } InvocationArgument::Keyword { name: s, expr }
}, },
_ => { _ => {
let expr = self.expression()?; let expr = self.expression()?;
@ -799,14 +797,11 @@ impl Parser {
#[recursive_descent_method] #[recursive_descent_method]
fn qualified_identifier(&mut self) -> ParseResult<Vec<Rc<String>>> { fn qualified_identifier(&mut self) -> ParseResult<Vec<Rc<String>>> {
let mut components = vec![self.identifier()?]; let mut components = vec![self.identifier()?];
loop {
match (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) { while let (Colon, Colon) = (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) {
(Colon, Colon) => { self.token_handler.next();
self.token_handler.next(); self.token_handler.next(); self.token_handler.next();
components.push(self.identifier()?); components.push(self.identifier()?);
},
_ => break,
}
} }
Ok(components) Ok(components)
} }
@ -1023,7 +1018,7 @@ impl Parser {
let pat = self.pattern()?; let pat = self.pattern()?;
(name, pat) (name, pat)
}, },
_ => (name.clone(), Pattern::Literal(PatternLiteral::StringPattern(name.clone()))) _ => (name.clone(), Pattern::Literal(PatternLiteral::StringPattern(name)))
}) })
} }
@ -1054,7 +1049,7 @@ impl Parser {
self.restrictions.no_struct_literal = true; self.restrictions.no_struct_literal = true;
let x = self.while_cond(); let x = self.while_cond();
self.restrictions.no_struct_literal = false; self.restrictions.no_struct_literal = false;
x?.map(|expr| Box::new(expr)) x?.map(Box::new)
}; };
let body = self.block()?; let body = self.block()?;
Ok(Expression::new(self.id_store.fresh(), WhileExpression {condition, body})) Ok(Expression::new(self.id_store.fresh(), WhileExpression {condition, body}))
@ -1140,7 +1135,7 @@ impl Parser {
StrLiteral {s, ..} => { StrLiteral {s, ..} => {
self.token_handler.next(); self.token_handler.next();
let id = self.id_store.fresh(); let id = self.id_store.fresh();
Ok(Expression::new(id, StringLiteral(s.clone()))) Ok(Expression::new(id, StringLiteral(s)))
} }
e => ParseError::new_with_token(format!("Expected a literal expression, got {:?}", e), tok), e => ParseError::new_with_token(format!("Expected a literal expression, got {:?}", e), tok),
} }
@ -1180,7 +1175,7 @@ impl Parser {
let mut digits = self.digits()?; let mut digits = self.digits()?;
if let Period = self.token_handler.peek_kind() { if let Period = self.token_handler.peek_kind() {
self.token_handler.next(); self.token_handler.next();
digits.push_str("."); digits.push('.');
digits.push_str(&self.digits()?); digits.push_str(&self.digits()?);
match digits.parse::<f64>() { match digits.parse::<f64>() {
Ok(f) => Ok(Expression::new(self.id_store.fresh(), FloatLiteral(f))), Ok(f) => Ok(Expression::new(self.id_store.fresh(), FloatLiteral(f))),
@ -1211,20 +1206,16 @@ impl Parser {
#[recursive_descent_method] #[recursive_descent_method]
fn import_declaration(&mut self) -> ParseResult<ImportSpecifier> { fn import_declaration(&mut self) -> ParseResult<ImportSpecifier> {
expect!(self, Keyword(Import)); expect!(self, Keyword(Import));
let mut path_components = vec![]; let mut path_components = vec![self.identifier()?];
path_components.push(self.identifier()?);
loop { while let (Colon, Colon) = (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) {
match (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) { self.token_handler.next();
(Colon, Colon) => { self.token_handler.next();
self.token_handler.next(); self.token_handler.next(); if let Identifier(_) = self.token_handler.peek_kind() {
if let Identifier(_) = self.token_handler.peek_kind() {
path_components.push(self.identifier()?); path_components.push(self.identifier()?);
} else { } else {
break; break;
} }
},
_ => break,
}
} }
let imported_names = match self.token_handler.peek_kind() { let imported_names = match self.token_handler.peek_kind() {

View File

@ -1,4 +1,7 @@
#![cfg(test)] #![cfg(test)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::vec_init_then_push)]
use std::rc::Rc; use std::rc::Rc;
use crate::tokenizing::Location; use crate::tokenizing::Location;
@ -170,12 +173,12 @@ fn parsing_tuples() {
parse_test_wrap_ast!("()", exst!(TupleLiteral(vec![]))); parse_test_wrap_ast!("()", exst!(TupleLiteral(vec![])));
parse_test_wrap_ast!("(\"hella\", 34)", exst!( parse_test_wrap_ast!("(\"hella\", 34)", exst!(
TupleLiteral( TupleLiteral(
vec![ex!(s r#""hella""#).into(), ex!(s "34").into()] vec![ex!(s r#""hella""#), ex!(s "34")]
) )
)); ));
parse_test_wrap_ast!("((1+2), \"slough\")", exst!(TupleLiteral(vec![ parse_test_wrap_ast!("((1+2), \"slough\")", exst!(TupleLiteral(vec![
ex!(binexp!("+", NatLiteral(1), NatLiteral(2))).into(), ex!(binexp!("+", NatLiteral(1), NatLiteral(2))),
ex!(StringLiteral(rc!(slough))).into(), ex!(StringLiteral(rc!(slough))),
]))) ])))
} }
@ -255,7 +258,7 @@ fn parsing_functions() {
parse_test_wrap_ast!("oi()", exst!(Call { f: bx!(ex!(val!("oi"))), arguments: vec![] })); parse_test_wrap_ast!("oi()", exst!(Call { f: bx!(ex!(val!("oi"))), arguments: vec![] }));
parse_test_wrap_ast!("oi(a, 2 + 2)", exst!(Call parse_test_wrap_ast!("oi(a, 2 + 2)", exst!(Call
{ f: bx!(ex!(val!("oi"))), { f: bx!(ex!(val!("oi"))),
arguments: vec![inv!(ex!(val!("a"))), inv!(ex!(binexp!("+", NatLiteral(2), NatLiteral(2)))).into()] arguments: vec![inv!(ex!(val!("a"))), inv!(ex!(binexp!("+", NatLiteral(2), NatLiteral(2))))]
})); }));
parse_error!("a(b,,c)"); parse_error!("a(b,,c)");
@ -541,7 +544,7 @@ fn parsing_lambdas() {
type_anno: None, type_anno: None,
body: vec![exst!(s "y")] } body: vec![exst!(s "y")] }
)), )),
arguments: vec![inv!(ex!(NatLiteral(1))).into()] }) arguments: vec![inv!(ex!(NatLiteral(1)))] })
}; };
parse_test_wrap_ast! { parse_test_wrap_ast! {
@ -589,7 +592,7 @@ fn more_advanced_lambdas() {
exst! { exst! {
Call { Call {
f: bx!(ex!(Call { f: bx!(ex!(val!("wahoo"))), arguments: vec![] })), f: bx!(ex!(Call { f: bx!(ex!(val!("wahoo"))), arguments: vec![] })),
arguments: vec![inv!(ex!(NatLiteral(3))).into()], arguments: vec![inv!(ex!(NatLiteral(3)))],
} }
} }
] ]

View File

@ -92,7 +92,7 @@ impl<'a> ASTVisitor for Resolver<'a> {
self.symbol_table.id_to_fqsn.insert(qualified_name.id.clone(), fqsn); self.symbol_table.id_to_fqsn.insert(qualified_name.id.clone(), fqsn);
} }
fn named_struct(&mut self, qualified_name: &QualifiedName, _fields: &Vec<(Rc<String>, Expression)>) { fn named_struct(&mut self, qualified_name: &QualifiedName, _fields: &[ (Rc<String>, Expression) ]) {
let fqsn = self.lookup_name_in_scope(qualified_name); let fqsn = self.lookup_name_in_scope(qualified_name);
self.symbol_table.id_to_fqsn.insert(qualified_name.id.clone(), fqsn); self.symbol_table.id_to_fqsn.insert(qualified_name.id.clone(), fqsn);
} }

View File

@ -1,8 +1,9 @@
#![allow(clippy::upper_case_acronyms)]
use itertools::Itertools; use itertools::Itertools;
use std::{iter::{Iterator, Peekable}, convert::TryFrom, rc::Rc, fmt}; use std::{iter::{Iterator, Peekable}, convert::TryFrom, rc::Rc, fmt};
use std::convert::TryInto; use std::convert::TryInto;
/// A location in a particular source file. Note that the /// A location in a particular source file. Note that the
/// sizes of the internal unsigned integer types limit /// sizes of the internal unsigned integer types limit
/// the size of a source file to 2^32 lines of /// the size of a source file to 2^32 lines of

View File

@ -1,5 +1,4 @@
use std::rc::Rc; use std::rc::Rc;
use std::fmt::Write;
use std::convert::TryFrom; use std::convert::TryFrom;
use ena::unify::{UnifyKey, InPlaceUnificationTable, UnificationTable, EqUnifyValue}; use ena::unify::{UnifyKey, InPlaceUnificationTable, UnificationTable, EqUnifyValue};
@ -79,19 +78,21 @@ pub enum TypeConst {
} }
impl TypeConst { impl TypeConst {
/*
#[allow(dead_code)] #[allow(dead_code)]
pub fn to_string(&self) -> String { pub fn to_string(&self) -> String {
use self::TypeConst::*; use self::TypeConst::*;
match self { match self {
Unit => format!("()"), Unit => "()".to_string(),
Nat => format!("Nat"), Nat => "Nat".to_string(),
Int => format!("Int"), Int => "Int".to_string(),
Float => format!("Float"), Float => "Float".to_string(),
StringT => format!("String"), StringT => "String".to_string(),
Bool => format!("Bool"), Bool => "Bool".to_string(),
Ordering => format!("Ordering"), Ordering => "Ordering".to_string(),
} }
} }
*/
} }
impl EqUnifyValue for TypeConst { } impl EqUnifyValue for TypeConst { }
@ -110,6 +111,7 @@ macro_rules! ty {
//TODO find a better way to capture the to/from string logic //TODO find a better way to capture the to/from string logic
impl Type { impl Type {
/*
#[allow(dead_code)] #[allow(dead_code)]
pub fn to_string(&self) -> String { pub fn to_string(&self) -> String {
use self::Type::*; use self::Type::*;
@ -117,7 +119,7 @@ impl Type {
Const(c) => c.to_string(), Const(c) => c.to_string(),
Var(v) => format!("t_{}", v.0), Var(v) => format!("t_{}", v.0),
Arrow { params, box ref ret } => { Arrow { params, box ref ret } => {
if params.len() == 0 { if params.is_empty() {
format!("-> {}", ret.to_string()) format!("-> {}", ret.to_string())
} else { } else {
let mut buf = String::new(); let mut buf = String::new();
@ -128,9 +130,10 @@ impl Type {
buf buf
} }
}, },
Compound { .. } => format!("<some compound type>") Compound { .. } => "<some compound type>".to_string()
} }
} }
*/
fn from_string(string: &str) -> Option<Type> { fn from_string(string: &str) -> Option<Type> {
Some(match string { Some(match string {
@ -256,7 +259,7 @@ impl<'a> TypeContext<'a> {
use self::TypeIdentifier::*; use self::TypeIdentifier::*;
Ok(match name { Ok(match name {
Singleton(TypeSingletonName { name,.. }) => { Singleton(TypeSingletonName { name,.. }) => {
match Type::from_string(&name) { match Type::from_string(name) {
Some(ty) => ty, Some(ty) => ty,
None => return TypeError::new(format!("Unknown type name: {}", name)) None => return TypeError::new(format!("Unknown type name: {}", name))
} }
@ -279,7 +282,7 @@ impl<'a> TypeContext<'a> {
fn statement(&mut self, statement: &Statement) -> InferResult<Type> { fn statement(&mut self, statement: &Statement) -> InferResult<Type> {
match &statement.kind { match &statement.kind {
StatementKind::Expression(e) => self.expr(e), StatementKind::Expression(e) => self.expr(e),
StatementKind::Declaration(decl) => self.decl(&decl), StatementKind::Declaration(decl) => self.decl(decl),
StatementKind::Import(_) => Ok(ty!(Unit)), StatementKind::Import(_) => Ok(ty!(Unit)),
StatementKind::Module(_) => Ok(ty!(Unit)), StatementKind::Module(_) => Ok(ty!(Unit)),
} }
@ -287,12 +290,9 @@ impl<'a> TypeContext<'a> {
fn decl(&mut self, decl: &Declaration) -> InferResult<Type> { fn decl(&mut self, decl: &Declaration) -> InferResult<Type> {
use self::Declaration::*; use self::Declaration::*;
match decl { if let Binding { name, expr, .. } = decl {
Binding { name, expr, .. } => {
let ty = self.expr(expr)?; let ty = self.expr(expr)?;
self.variable_map.insert(name.clone(), ty); self.variable_map.insert(name.clone(), ty);
},
_ => (),
} }
Ok(ty!(Unit)) Ok(ty!(Unit))
} }
@ -361,10 +361,11 @@ impl<'a> TypeContext<'a> {
use self::IfExpressionBody::*; use self::IfExpressionBody::*;
match (discriminator, body) { match (discriminator, body) {
(Some(expr), SimpleConditional{ then_case, else_case }) => self.handle_simple_if(expr, then_case, else_case), (Some(expr), SimpleConditional{ then_case, else_case }) => self.handle_simple_if(expr, then_case, else_case),
_ => TypeError::new(format!("Complex conditionals not supported")) _ => TypeError::new("Complex conditionals not supported".to_string())
} }
} }
#[allow(clippy::ptr_arg)]
fn handle_simple_if(&mut self, expr: &Expression, then_clause: &Block, else_clause: &Option<Block>) -> InferResult<Type> { fn handle_simple_if(&mut self, expr: &Expression, then_clause: &Block, else_clause: &Option<Block>) -> InferResult<Type> {
let t1 = self.expr(expr)?; let t1 = self.expr(expr)?;
let t2 = self.block(then_clause)?; let t2 = self.block(then_clause)?;
@ -377,6 +378,7 @@ impl<'a> TypeContext<'a> {
self.unify(t2, t3) self.unify(t2, t3)
} }
#[allow(clippy::ptr_arg)]
fn lambda(&mut self, params: &Vec<FormalParam>, type_anno: &Option<TypeIdentifier>, _body: &Block) -> InferResult<Type> { fn lambda(&mut self, params: &Vec<FormalParam>, type_anno: &Option<TypeIdentifier>, _body: &Block) -> InferResult<Type> {
let argument_types: InferResult<Vec<Type>> = params.iter().map(|param: &FormalParam| { let argument_types: InferResult<Vec<Type>> = params.iter().map(|param: &FormalParam| {
if let FormalParam { anno: Some(type_identifier), .. } = param { if let FormalParam { anno: Some(type_identifier), .. } = param {
@ -394,7 +396,7 @@ impl<'a> TypeContext<'a> {
Ok(ty!(argument_types, ret_type)) Ok(ty!(argument_types, ret_type))
} }
fn call(&mut self, f: &Expression, args: &Vec<InvocationArgument>) -> InferResult<Type> { fn call(&mut self, f: &Expression, args: &[ InvocationArgument ]) -> InferResult<Type> {
let tf = self.expr(f)?; let tf = self.expr(f)?;
let arg_types: InferResult<Vec<Type>> = args.iter().map(|ex| self.invoc(ex)).collect(); let arg_types: InferResult<Vec<Type>> = args.iter().map(|ex| self.invoc(ex)).collect();
let arg_types = arg_types?; let arg_types = arg_types?;
@ -410,10 +412,11 @@ impl<'a> TypeContext<'a> {
t_ret.clone() t_ret.clone()
}, },
Type::Arrow { .. } => return TypeError::new("Wrong length"), Type::Arrow { .. } => return TypeError::new("Wrong length"),
_ => return TypeError::new(format!("Not a function")) _ => return TypeError::new("Not a function".to_string())
}) })
} }
#[allow(clippy::ptr_arg)]
fn block(&mut self, block: &Block) -> InferResult<Type> { fn block(&mut self, block: &Block) -> InferResult<Type> {
let mut output = ty!(Unit); let mut output = ty!(Unit);
for statement in block.iter() { for statement in block.iter() {
@ -438,26 +441,26 @@ impl<'a> TypeContext<'a> {
(Const(ref c1), Const(ref c2)) if c1 == c2 => Ok(Const(c1.clone())), //choice of c1 is arbitrary I *think* (Const(ref c1), Const(ref c2)) if c1 == c2 => Ok(Const(c1.clone())), //choice of c1 is arbitrary I *think*
(a @ Var(_), b @ Const(_)) => self.unify(b, a), (a @ Var(_), b @ Const(_)) => self.unify(b, a),
(Const(ref c1), Var(ref v2)) => { (Const(ref c1), Var(ref v2)) => {
self.unification_table.unify_var_value(v2.clone(), Some(c1.clone())) self.unification_table.unify_var_value(*v2, Some(c1.clone()))
.or_else(|_| TypeError::new(format!("Couldn't unify {:?} and {:?}", Const(c1.clone()), Var(*v2))))?; .or_else(|_| TypeError::new(format!("Couldn't unify {:?} and {:?}", Const(c1.clone()), Var(*v2))))?;
Ok(Const(c1.clone())) Ok(Const(c1.clone()))
}, },
(Var(v1), Var(v2)) => { (Var(v1), Var(v2)) => {
//TODO add occurs check //TODO add occurs check
self.unification_table.unify_var_var(v1.clone(), v2.clone()) self.unification_table.unify_var_var(v1, v2)
.or_else(|e| { .or_else(|e| {
println!("Unify error: {:?}", e); println!("Unify error: {:?}", e);
TypeError::new(format!("Two type variables {:?} and {:?} couldn't unify", v1, v2)) TypeError::new(format!("Two type variables {:?} and {:?} couldn't unify", v1, v2))
})?; })?;
Ok(Var(v1.clone())) //arbitrary decision I think Ok(Var(v1)) //arbitrary decision I think
}, },
(a, b) => TypeError::new(format!("{:?} and {:?} do not unify", a, b)), (a, b) => TypeError::new(format!("{:?} and {:?} do not unify", a, b)),
} }
} }
fn fresh_type_variable(&mut self) -> TypeVar { fn fresh_type_variable(&mut self) -> TypeVar {
let new_type_var = self.unification_table.new_key(None);
new_type_var self.unification_table.new_key(None)
} }
} }
@ -468,7 +471,7 @@ mod typechecking_tests {
macro_rules! assert_type_in_fresh_context { macro_rules! assert_type_in_fresh_context {
($string:expr, $type:expr) => { ($string:expr, $type:expr) => {
let mut tc = TypeContext::new(); let mut tc = TypeContext::new();
let ref ast = crate::util::quick_ast($string); let ast = &crate::util::quick_ast($string);
let ty = tc.typecheck(ast).unwrap(); let ty = tc.typecheck(ast).unwrap();
assert_eq!(ty, $type) assert_eq!(ty, $type)
} }

View File

@ -4,7 +4,7 @@ use std::cmp::Eq;
use std::ops::Deref; use std::ops::Deref;
pub fn deref_optional_box<T>(x: &Option<Box<T>>) -> Option<&T> { pub fn deref_optional_box<T>(x: &Option<Box<T>>) -> Option<&T> {
x.as_ref().map(|b: &Box<T>| Deref::deref(b)) x.as_ref().map(Deref::deref)
} }
#[derive(Default, Debug)] #[derive(Default, Debug)]