Compare commits
4 Commits
91a7abf4cd
...
60ddac9774
Author | SHA1 | Date | |
---|---|---|---|
|
60ddac9774 | ||
|
ae6a79077f | ||
|
36f06b38de | ||
|
c9c65b050c |
@ -15,7 +15,7 @@ struct RecursiveDescentFn {
|
||||
impl Fold for RecursiveDescentFn {
|
||||
fn fold_item_fn(&mut self, mut i: syn::ItemFn) -> syn::ItemFn {
|
||||
let box block = i.block;
|
||||
let ref ident = i.ident;
|
||||
let ident = &i.ident;
|
||||
|
||||
let new_block: syn::Block = parse_quote! {
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
mod walker;
|
||||
|
@ -6,26 +6,28 @@ use crate::ast::*;
|
||||
|
||||
pub trait ASTVisitor: Sized {
|
||||
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 declaration(&mut self, _declaration: &Declaration) {}
|
||||
fn signature(&mut self, _signature: &Signature) {}
|
||||
fn type_declaration(&mut self, _name: &TypeSingletonName, _body: &TypeBody, _mutable: bool) {}
|
||||
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 implemention(&mut self, _type_name: &TypeIdentifier, _interface_name: Option<&TypeSingletonName>, _block: &Vec<Declaration>) {}
|
||||
fn interface(&mut self, _name: &Rc<String>, _signatures: &Vec<Signature>) {}
|
||||
fn implemention(&mut self, _type_name: &TypeIdentifier, _interface_name: Option<&TypeSingletonName>, _block: &[ Declaration ]) {}
|
||||
fn interface(&mut self, _name: &Rc<String>, _signatures: &[ Signature ]) {}
|
||||
fn expression(&mut self, _expression: &Expression) {}
|
||||
fn expression_kind(&mut self, _kind: &ExpressionKind) {}
|
||||
fn type_annotation(&mut self, _type_anno: Option<&TypeIdentifier>) {}
|
||||
fn named_struct(&mut self, _name: &QualifiedName, _fields: &Vec<(Rc<String>, Expression)>) {}
|
||||
fn call(&mut self, _f: &Expression, _arguments: &Vec<InvocationArgument>) {}
|
||||
fn index(&mut self, _indexee: &Expression, _indexers: &Vec<Expression>) {}
|
||||
fn named_struct(&mut self, _name: &QualifiedName, _fields: &[ (Rc<String>, Expression) ]) {}
|
||||
fn call(&mut self, _f: &Expression, _arguments: &[ InvocationArgument ]) {}
|
||||
fn index(&mut self, _indexee: &Expression, _indexers: &[ Expression ]) {}
|
||||
fn if_expression(&mut self, _discrim: Option<&Expression>, _body: &IfExpressionBody) {}
|
||||
fn condition_arm(&mut self, _arm: &ConditionArm) {}
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn while_expression(&mut self, _condition: Option<&Expression>, _body: &Block) {}
|
||||
fn for_expression(&mut self, _enumerators: &Vec<Enumerator>, _body: &ForBody) {}
|
||||
fn lambda(&mut self, _params: &Vec<FormalParam>, _type_anno: Option<&TypeIdentifier>, _body: &Block) {}
|
||||
fn for_expression(&mut self, _enumerators: &[ Enumerator ], _body: &ForBody) {}
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn lambda(&mut self, _params: &[ FormalParam ], _type_anno: Option<&TypeIdentifier>, _body: &Block) {}
|
||||
fn invocation_argument(&mut self, _arg: &InvocationArgument) {}
|
||||
fn formal_param(&mut self, _param: &FormalParam) {}
|
||||
fn import(&mut self, _import: &ImportSpecifier) {}
|
||||
|
@ -9,6 +9,7 @@ pub fn walk_ast<V: ASTVisitor>(v: &mut V, ast: &AST) {
|
||||
walk_block(v, &ast.statements);
|
||||
}
|
||||
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn walk_block<V: ASTVisitor>(v: &mut V, block: &Vec<Statement>) {
|
||||
for s in block {
|
||||
v.statement(s);
|
||||
@ -39,12 +40,12 @@ fn declaration<V: ASTVisitor>(v: &mut V, decl: &Declaration) {
|
||||
use Declaration::*;
|
||||
match decl {
|
||||
FuncSig(sig) => {
|
||||
v.signature(&sig);
|
||||
signature(v, &sig);
|
||||
v.signature(sig);
|
||||
signature(v, sig);
|
||||
},
|
||||
FuncDecl(sig, block) => {
|
||||
v.signature(&sig);
|
||||
v.block(&block);
|
||||
v.signature(sig);
|
||||
v.block(block);
|
||||
walk_block(v, block);
|
||||
},
|
||||
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 } => {
|
||||
v.binding(name, *constant, type_anno.as_ref(), expr);
|
||||
v.type_annotation(type_anno.as_ref());
|
||||
v.expression(&expr);
|
||||
expression(v, &expr);
|
||||
v.expression(expr);
|
||||
expression(v, expr);
|
||||
},
|
||||
Impl { type_name, interface_name, 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);
|
||||
expression(v, f);
|
||||
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);
|
||||
for i in indexers.iter() {
|
||||
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);
|
||||
for (_, expr) in fields.iter() {
|
||||
v.expression(expr);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::ptr_arg)]
|
||||
fn lambda<V: ASTVisitor>(v: &mut V, params: &Vec<FormalParam>, type_anno: Option<&TypeIdentifier>, body: &Block) {
|
||||
for param in params {
|
||||
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) {
|
||||
param.default.as_ref().map(|p| {
|
||||
v.expression(p);
|
||||
expression(v, p);
|
||||
});
|
||||
v.type_annotation(param.anno.as_ref());
|
||||
if let Some(p) = param.default.as_ref() {
|
||||
v.expression(p);
|
||||
expression(v, p);
|
||||
};
|
||||
v.type_annotation(param.anno.as_ref());
|
||||
}
|
||||
|
||||
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 } => {
|
||||
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);
|
||||
},
|
||||
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 {
|
||||
SimpleConditional { then_case, else_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 } => {
|
||||
v.pattern(pattern);
|
||||
walk_pattern(v, pattern);
|
||||
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) => {
|
||||
for arm in arms {
|
||||
@ -230,10 +232,10 @@ fn condition_arm<V: ASTVisitor>(v: &mut V, arm: &ConditionArm) {
|
||||
},
|
||||
_ => ()
|
||||
}
|
||||
arm.guard.as_ref().map(|guard| {
|
||||
v.expression(guard);
|
||||
expression(v, guard);
|
||||
});
|
||||
if let Some(guard) = arm.guard.as_ref() {
|
||||
v.expression(guard);
|
||||
expression(v, guard);
|
||||
};
|
||||
v.block(&arm.body);
|
||||
walk_block(v, &arm.body);
|
||||
}
|
||||
|
@ -13,15 +13,15 @@ fn evaluate_all_outputs(input: &str) -> Vec<Result<String, String>> {
|
||||
let reduced = reduce(&ast, &symbol_table);
|
||||
|
||||
let mut state = State::new();
|
||||
let all_output = state.evaluate(reduced, true);
|
||||
all_output
|
||||
|
||||
state.evaluate(reduced, true)
|
||||
}
|
||||
|
||||
macro_rules! test_in_fresh_env {
|
||||
($string:expr, $correct:expr) => {
|
||||
{
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
//! # Parsing
|
||||
//! This module is where the recursive-descent parsing methods live.
|
||||
//!
|
||||
@ -230,15 +232,15 @@ impl TokenHandler {
|
||||
self.peek_n(n).kind
|
||||
}
|
||||
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()
|
||||
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 {
|
||||
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() {
|
||||
Keyword(Type) => self.type_declaration().map(|decl| { StatementKind::Declaration(decl) }),
|
||||
Keyword(Func)=> self.func_declaration().map(|func| { StatementKind::Declaration(func) }),
|
||||
Keyword(Let) => self.binding_declaration().map(|decl| StatementKind::Declaration(decl)),
|
||||
Keyword(Interface) => self.interface_declaration().map(|decl| StatementKind::Declaration(decl)),
|
||||
Keyword(Impl) => self.impl_declaration().map(|decl| StatementKind::Declaration(decl)),
|
||||
Keyword(Import) => self.import_declaration().map(|spec| StatementKind::Import(spec)),
|
||||
Keyword(Module) => self.module_declaration().map(|spec| StatementKind::Module(spec)),
|
||||
Keyword(Let) => self.binding_declaration().map(StatementKind::Declaration),
|
||||
Keyword(Interface) => self.interface_declaration().map(StatementKind::Declaration),
|
||||
Keyword(Impl) => self.impl_declaration().map(StatementKind::Declaration),
|
||||
Keyword(Import) => self.import_declaration().map(StatementKind::Import),
|
||||
Keyword(Module) => self.module_declaration().map(StatementKind::Module),
|
||||
_ => self.expression().map(|expr| { StatementKind::Expression(expr) } ),
|
||||
}?;
|
||||
let id = self.id_store.fresh();
|
||||
@ -417,15 +419,10 @@ impl Parser {
|
||||
|
||||
#[recursive_descent_method]
|
||||
fn type_body(&mut self) -> ParseResult<TypeBody> {
|
||||
let mut variants = Vec::new();
|
||||
variants.push(self.variant_specifier()?);
|
||||
loop {
|
||||
if let Pipe = self.token_handler.peek_kind() {
|
||||
let mut variants = vec![self.variant_specifier()?];
|
||||
while let Pipe = self.token_handler.peek_kind() {
|
||||
self.token_handler.next();
|
||||
variants.push(self.variant_specifier()?);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(TypeBody(variants))
|
||||
}
|
||||
@ -472,7 +469,7 @@ impl Parser {
|
||||
expect!(self, Keyword(Func));
|
||||
let (name, operator) = match self.token_handler.peek_kind() {
|
||||
Operator(s) => {
|
||||
let name = s.clone();
|
||||
let name = s;
|
||||
self.token_handler.next();
|
||||
(name, true)
|
||||
},
|
||||
@ -582,7 +579,7 @@ impl Parser {
|
||||
Colon => Some(self.type_anno()?),
|
||||
_ => 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());
|
||||
}
|
||||
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/
|
||||
#[allow(clippy::while_let_loop)]
|
||||
fn precedence_expr(&mut self, precedence: i32) -> ParseResult<Expression> {
|
||||
let record = ParseRecord {
|
||||
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,
|
||||
};
|
||||
self.parse_level += 1;
|
||||
@ -691,7 +689,7 @@ impl Parser {
|
||||
self.token_handler.next();
|
||||
self.token_handler.next();
|
||||
let expr = self.expression()?;
|
||||
InvocationArgument::Keyword { name: s.clone(), expr }
|
||||
InvocationArgument::Keyword { name: s, expr }
|
||||
},
|
||||
_ => {
|
||||
let expr = self.expression()?;
|
||||
@ -799,14 +797,11 @@ impl Parser {
|
||||
#[recursive_descent_method]
|
||||
fn qualified_identifier(&mut self) -> ParseResult<Vec<Rc<String>>> {
|
||||
let mut components = vec![self.identifier()?];
|
||||
loop {
|
||||
match (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) {
|
||||
(Colon, Colon) => {
|
||||
self.token_handler.next(); self.token_handler.next();
|
||||
components.push(self.identifier()?);
|
||||
},
|
||||
_ => break,
|
||||
}
|
||||
|
||||
while let (Colon, Colon) = (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) {
|
||||
self.token_handler.next();
|
||||
self.token_handler.next();
|
||||
components.push(self.identifier()?);
|
||||
}
|
||||
Ok(components)
|
||||
}
|
||||
@ -1023,7 +1018,7 @@ impl Parser {
|
||||
let pat = self.pattern()?;
|
||||
(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;
|
||||
let x = self.while_cond();
|
||||
self.restrictions.no_struct_literal = false;
|
||||
x?.map(|expr| Box::new(expr))
|
||||
x?.map(Box::new)
|
||||
};
|
||||
let body = self.block()?;
|
||||
Ok(Expression::new(self.id_store.fresh(), WhileExpression {condition, body}))
|
||||
@ -1140,7 +1135,7 @@ impl Parser {
|
||||
StrLiteral {s, ..} => {
|
||||
self.token_handler.next();
|
||||
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),
|
||||
}
|
||||
@ -1180,7 +1175,7 @@ impl Parser {
|
||||
let mut digits = self.digits()?;
|
||||
if let Period = self.token_handler.peek_kind() {
|
||||
self.token_handler.next();
|
||||
digits.push_str(".");
|
||||
digits.push('.');
|
||||
digits.push_str(&self.digits()?);
|
||||
match digits.parse::<f64>() {
|
||||
Ok(f) => Ok(Expression::new(self.id_store.fresh(), FloatLiteral(f))),
|
||||
@ -1211,20 +1206,16 @@ impl Parser {
|
||||
#[recursive_descent_method]
|
||||
fn import_declaration(&mut self) -> ParseResult<ImportSpecifier> {
|
||||
expect!(self, Keyword(Import));
|
||||
let mut path_components = vec![];
|
||||
path_components.push(self.identifier()?);
|
||||
loop {
|
||||
match (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) {
|
||||
(Colon, Colon) => {
|
||||
self.token_handler.next(); self.token_handler.next();
|
||||
if let Identifier(_) = self.token_handler.peek_kind() {
|
||||
let mut path_components = vec![self.identifier()?];
|
||||
|
||||
while let (Colon, Colon) = (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) {
|
||||
self.token_handler.next();
|
||||
self.token_handler.next();
|
||||
if let Identifier(_) = self.token_handler.peek_kind() {
|
||||
path_components.push(self.identifier()?);
|
||||
} else {
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
},
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let imported_names = match self.token_handler.peek_kind() {
|
||||
|
@ -1,4 +1,7 @@
|
||||
#![cfg(test)]
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
#![allow(clippy::vec_init_then_push)]
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::tokenizing::Location;
|
||||
@ -170,12 +173,12 @@ fn parsing_tuples() {
|
||||
parse_test_wrap_ast!("()", exst!(TupleLiteral(vec![])));
|
||||
parse_test_wrap_ast!("(\"hella\", 34)", exst!(
|
||||
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![
|
||||
ex!(binexp!("+", NatLiteral(1), NatLiteral(2))).into(),
|
||||
ex!(StringLiteral(rc!(slough))).into(),
|
||||
ex!(binexp!("+", NatLiteral(1), NatLiteral(2))),
|
||||
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(a, 2 + 2)", exst!(Call
|
||||
{ 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)");
|
||||
|
||||
@ -541,7 +544,7 @@ fn parsing_lambdas() {
|
||||
type_anno: None,
|
||||
body: vec![exst!(s "y")] }
|
||||
)),
|
||||
arguments: vec![inv!(ex!(NatLiteral(1))).into()] })
|
||||
arguments: vec![inv!(ex!(NatLiteral(1)))] })
|
||||
};
|
||||
|
||||
parse_test_wrap_ast! {
|
||||
@ -589,7 +592,7 @@ fn more_advanced_lambdas() {
|
||||
exst! {
|
||||
Call {
|
||||
f: bx!(ex!(Call { f: bx!(ex!(val!("wahoo"))), arguments: vec![] })),
|
||||
arguments: vec![inv!(ex!(NatLiteral(3))).into()],
|
||||
arguments: vec![inv!(ex!(NatLiteral(3)))],
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -92,7 +92,7 @@ impl<'a> ASTVisitor for Resolver<'a> {
|
||||
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);
|
||||
self.symbol_table.id_to_fqsn.insert(qualified_name.id.clone(), fqsn);
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
use itertools::Itertools;
|
||||
use std::{iter::{Iterator, Peekable}, convert::TryFrom, rc::Rc, fmt};
|
||||
use std::convert::TryInto;
|
||||
|
||||
|
||||
/// A location in a particular source file. Note that the
|
||||
/// sizes of the internal unsigned integer types limit
|
||||
/// the size of a source file to 2^32 lines of
|
||||
|
@ -1,5 +1,4 @@
|
||||
use std::rc::Rc;
|
||||
use std::fmt::Write;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use ena::unify::{UnifyKey, InPlaceUnificationTable, UnificationTable, EqUnifyValue};
|
||||
@ -79,19 +78,21 @@ pub enum TypeConst {
|
||||
}
|
||||
|
||||
impl TypeConst {
|
||||
/*
|
||||
#[allow(dead_code)]
|
||||
pub fn to_string(&self) -> String {
|
||||
use self::TypeConst::*;
|
||||
match self {
|
||||
Unit => format!("()"),
|
||||
Nat => format!("Nat"),
|
||||
Int => format!("Int"),
|
||||
Float => format!("Float"),
|
||||
StringT => format!("String"),
|
||||
Bool => format!("Bool"),
|
||||
Ordering => format!("Ordering"),
|
||||
Unit => "()".to_string(),
|
||||
Nat => "Nat".to_string(),
|
||||
Int => "Int".to_string(),
|
||||
Float => "Float".to_string(),
|
||||
StringT => "String".to_string(),
|
||||
Bool => "Bool".to_string(),
|
||||
Ordering => "Ordering".to_string(),
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
impl EqUnifyValue for TypeConst { }
|
||||
@ -110,6 +111,7 @@ macro_rules! ty {
|
||||
|
||||
//TODO find a better way to capture the to/from string logic
|
||||
impl Type {
|
||||
/*
|
||||
#[allow(dead_code)]
|
||||
pub fn to_string(&self) -> String {
|
||||
use self::Type::*;
|
||||
@ -117,7 +119,7 @@ impl Type {
|
||||
Const(c) => c.to_string(),
|
||||
Var(v) => format!("t_{}", v.0),
|
||||
Arrow { params, box ref ret } => {
|
||||
if params.len() == 0 {
|
||||
if params.is_empty() {
|
||||
format!("-> {}", ret.to_string())
|
||||
} else {
|
||||
let mut buf = String::new();
|
||||
@ -128,9 +130,10 @@ impl Type {
|
||||
buf
|
||||
}
|
||||
},
|
||||
Compound { .. } => format!("<some compound type>")
|
||||
Compound { .. } => "<some compound type>".to_string()
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
fn from_string(string: &str) -> Option<Type> {
|
||||
Some(match string {
|
||||
@ -256,7 +259,7 @@ impl<'a> TypeContext<'a> {
|
||||
use self::TypeIdentifier::*;
|
||||
Ok(match name {
|
||||
Singleton(TypeSingletonName { name,.. }) => {
|
||||
match Type::from_string(&name) {
|
||||
match Type::from_string(name) {
|
||||
Some(ty) => ty,
|
||||
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> {
|
||||
match &statement.kind {
|
||||
StatementKind::Expression(e) => self.expr(e),
|
||||
StatementKind::Declaration(decl) => self.decl(&decl),
|
||||
StatementKind::Declaration(decl) => self.decl(decl),
|
||||
StatementKind::Import(_) => Ok(ty!(Unit)),
|
||||
StatementKind::Module(_) => Ok(ty!(Unit)),
|
||||
}
|
||||
@ -287,12 +290,9 @@ impl<'a> TypeContext<'a> {
|
||||
|
||||
fn decl(&mut self, decl: &Declaration) -> InferResult<Type> {
|
||||
use self::Declaration::*;
|
||||
match decl {
|
||||
Binding { name, expr, .. } => {
|
||||
if let Binding { name, expr, .. } = decl {
|
||||
let ty = self.expr(expr)?;
|
||||
self.variable_map.insert(name.clone(), ty);
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
Ok(ty!(Unit))
|
||||
}
|
||||
@ -361,10 +361,11 @@ impl<'a> TypeContext<'a> {
|
||||
use self::IfExpressionBody::*;
|
||||
match (discriminator, body) {
|
||||
(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> {
|
||||
let t1 = self.expr(expr)?;
|
||||
let t2 = self.block(then_clause)?;
|
||||
@ -377,6 +378,7 @@ impl<'a> TypeContext<'a> {
|
||||
self.unify(t2, t3)
|
||||
}
|
||||
|
||||
#[allow(clippy::ptr_arg)]
|
||||
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| {
|
||||
if let FormalParam { anno: Some(type_identifier), .. } = param {
|
||||
@ -394,7 +396,7 @@ impl<'a> TypeContext<'a> {
|
||||
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 arg_types: InferResult<Vec<Type>> = args.iter().map(|ex| self.invoc(ex)).collect();
|
||||
let arg_types = arg_types?;
|
||||
@ -410,10 +412,11 @@ impl<'a> TypeContext<'a> {
|
||||
t_ret.clone()
|
||||
},
|
||||
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> {
|
||||
let mut output = ty!(Unit);
|
||||
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*
|
||||
(a @ Var(_), b @ Const(_)) => self.unify(b, a),
|
||||
(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))))?;
|
||||
Ok(Const(c1.clone()))
|
||||
},
|
||||
(Var(v1), Var(v2)) => {
|
||||
//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| {
|
||||
println!("Unify error: {:?}", e);
|
||||
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)),
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
($string:expr, $type:expr) => {
|
||||
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();
|
||||
assert_eq!(ty, $type)
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use std::cmp::Eq;
|
||||
use std::ops::Deref;
|
||||
|
||||
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)]
|
||||
|
Loading…
Reference in New Issue
Block a user