mirror of
https://github.com/azur1s/bobbylisp.git
synced 2024-10-16 02:37:40 -05:00
Pipe operator
This commit is contained in:
parent
8de2629269
commit
9a649db22a
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -212,10 +212,6 @@ dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ir"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is-terminal"
|
name = "is-terminal"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
|
|
|
@ -4,5 +4,4 @@ members = [
|
||||||
"bin",
|
"bin",
|
||||||
"syntax",
|
"syntax",
|
||||||
"typing",
|
"typing",
|
||||||
"ir",
|
|
||||||
]
|
]
|
|
@ -1,8 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "ir"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
190
ir/src/lib.rs
190
ir/src/lib.rs
|
@ -1,190 +0,0 @@
|
||||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
enum IRExpr<'src> {
|
|
||||||
Int(i64),
|
|
||||||
Var(&'src str),
|
|
||||||
Call(&'src str, Vec<Self>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for IRExpr<'_> {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
|
||||||
match self {
|
|
||||||
IRExpr::Int(x) => write!(f, "{x}"),
|
|
||||||
IRExpr::Var(x) => write!(f, "{x}"),
|
|
||||||
IRExpr::Call(name, args) => {
|
|
||||||
write!(f, "{name}(")?;
|
|
||||||
for (i, arg) in args.iter().enumerate() {
|
|
||||||
if i > 0 { write!(f, ", ")?; }
|
|
||||||
write!(f, "{arg}")?;
|
|
||||||
}
|
|
||||||
write!(f, ")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
enum IR<'src> {
|
|
||||||
Define {
|
|
||||||
name: &'src str,
|
|
||||||
value: Box<IRExpr<'src>>,
|
|
||||||
},
|
|
||||||
IRExpr(IRExpr<'src>),
|
|
||||||
Block {
|
|
||||||
id: usize,
|
|
||||||
body: Vec<Self>,
|
|
||||||
},
|
|
||||||
Func {
|
|
||||||
name: &'src str,
|
|
||||||
args: Vec<&'src str>,
|
|
||||||
body: Vec<Self>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
fn display_ir(ir: &IR, indent: usize) -> String {
|
|
||||||
let mut s = String::new();
|
|
||||||
for _ in 0..indent { s.push(' '); }
|
|
||||||
match ir {
|
|
||||||
IR::Define { name, value } => s.push_str(&format!("{name} = {value}")),
|
|
||||||
IR::IRExpr(expr) => s.push_str(&format!("{expr}")),
|
|
||||||
IR::Block { id, body } => {
|
|
||||||
s.push_str(&format!("{id}:\n"));
|
|
||||||
for ir in body {
|
|
||||||
s.push_str(&display_ir(ir, indent + 4));
|
|
||||||
s.push_str("\n");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
IR::Func { name, args, body } => {
|
|
||||||
s.push_str(&format!("{name} "));
|
|
||||||
for (i, arg) in args.iter().enumerate() {
|
|
||||||
if i > 0 { s.push_str(" "); }
|
|
||||||
s.push_str(&format!("{arg}"));
|
|
||||||
}
|
|
||||||
s.push_str(":\n");
|
|
||||||
for ir in body {
|
|
||||||
s.push_str(&display_ir(ir, indent + 4));
|
|
||||||
s.push_str("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for IR<'_> {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
|
||||||
write!(f, "{}", display_ir(self, 0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::{
|
|
||||||
IR::*,
|
|
||||||
IRExpr::*
|
|
||||||
};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ir() {
|
|
||||||
let fns = [
|
|
||||||
Func {
|
|
||||||
name: "my_add",
|
|
||||||
args: vec!["a", "b"],
|
|
||||||
body: vec![
|
|
||||||
Block {
|
|
||||||
id: 0,
|
|
||||||
body: vec![
|
|
||||||
Define {
|
|
||||||
name: "v0",
|
|
||||||
value: Call(
|
|
||||||
"add",
|
|
||||||
vec![
|
|
||||||
Var("a"),
|
|
||||||
Var("b"),
|
|
||||||
]
|
|
||||||
).into(),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
Func {
|
|
||||||
name: "factorial",
|
|
||||||
args: vec!["n"],
|
|
||||||
body: vec![
|
|
||||||
Block {
|
|
||||||
id: 0,
|
|
||||||
body: vec![
|
|
||||||
Define {
|
|
||||||
name: "v0",
|
|
||||||
value: Call(
|
|
||||||
"eq",
|
|
||||||
vec![
|
|
||||||
Var("n"),
|
|
||||||
Int(1),
|
|
||||||
]
|
|
||||||
).into(),
|
|
||||||
},
|
|
||||||
IRExpr(Call(
|
|
||||||
"jf",
|
|
||||||
vec![
|
|
||||||
Var("v0"),
|
|
||||||
Int(1),
|
|
||||||
]
|
|
||||||
)),
|
|
||||||
IRExpr(Call(
|
|
||||||
"ret",
|
|
||||||
vec![
|
|
||||||
Var("n"),
|
|
||||||
]
|
|
||||||
)),
|
|
||||||
]
|
|
||||||
},
|
|
||||||
Block {
|
|
||||||
id: 1,
|
|
||||||
body: vec![
|
|
||||||
Define {
|
|
||||||
name: "v0",
|
|
||||||
value: Call(
|
|
||||||
"isub",
|
|
||||||
vec![
|
|
||||||
Var("n"),
|
|
||||||
Int(1),
|
|
||||||
]
|
|
||||||
).into(),
|
|
||||||
},
|
|
||||||
Define {
|
|
||||||
name: "v1",
|
|
||||||
value: Call(
|
|
||||||
"call",
|
|
||||||
vec![
|
|
||||||
Var("factorial"),
|
|
||||||
Var("v0"),
|
|
||||||
]
|
|
||||||
).into(),
|
|
||||||
},
|
|
||||||
Define {
|
|
||||||
name: "v2",
|
|
||||||
value: Call(
|
|
||||||
"imul",
|
|
||||||
vec![
|
|
||||||
Var("n"),
|
|
||||||
Var("v1"),
|
|
||||||
]
|
|
||||||
).into(),
|
|
||||||
},
|
|
||||||
IRExpr(Call(
|
|
||||||
"ret",
|
|
||||||
vec![
|
|
||||||
Var("v2"),
|
|
||||||
]
|
|
||||||
)),
|
|
||||||
]
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
fns.iter().for_each(|ir| println!("{}", ir));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +1,4 @@
|
||||||
let mk = fn n = fn x = x + n;
|
let succ = fn x = x + 1;
|
||||||
let f = mk(35);
|
let add = fn a b = a + b;
|
||||||
let res = f(34);
|
|
||||||
|
let res = 10 |> succ |> fn a = add(a, 1) |> add;
|
|
@ -16,6 +16,7 @@ pub enum Token<'src> {
|
||||||
Add, Sub, Mul, Div, Rem,
|
Add, Sub, Mul, Div, Rem,
|
||||||
Eq, Ne, Lt, Gt, Le, Ge,
|
Eq, Ne, Lt, Gt, Le, Ge,
|
||||||
And, Or, Not,
|
And, Or, Not,
|
||||||
|
Pipe,
|
||||||
|
|
||||||
Assign, Comma, Colon, Semicolon,
|
Assign, Comma, Colon, Semicolon,
|
||||||
Open(Delim), Close(Delim),
|
Open(Delim), Close(Delim),
|
||||||
|
@ -47,6 +48,7 @@ impl<'src> Display for Token<'src> {
|
||||||
Token::And => write!(f, "&&"),
|
Token::And => write!(f, "&&"),
|
||||||
Token::Or => write!(f, "||"),
|
Token::Or => write!(f, "||"),
|
||||||
Token::Not => write!(f, "!"),
|
Token::Not => write!(f, "!"),
|
||||||
|
Token::Pipe => write!(f, "|>"),
|
||||||
|
|
||||||
Token::Assign => write!(f, "="),
|
Token::Assign => write!(f, "="),
|
||||||
Token::Comma => write!(f, ","),
|
Token::Comma => write!(f, ","),
|
||||||
|
@ -103,6 +105,7 @@ pub enum BinaryOp {
|
||||||
Add, Sub, Mul, Div, Rem,
|
Add, Sub, Mul, Div, Rem,
|
||||||
And, Or,
|
And, Or,
|
||||||
Eq, Ne, Lt, Le, Gt, Ge,
|
Eq, Ne, Lt, Le, Gt, Ge,
|
||||||
|
Pipe,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for BinaryOp {
|
impl Display for BinaryOp {
|
||||||
|
@ -121,6 +124,7 @@ impl Display for BinaryOp {
|
||||||
BinaryOp::Le => write!(f, "<="),
|
BinaryOp::Le => write!(f, "<="),
|
||||||
BinaryOp::Gt => write!(f, ">"),
|
BinaryOp::Gt => write!(f, ">"),
|
||||||
BinaryOp::Ge => write!(f, ">="),
|
BinaryOp::Ge => write!(f, ">="),
|
||||||
|
BinaryOp::Pipe => write!(f, "|>"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ pub fn lexer<'src>() -> impl Parser<'src, &'src str, Vec<(Token<'src>, Span)>, e
|
||||||
just("()").to(Token::Unit),
|
just("()").to(Token::Unit),
|
||||||
just("\\").to(Token::Lambda),
|
just("\\").to(Token::Lambda),
|
||||||
just("->").to(Token::Arrow),
|
just("->").to(Token::Arrow),
|
||||||
|
just("|>").to(Token::Pipe),
|
||||||
|
|
||||||
just('+').to(Token::Add),
|
just('+').to(Token::Add),
|
||||||
just('-').to(Token::Sub),
|
just('-').to(Token::Sub),
|
||||||
|
@ -324,7 +325,17 @@ pub fn expr_parser<'tokens, 'src: 'tokens>() -> impl Parser<
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
logical
|
let pipe = logical.clone()
|
||||||
|
.foldl(
|
||||||
|
just(Token::Pipe).to(BinaryOp::Pipe)
|
||||||
|
.then(logical).repeated(),
|
||||||
|
|a, (op, b)| {
|
||||||
|
let span = a.1.start..b.1.end;
|
||||||
|
(Expr::Binary(op, boxspan(a), boxspan(b)), span.into())
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
pipe
|
||||||
.labelled("expression")
|
.labelled("expression")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,11 +57,29 @@ impl InferError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
struct Constraint {
|
||||||
|
t1: Type,
|
||||||
|
t2: Type,
|
||||||
|
// Where the constraint was generated, for error reporting
|
||||||
|
span: SimpleSpan,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Constraint {
|
||||||
|
fn new(t1: Type, t2: Type, span: SimpleSpan) -> Self {
|
||||||
|
Self {
|
||||||
|
t1,
|
||||||
|
t2,
|
||||||
|
span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct Infer<'src> {
|
struct Infer<'src> {
|
||||||
env: HashMap<&'src str, Type>,
|
env: HashMap<&'src str, Type>,
|
||||||
subst: Vec<Type>,
|
subst: Vec<Type>,
|
||||||
constraints: Vec<(Type, Type, SimpleSpan)>,
|
constraints: Vec<Constraint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Infer<'src> {
|
impl<'src> Infer<'src> {
|
||||||
|
@ -86,8 +104,8 @@ impl<'src> Infer<'src> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add new constraint
|
/// Add new constraint
|
||||||
fn add_constraint(&mut self, t1: Type, t2: Type, span: SimpleSpan) {
|
fn add_constraint(&mut self, c: Constraint) {
|
||||||
self.constraints.push((t1, t2, span));
|
self.constraints.push(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a type variable occurs in a type
|
/// Check if a type variable occurs in a type
|
||||||
|
@ -112,9 +130,15 @@ impl<'src> Infer<'src> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unify two types
|
/// Unify two types
|
||||||
fn unify(&mut self, t1: Type, t2: Type, s: SimpleSpan) -> Result<(), InferError> {
|
fn unify(&mut self, c: Constraint) -> Result<(), InferError> {
|
||||||
|
macro_rules! constraint {
|
||||||
|
($t1:expr, $t2:expr) => {
|
||||||
|
Constraint::new($t1, $t2, c.span)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
use Type::*;
|
use Type::*;
|
||||||
match (t1, t2) {
|
match (c.t1.clone(), c.t2.clone()) {
|
||||||
// Literal types
|
// Literal types
|
||||||
(Unit, Unit)
|
(Unit, Unit)
|
||||||
| (Bool, Bool)
|
| (Bool, Bool)
|
||||||
|
@ -128,15 +152,15 @@ impl<'src> Infer<'src> {
|
||||||
// unify the substitution with t2
|
// unify the substitution with t2
|
||||||
if let Some(t) = self.subst(i) {
|
if let Some(t) = self.subst(i) {
|
||||||
if t != Var(i) {
|
if t != Var(i) {
|
||||||
return self.unify(t, t2, s);
|
return self.unify(constraint!(t, t2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the variable occurs in t2
|
// If the variable occurs in t2
|
||||||
if self.occurs(i, t2.clone()) {
|
if self.occurs(i, t2.clone()) {
|
||||||
return Err(InferError::new("Infinite type", s)
|
return Err(InferError::new("Infinite type", c.span)
|
||||||
.add_error(format!(
|
.add_error(format!(
|
||||||
"This type contains itself: {}", rename_type(Var(i))
|
"This type contains itself: {}", rename_type(Var(i))
|
||||||
), s));
|
), c.span));
|
||||||
}
|
}
|
||||||
// Set the substitution
|
// Set the substitution
|
||||||
self.subst[i] = t2;
|
self.subst[i] = t2;
|
||||||
|
@ -145,15 +169,15 @@ impl<'src> Infer<'src> {
|
||||||
(t1, Var(i)) => {
|
(t1, Var(i)) => {
|
||||||
if let Some(t) = self.subst(i) {
|
if let Some(t) = self.subst(i) {
|
||||||
if t != Var(i) {
|
if t != Var(i) {
|
||||||
return self.unify(t1, t, s);
|
return self.unify(constraint!(t1, t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.occurs(i, t1.clone()) {
|
if self.occurs(i, t1.clone()) {
|
||||||
return Err(InferError::new("Infinite type", s)
|
return Err(InferError::new("Infinite type", c.span)
|
||||||
.add_error(format!(
|
.add_error(format!(
|
||||||
"This type contains itself: {}",
|
"This type contains itself: {}",
|
||||||
rename_type(Var(i))
|
rename_type(Var(i))
|
||||||
), s));
|
), c.span));
|
||||||
}
|
}
|
||||||
self.subst[i] = t1;
|
self.subst[i] = t1;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -163,53 +187,53 @@ impl<'src> Infer<'src> {
|
||||||
(Func(a1, r1), Func(a2, r2)) => {
|
(Func(a1, r1), Func(a2, r2)) => {
|
||||||
// Check the number of arguments
|
// Check the number of arguments
|
||||||
if a1.len() != a2.len() {
|
if a1.len() != a2.len() {
|
||||||
return Err(InferError::new("Argument length mismatch", s)
|
return Err(InferError::new("Argument length mismatch", c.span)
|
||||||
.add_error(format!(
|
.add_error(format!(
|
||||||
"Expected {} arguments, found {}",
|
"This function should take {} arguments, found {}",
|
||||||
a1.len(), a2.len()
|
a1.len(), a2.len()
|
||||||
), s));
|
), c.span));
|
||||||
}
|
}
|
||||||
// Unify the arguments
|
// Unify the arguments
|
||||||
for (a1, a2) in a1.into_iter().zip(a2.into_iter()) {
|
for (a1, a2) in a1.into_iter().zip(a2.into_iter()) {
|
||||||
self.unify(a1, a2, s)?;
|
self.unify(constraint!(a1, a2))?;
|
||||||
}
|
}
|
||||||
// Unify the return types
|
// Unify the return types
|
||||||
self.unify(*r1, *r2, s)
|
self.unify(constraint!(*r1, *r2))
|
||||||
},
|
},
|
||||||
|
|
||||||
// Tuple
|
// Tuple
|
||||||
(Tuple(t1), Tuple(t2)) => {
|
(Tuple(t1), Tuple(t2)) => {
|
||||||
// Check the number of elements
|
// Check the number of elements
|
||||||
if t1.len() != t2.len() {
|
if t1.len() != t2.len() {
|
||||||
return Err(InferError::new("Tuple length mismatch", s)
|
return Err(InferError::new("Tuple length mismatch", c.span)
|
||||||
.add_error(format!(
|
.add_error(format!(
|
||||||
"Expected {} elements, found {}",
|
"Expected {} elements, found {}",
|
||||||
t1.len(), t2.len()
|
t1.len(), t2.len()
|
||||||
), s));
|
), c.span));
|
||||||
}
|
}
|
||||||
// Unify the elements
|
// Unify the elements
|
||||||
for (t1, t2) in t1.into_iter().zip(t2.into_iter()) {
|
for (t1, t2) in t1.into_iter().zip(t2.into_iter()) {
|
||||||
self.unify(t1, t2, s)?;
|
self.unify(constraint!(t1, t2))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|
|
||||||
// Array
|
// Array
|
||||||
(Array(t1), Array(t2)) => self.unify(*t1, *t2, s),
|
(Array(t1), Array(t2)) => self.unify(constraint!(*t1, *t2)),
|
||||||
|
|
||||||
// The rest will be type mismatch
|
// The rest will be type mismatch
|
||||||
(t1, t2) => Err(InferError::new("Type mismatch", s)
|
(t1, t2) => Err(InferError::new("Type mismatch", c.span)
|
||||||
.add_error(format!(
|
.add_error(format!(
|
||||||
"Expected {}, found {}",
|
"Expected {}, found {}",
|
||||||
rename_type(t1), rename_type(t2)
|
rename_type(t1), rename_type(t2)
|
||||||
), s)),
|
), c.span)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Solve the constraints by unifying them
|
/// Solve the constraints by unifying them
|
||||||
fn solve(&mut self) -> Result<(), InferError> {
|
fn solve(&mut self) -> Result<(), InferError> {
|
||||||
for (t1, t2, span) in self.constraints.clone().into_iter() {
|
for c in self.constraints.clone().into_iter() {
|
||||||
self.unify(t1, t2, span)?;
|
self.unify(c)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -330,25 +354,31 @@ impl<'src> Infer<'src> {
|
||||||
&mut self, e: (Expr<'src>, SimpleSpan), expected: Type
|
&mut self, e: (Expr<'src>, SimpleSpan), expected: Type
|
||||||
) -> (TExpr<'src>, Vec<InferError>) {
|
) -> (TExpr<'src>, Vec<InferError>) {
|
||||||
let span = e.1;
|
let span = e.1;
|
||||||
|
macro_rules! constraint {
|
||||||
|
($ty:expr) => {
|
||||||
|
self.add_constraint(Constraint::new(expected, $ty, span))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
match e.0 {
|
match e.0 {
|
||||||
// Literal values
|
// Literal values
|
||||||
// Push the constraint (expected type to be the literal type) and
|
// Push the constraint (expected type to be the literal type) and
|
||||||
// return the typed expression
|
// return the typed expression
|
||||||
Expr::Lit(l) => match l {
|
Expr::Lit(l) => match l {
|
||||||
Lit::Unit => {
|
Lit::Unit => {
|
||||||
self.add_constraint(expected, Type::Unit, span);
|
constraint!(Type::Unit);
|
||||||
ok!(TExpr::Lit(Lit::Unit))
|
ok!(TExpr::Lit(Lit::Unit))
|
||||||
}
|
}
|
||||||
Lit::Bool(b) => {
|
Lit::Bool(b) => {
|
||||||
self.add_constraint(expected, Type::Bool, span);
|
constraint!(Type::Bool);
|
||||||
ok!(TExpr::Lit(Lit::Bool(b)))
|
ok!(TExpr::Lit(Lit::Bool(b)))
|
||||||
}
|
}
|
||||||
Lit::Int(i) => {
|
Lit::Int(i) => {
|
||||||
self.add_constraint(expected, Type::Int, span);
|
constraint!(Type::Int);
|
||||||
ok!(TExpr::Lit(Lit::Int(i)))
|
ok!(TExpr::Lit(Lit::Int(i)))
|
||||||
}
|
}
|
||||||
Lit::Str(s) => {
|
Lit::Str(s) => {
|
||||||
self.add_constraint(expected, Type::Str, span);
|
constraint!(Type::Str);
|
||||||
ok!(TExpr::Lit(Lit::Str(s)))
|
ok!(TExpr::Lit(Lit::Str(s)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -357,7 +387,7 @@ impl<'src> Infer<'src> {
|
||||||
// The same as literals but the type is looked up in the environment
|
// The same as literals but the type is looked up in the environment
|
||||||
Expr::Ident(ref x) => {
|
Expr::Ident(ref x) => {
|
||||||
if let Some(t) = self.env.get(x) {
|
if let Some(t) = self.env.get(x) {
|
||||||
self.add_constraint(expected, t.clone(), span);
|
constraint!(t.clone());
|
||||||
ok!(TExpr::Ident(x))
|
ok!(TExpr::Ident(x))
|
||||||
} else {
|
} else {
|
||||||
let kind = match &expected {
|
let kind = match &expected {
|
||||||
|
@ -378,7 +408,7 @@ impl<'src> Infer<'src> {
|
||||||
// Numeric operators (Int -> Int)
|
// Numeric operators (Int -> Int)
|
||||||
UnaryOp::Neg => {
|
UnaryOp::Neg => {
|
||||||
let (te, err) = self.infer(unbox!(e), Type::Int);
|
let (te, err) = self.infer(unbox!(e), Type::Int);
|
||||||
self.add_constraint(expected, Type::Int, span);
|
constraint!(Type::Int);
|
||||||
(TExpr::Unary {
|
(TExpr::Unary {
|
||||||
op,
|
op,
|
||||||
expr: (Box::new(te), span),
|
expr: (Box::new(te), span),
|
||||||
|
@ -388,7 +418,7 @@ impl<'src> Infer<'src> {
|
||||||
// Boolean operators (Bool -> Bool)
|
// Boolean operators (Bool -> Bool)
|
||||||
UnaryOp::Not => {
|
UnaryOp::Not => {
|
||||||
let (te, err) = self.infer(unbox!(e), Type::Bool);
|
let (te, err) = self.infer(unbox!(e), Type::Bool);
|
||||||
self.add_constraint(expected, Type::Bool, span);
|
constraint!(Type::Bool);
|
||||||
(TExpr::Unary {
|
(TExpr::Unary {
|
||||||
op,
|
op,
|
||||||
expr: (Box::new(te), span),
|
expr: (Box::new(te), span),
|
||||||
|
@ -407,7 +437,7 @@ impl<'src> Infer<'src> {
|
||||||
let (lt, mut errs0) = self.infer(unbox!(lhs), Type::Int);
|
let (lt, mut errs0) = self.infer(unbox!(lhs), Type::Int);
|
||||||
let (rt, errs1) = self.infer(unbox!(rhs), Type::Int);
|
let (rt, errs1) = self.infer(unbox!(rhs), Type::Int);
|
||||||
errs0.extend(errs1);
|
errs0.extend(errs1);
|
||||||
self.add_constraint(expected, Type::Int, span);
|
constraint!(Type::Int);
|
||||||
(TExpr::Binary {
|
(TExpr::Binary {
|
||||||
op,
|
op,
|
||||||
lhs: (Box::new(lt), lhs.1),
|
lhs: (Box::new(lt), lhs.1),
|
||||||
|
@ -422,7 +452,7 @@ impl<'src> Infer<'src> {
|
||||||
let (lt, mut errs0) = self.infer(unbox!(lhs), Type::Bool);
|
let (lt, mut errs0) = self.infer(unbox!(lhs), Type::Bool);
|
||||||
let (rt, errs1) = self.infer(unbox!(rhs), Type::Bool);
|
let (rt, errs1) = self.infer(unbox!(rhs), Type::Bool);
|
||||||
errs0.extend(errs1);
|
errs0.extend(errs1);
|
||||||
self.add_constraint(expected, Type::Bool, span);
|
constraint!(Type::Bool);
|
||||||
(TExpr::Binary {
|
(TExpr::Binary {
|
||||||
op,
|
op,
|
||||||
lhs: (Box::new(lt), lhs.1),
|
lhs: (Box::new(lt), lhs.1),
|
||||||
|
@ -445,7 +475,7 @@ impl<'src> Infer<'src> {
|
||||||
let (lt, mut errs0) = self.infer(unbox!(lhs), t.clone());
|
let (lt, mut errs0) = self.infer(unbox!(lhs), t.clone());
|
||||||
let (rt, errs1) = self.infer(unbox!(rhs), t);
|
let (rt, errs1) = self.infer(unbox!(rhs), t);
|
||||||
errs0.extend(errs1);
|
errs0.extend(errs1);
|
||||||
self.add_constraint(expected, Type::Bool, span);
|
constraint!(Type::Bool);
|
||||||
(TExpr::Binary {
|
(TExpr::Binary {
|
||||||
op,
|
op,
|
||||||
lhs: (Box::new(lt), lhs.1),
|
lhs: (Box::new(lt), lhs.1),
|
||||||
|
@ -453,6 +483,27 @@ impl<'src> Infer<'src> {
|
||||||
ret_ty: Type::Bool,
|
ret_ty: Type::Bool,
|
||||||
}, errs0)
|
}, errs0)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
BinaryOp::Pipe => {
|
||||||
|
// Since this is parsed with a fold left, the right hand
|
||||||
|
// side should always be a function
|
||||||
|
let t = self.fresh();
|
||||||
|
let (lt, mut errs0) = self.infer(unbox!(lhs), t.clone());
|
||||||
|
// The right hand side should be a function that takes
|
||||||
|
// 1 argument with the type of t
|
||||||
|
let (rt, errs1) = self.infer(
|
||||||
|
unbox!(rhs),
|
||||||
|
Type::Func(vec![t.clone()], Box::new(t.clone())),
|
||||||
|
);
|
||||||
|
errs0.extend(errs1);
|
||||||
|
constraint!(t.clone());
|
||||||
|
(TExpr::Binary {
|
||||||
|
op,
|
||||||
|
lhs: (Box::new(lt), lhs.1),
|
||||||
|
rhs: (Box::new(rt), rhs.1),
|
||||||
|
ret_ty: t,
|
||||||
|
}, errs0)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lambda
|
// Lambda
|
||||||
|
@ -486,12 +537,12 @@ impl<'src> Infer<'src> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push the constraints
|
// Push the constraints
|
||||||
self.add_constraint(expected, Type::Func(
|
constraint!(Type::Func(
|
||||||
xs.clone().into_iter()
|
xs.clone().into_iter()
|
||||||
.map(|x| x.1)
|
.map(|x| x.1)
|
||||||
.collect(),
|
.collect(),
|
||||||
Box::new(rt.clone()),
|
Box::new(rt.clone()),
|
||||||
), span);
|
));
|
||||||
|
|
||||||
(TExpr::Lambda {
|
(TExpr::Lambda {
|
||||||
params: xs,
|
params: xs,
|
||||||
|
@ -580,7 +631,7 @@ impl<'src> Infer<'src> {
|
||||||
self.env.insert(name.clone(), ty.clone());
|
self.env.insert(name.clone(), ty.clone());
|
||||||
let (val_ty, errs) = self.infer(unbox!(value), ty.clone());
|
let (val_ty, errs) = self.infer(unbox!(value), ty.clone());
|
||||||
|
|
||||||
self.constraints.push((expected, Type::Unit, e.1));
|
constraint!(Type::Unit);
|
||||||
|
|
||||||
(TExpr::Define {
|
(TExpr::Define {
|
||||||
name,
|
name,
|
||||||
|
@ -615,11 +666,12 @@ impl<'src> Infer<'src> {
|
||||||
let rt = if void || last.is_none() {
|
let rt = if void || last.is_none() {
|
||||||
// If the block is void or there is no expression,
|
// If the block is void or there is no expression,
|
||||||
// the return type is unit
|
// the return type is unit
|
||||||
self.add_constraint(expected, Type::Unit, span);
|
constraint!(Type::Unit);
|
||||||
Type::Unit
|
Type::Unit
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, the return type is the same as the expected type
|
// Otherwise, the return type is the same as the expected type
|
||||||
self.add_constraint(expected.clone(), last.unwrap(), span);
|
// constraint!(last.unwrap());
|
||||||
|
self.add_constraint(Constraint::new(expected.clone(), last.unwrap(), span));
|
||||||
expected
|
expected
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue