Start isolating names into their own thing.
This commit is contained in:
8
src/lambda_lift.rs
Normal file
8
src/lambda_lift.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
use crate::syntax::{Expression, Name};
|
||||||
|
use std::collections::{HashSet, HashMap};
|
||||||
|
|
||||||
|
impl Expression {
|
||||||
|
fn free_variables(&self) -> HashSet<Name> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,6 +66,7 @@ pub mod eval;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod examples;
|
mod examples;
|
||||||
pub mod ir;
|
pub mod ir;
|
||||||
|
pub mod lambda_lift;
|
||||||
pub mod syntax;
|
pub mod syntax;
|
||||||
pub mod type_infer;
|
pub mod type_infer;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|||||||
@@ -134,8 +134,8 @@ impl REPL {
|
|||||||
// if this is a variable binding, and we've never defined this variable before,
|
// if this is a variable binding, and we've never defined this variable before,
|
||||||
// we should tell cranelift about it. this is optimistic; if we fail to compile,
|
// we should tell cranelift about it. this is optimistic; if we fail to compile,
|
||||||
// then we won't use this definition until someone tries again.
|
// then we won't use this definition until someone tries again.
|
||||||
if !self.variable_binding_sites.contains_key(&name.name) {
|
if !self.variable_binding_sites.contains_key(&name.current_name().to_string()) {
|
||||||
self.jitter.define_string(&name.name)?;
|
self.jitter.define_string(name.current_name())?;
|
||||||
self.jitter
|
self.jitter
|
||||||
.define_variable(name.to_string(), ConstantType::U64)?;
|
.define_variable(name.to_string(), ConstantType::U64)?;
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ impl REPL {
|
|||||||
loc.clone(),
|
loc.clone(),
|
||||||
crate::syntax::Name::manufactured("print"),
|
crate::syntax::Name::manufactured("print"),
|
||||||
)),
|
)),
|
||||||
vec![Expression::Reference(loc.clone(), name.name)],
|
vec![Expression::Reference(name.clone())],
|
||||||
)),
|
)),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ pub mod arbitrary;
|
|||||||
mod ast;
|
mod ast;
|
||||||
pub mod eval;
|
pub mod eval;
|
||||||
mod location;
|
mod location;
|
||||||
|
mod name;
|
||||||
mod tokens;
|
mod tokens;
|
||||||
lalrpop_mod!(
|
lalrpop_mod!(
|
||||||
#[allow(clippy::just_underscores_and_digits, clippy::clone_on_copy)]
|
#[allow(clippy::just_underscores_and_digits, clippy::clone_on_copy)]
|
||||||
@@ -44,6 +45,7 @@ mod validate;
|
|||||||
use crate::syntax::arbitrary::GenerationEnvironment;
|
use crate::syntax::arbitrary::GenerationEnvironment;
|
||||||
pub use crate::syntax::ast::*;
|
pub use crate::syntax::ast::*;
|
||||||
pub use crate::syntax::location::Location;
|
pub use crate::syntax::location::Location;
|
||||||
|
pub use crate::syntax::name::Name;
|
||||||
pub use crate::syntax::parser::{ProgramParser, TopLevelParser};
|
pub use crate::syntax::parser::{ProgramParser, TopLevelParser};
|
||||||
pub use crate::syntax::tokens::{LexerError, Token};
|
pub use crate::syntax::tokens::{LexerError, Token};
|
||||||
use lalrpop_util::ParseError;
|
use lalrpop_util::ParseError;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::syntax::ast::{ConstantType, Expression, Name, Program, TopLevel, Value};
|
use crate::syntax::ast::{ConstantType, Expression, Program, TopLevel, Value};
|
||||||
|
use crate::syntax::name::Name;
|
||||||
use crate::syntax::location::Location;
|
use crate::syntax::location::Location;
|
||||||
use proptest::sample::select;
|
use proptest::sample::select;
|
||||||
use proptest::{
|
use proptest::{
|
||||||
@@ -88,10 +89,7 @@ impl Arbitrary for Program {
|
|||||||
Location::manufactured(),
|
Location::manufactured(),
|
||||||
Name::manufactured("print"),
|
Name::manufactured("print"),
|
||||||
)),
|
)),
|
||||||
vec![Expression::Reference(
|
vec![Expression::Reference(n.clone())],
|
||||||
Location::manufactured(),
|
|
||||||
n.to_string(),
|
|
||||||
)],
|
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
items.push(Union::new(printers).boxed());
|
items.push(Union::new(printers).boxed());
|
||||||
@@ -168,12 +166,7 @@ impl Arbitrary for Expression {
|
|||||||
} else {
|
} else {
|
||||||
let mut strats = bound_variables_of_type
|
let mut strats = bound_variables_of_type
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.map(|x| {
|
.map(|x| { Just(Expression::Reference(x.clone())).boxed()
|
||||||
Just(Expression::Reference(
|
|
||||||
Location::manufactured(),
|
|
||||||
x.name.clone(),
|
|
||||||
))
|
|
||||||
.boxed()
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
strats.push(value_strategy);
|
strats.push(value_strategy);
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
use std::fmt;
|
use crate::syntax::name::Name;
|
||||||
use std::hash::Hash;
|
|
||||||
|
|
||||||
use internment::ArcIntern;
|
|
||||||
|
|
||||||
pub use crate::syntax::tokens::ConstantType;
|
|
||||||
use crate::syntax::Location;
|
use crate::syntax::Location;
|
||||||
|
pub use crate::syntax::tokens::ConstantType;
|
||||||
|
|
||||||
/// A structure represented a parsed program.
|
/// A structure represented a parsed program.
|
||||||
///
|
///
|
||||||
@@ -30,56 +26,6 @@ pub enum TopLevel {
|
|||||||
Structure(Location, Name, Vec<(Name, Type)>),
|
Structure(Location, Name, Vec<(Name, Type)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Name.
|
|
||||||
///
|
|
||||||
/// This is basically a string, but annotated with the place the string
|
|
||||||
/// is in the source file.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Name {
|
|
||||||
pub name: String,
|
|
||||||
pub location: Location,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Name {
|
|
||||||
pub fn new<S: ToString>(n: S, location: Location) -> Name {
|
|
||||||
Name {
|
|
||||||
name: n.to_string(),
|
|
||||||
location,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn manufactured<S: ToString>(n: S) -> Name {
|
|
||||||
Name {
|
|
||||||
name: n.to_string(),
|
|
||||||
location: Location::manufactured(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn intern(self) -> ArcIntern<String> {
|
|
||||||
ArcIntern::new(self.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Name {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
self.name == other.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for Name {}
|
|
||||||
|
|
||||||
impl Hash for Name {
|
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.name.hash(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Name {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
self.name.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An expression in the underlying syntax.
|
/// An expression in the underlying syntax.
|
||||||
///
|
///
|
||||||
/// Like statements, these expressions are guaranteed to have been
|
/// Like statements, these expressions are guaranteed to have been
|
||||||
@@ -90,7 +36,7 @@ impl fmt::Display for Name {
|
|||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Value(Location, Value),
|
Value(Location, Value),
|
||||||
Constructor(Location, Name, Vec<(Name, Expression)>),
|
Constructor(Location, Name, Vec<(Name, Expression)>),
|
||||||
Reference(Location, String),
|
Reference(Name),
|
||||||
FieldRef(Location, Box<Expression>, Name),
|
FieldRef(Location, Box<Expression>, Name),
|
||||||
Cast(Location, String, Box<Expression>),
|
Cast(Location, String, Box<Expression>),
|
||||||
Primitive(Location, Name),
|
Primitive(Location, Name),
|
||||||
@@ -130,8 +76,8 @@ impl PartialEq for Expression {
|
|||||||
Expression::Constructor(_, name2, fields2) => name1 == name2 && fields1 == fields2,
|
Expression::Constructor(_, name2, fields2) => name1 == name2 && fields1 == fields2,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
Expression::Reference(_, var1) => match other {
|
Expression::Reference(var1) => match other {
|
||||||
Expression::Reference(_, var2) => var1 == var2,
|
Expression::Reference(var2) => var1 == var2,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
Expression::FieldRef(_, exp1, field1) => match other {
|
Expression::FieldRef(_, exp1, field1) => match other {
|
||||||
@@ -174,7 +120,7 @@ impl Expression {
|
|||||||
match self {
|
match self {
|
||||||
Expression::Value(loc, _) => loc,
|
Expression::Value(loc, _) => loc,
|
||||||
Expression::Constructor(loc, _, _) => loc,
|
Expression::Constructor(loc, _, _) => loc,
|
||||||
Expression::Reference(loc, _) => loc,
|
Expression::Reference(n) => n.location(),
|
||||||
Expression::FieldRef(loc, _, _) => loc,
|
Expression::FieldRef(loc, _, _) => loc,
|
||||||
Expression::Cast(loc, _, _) => loc,
|
Expression::Cast(loc, _, _) => loc,
|
||||||
Expression::Primitive(loc, _) => loc,
|
Expression::Primitive(loc, _) => loc,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::eval::{EvalError, PrimitiveType, Value};
|
use crate::eval::{EvalError, PrimitiveType, Value};
|
||||||
use crate::syntax::{ConstantType, Expression, Name, Program, TopLevel};
|
use crate::syntax::{ConstantType, Expression, Program, TopLevel};
|
||||||
use crate::util::scoped_map::ScopedMap;
|
use crate::util::scoped_map::ScopedMap;
|
||||||
use internment::ArcIntern;
|
use internment::ArcIntern;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -69,9 +69,9 @@ impl Expression {
|
|||||||
Ok(Value::Structure(Some(on.clone().intern()), map))
|
Ok(Value::Structure(Some(on.clone().intern()), map))
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Reference(loc, n) => env
|
Expression::Reference(n) => env
|
||||||
.get(&ArcIntern::new(n.clone()))
|
.get(n.current_interned())
|
||||||
.ok_or_else(|| EvalError::LookupFailed(loc.clone(), n.clone()))
|
.ok_or_else(|| EvalError::LookupFailed(n.location().clone(), n.current_name().to_string()))
|
||||||
.cloned(),
|
.cloned(),
|
||||||
|
|
||||||
Expression::FieldRef(loc, expr, field) => {
|
Expression::FieldRef(loc, expr, field) => {
|
||||||
@@ -102,7 +102,7 @@ impl Expression {
|
|||||||
Ok(target_type.safe_cast(&value)?)
|
Ok(target_type.safe_cast(&value)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression::Primitive(_, op) => Ok(Value::primitive(op.name.clone())),
|
Expression::Primitive(_, op) => Ok(Value::primitive(op.original_name().to_string())),
|
||||||
|
|
||||||
Expression::Call(loc, fun, args) => {
|
Expression::Call(loc, fun, args) => {
|
||||||
let function = fun.eval(stdout, env)?;
|
let function = fun.eval(stdout, env)?;
|
||||||
@@ -129,8 +129,8 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Value::Primitive(name) if name == "print" => {
|
Value::Primitive(name) if name == "print" => {
|
||||||
if let [Expression::Reference(_, name)] = &args[..] {
|
if let [Expression::Reference(name)] = &args[..] {
|
||||||
let value = Expression::Reference(loc.clone(), name.clone())
|
let value = Expression::Reference(name.clone())
|
||||||
.eval(stdout, env)?;
|
.eval(stdout, env)?;
|
||||||
let value = match value {
|
let value = match value {
|
||||||
Value::Number(x) => Value::U64(x),
|
Value::Number(x) => Value::U64(x),
|
||||||
@@ -178,12 +178,12 @@ impl Expression {
|
|||||||
|
|
||||||
Expression::Function(_, name, arg_names, _, body) => {
|
Expression::Function(_, name, arg_names, _, body) => {
|
||||||
let result = Value::Closure(
|
let result = Value::Closure(
|
||||||
name.clone().map(Name::intern),
|
name.as_ref().map(|n| n.current_interned().clone()),
|
||||||
env.clone(),
|
env.clone(),
|
||||||
arg_names
|
arg_names
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|(x, _)| Name::intern(x))
|
.map(|(x, _)| x.current_interned().clone())
|
||||||
.collect(),
|
.collect(),
|
||||||
*body.clone(),
|
*body.clone(),
|
||||||
);
|
);
|
||||||
|
|||||||
113
src/syntax/name.rs
Normal file
113
src/syntax/name.rs
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
use crate::syntax::Location;
|
||||||
|
use internment::ArcIntern;
|
||||||
|
use std::fmt;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
/// The name of a thing in the source language.
|
||||||
|
///
|
||||||
|
/// In many ways, you can treat this like a string, but it's a very tricky
|
||||||
|
/// string in a couple of ways:
|
||||||
|
///
|
||||||
|
/// First, it's a string associated with a particular location in the source
|
||||||
|
/// file, and you can find out what that source location is relatively easily.
|
||||||
|
///
|
||||||
|
/// Second, it's a name that retains something of its identity across renaming,
|
||||||
|
/// so that you can keep track of what a variables original name was, as well as
|
||||||
|
/// what it's new name is if it's been renamed.
|
||||||
|
///
|
||||||
|
/// Finally, when it comes to equality tests, comparisons, and hashing, `Name`
|
||||||
|
/// uses *only* the new name, if the variable has been renamed, or the original
|
||||||
|
/// name, if it has not been renamed. It never uses the location. This allows
|
||||||
|
/// relatively fast hashing and searching for things like binding sites, as the
|
||||||
|
/// value of the binding `Name` will be equal to the bound `Name`, even though
|
||||||
|
/// they occur at different locations.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Name {
|
||||||
|
name: ArcIntern<String>,
|
||||||
|
rename: Option<ArcIntern<String>>,
|
||||||
|
location: Location,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Name {
|
||||||
|
/// Create a new name at the given location.
|
||||||
|
///
|
||||||
|
/// This creates an "original" name, which has not been renamed, at the
|
||||||
|
/// given location.
|
||||||
|
pub fn new<S: ToString>(n: S, location: Location) -> Name {
|
||||||
|
Name {
|
||||||
|
name: ArcIntern::new(n.to_string()),
|
||||||
|
rename: None,
|
||||||
|
location,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new name with no location information.
|
||||||
|
///
|
||||||
|
/// This creates an "original" name, which has not been renamed, at the
|
||||||
|
/// given location. You should always prefer to use [`Location::new`] if
|
||||||
|
/// there is any possible way to get it, because that will be more
|
||||||
|
/// helpful to our users.
|
||||||
|
pub fn manufactured<S: ToString>(n: S) -> Name {
|
||||||
|
Name {
|
||||||
|
name: ArcIntern::new(n.to_string()),
|
||||||
|
rename: None,
|
||||||
|
location: Location::manufactured(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the original name of the variable.
|
||||||
|
///
|
||||||
|
/// Regardless of whether or not the function has been renamed, this will
|
||||||
|
/// return whatever name this variable started with.
|
||||||
|
pub fn original_name(&self) -> &str {
|
||||||
|
self.name.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the current name of the variable.
|
||||||
|
///
|
||||||
|
/// If the variable has been renamed, it will return that, otherwise we'll
|
||||||
|
/// return the current name.
|
||||||
|
pub fn current_name(&self) -> &str {
|
||||||
|
self.rename.as_ref().map(|x| x.as_str()).unwrap_or_else(|| self.name.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the current name of the variable as an interned string.
|
||||||
|
pub fn current_interned(&self) -> &ArcIntern<String> {
|
||||||
|
self.rename.as_ref().unwrap_or(&self.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the location of this name.
|
||||||
|
pub fn location(&self) -> &Location {
|
||||||
|
&self.location
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rename this variable to the given value
|
||||||
|
pub fn rename(&mut self, new_name: &ArcIntern<String>) {
|
||||||
|
self.rename = Some(new_name.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intern(&self) -> ArcIntern<String> {
|
||||||
|
self.current_interned().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Name {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.current_interned() == other.current_interned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for Name {}
|
||||||
|
|
||||||
|
impl Hash for Name {
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.current_interned().hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Name {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.current_name().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -9,7 +9,8 @@
|
|||||||
//! eventually want to leave lalrpop behind.)
|
//! eventually want to leave lalrpop behind.)
|
||||||
//!
|
//!
|
||||||
use crate::syntax::{Location, ParserError};
|
use crate::syntax::{Location, ParserError};
|
||||||
use crate::syntax::ast::{Program,TopLevel,Expression,Value,Name,Type};
|
use crate::syntax::ast::{Program,TopLevel,Expression,Value,Type};
|
||||||
|
use crate::syntax::name::Name;
|
||||||
use crate::syntax::tokens::{ConstantType, Token};
|
use crate::syntax::tokens::{ConstantType, Token};
|
||||||
use internment::ArcIntern;
|
use internment::ArcIntern;
|
||||||
|
|
||||||
@@ -241,7 +242,7 @@ FieldExpression: Expression = {
|
|||||||
// they cannot be further divided into parts
|
// they cannot be further divided into parts
|
||||||
AtomicExpression: Expression = {
|
AtomicExpression: Expression = {
|
||||||
// just a variable reference
|
// just a variable reference
|
||||||
<l: @L> <v:"<var>"> <end: @L> => Expression::Reference(Location::new(file_idx, l..end), v.to_string()),
|
<l: @L> <v:"<var>"> <end: @L> => Expression::Reference(Name::new(v.to_string(), Location::new(file_idx, l..end))),
|
||||||
// just a number
|
// just a number
|
||||||
<l: @L> <n:"<num>"> <end: @L> => Expression::Value(Location::new(file_idx, l..end), Value::Number(n.0, n.1, n.2)),
|
<l: @L> <n:"<num>"> <end: @L> => Expression::Value(Location::new(file_idx, l..end), Value::Number(n.0, n.1, n.2)),
|
||||||
// this expression could actually be a block!
|
// this expression could actually be a block!
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ impl Expression {
|
|||||||
.nest(2)
|
.nest(2)
|
||||||
.braces(),
|
.braces(),
|
||||||
),
|
),
|
||||||
Expression::Reference(_, var) => allocator.text(var.to_string()),
|
Expression::Reference(var) => allocator.text(var.to_string()),
|
||||||
Expression::FieldRef(_, val, field) => val
|
Expression::FieldRef(_, val, field) => val
|
||||||
.pretty(allocator)
|
.pretty(allocator)
|
||||||
.append(allocator.text("."))
|
.append(allocator.text("."))
|
||||||
@@ -76,7 +76,7 @@ impl Expression {
|
|||||||
.text(t.clone())
|
.text(t.clone())
|
||||||
.angles()
|
.angles()
|
||||||
.append(e.pretty(allocator)),
|
.append(e.pretty(allocator)),
|
||||||
Expression::Primitive(_, op) => allocator.text(op.name.clone()),
|
Expression::Primitive(_, op) => allocator.text(op.original_name().to_string()),
|
||||||
Expression::Call(_, fun, args) => {
|
Expression::Call(_, fun, args) => {
|
||||||
let args = args.iter().map(|x| x.pretty(allocator));
|
let args = args.iter().map(|x| x.pretty(allocator));
|
||||||
let comma_sepped_args = allocator.intersperse(args, allocator.text(","));
|
let comma_sepped_args = allocator.intersperse(args, allocator.text(","));
|
||||||
|
|||||||
@@ -141,9 +141,9 @@ impl Expression {
|
|||||||
|
|
||||||
(errors, warnings)
|
(errors, warnings)
|
||||||
}
|
}
|
||||||
Expression::Reference(_, var) if variable_map.contains_key(var) => (vec![], vec![]),
|
Expression::Reference(var) if variable_map.contains_key(&var.original_name().to_string()) => (vec![], vec![]),
|
||||||
Expression::Reference(loc, var) => (
|
Expression::Reference(var) => (
|
||||||
vec![Error::UnboundVariable(loc.clone(), var.clone())],
|
vec![Error::UnboundVariable(var.location().clone(), var.original_name().to_string())],
|
||||||
vec![],
|
vec![],
|
||||||
),
|
),
|
||||||
Expression::FieldRef(_, exp, _) => exp.validate(variable_map),
|
Expression::FieldRef(_, exp, _) => exp.validate(variable_map),
|
||||||
@@ -187,7 +187,7 @@ impl Expression {
|
|||||||
// immediately check the expression, and go from there.
|
// immediately check the expression, and go from there.
|
||||||
let (errors, mut warnings) = val.validate(variable_map);
|
let (errors, mut warnings) = val.validate(variable_map);
|
||||||
|
|
||||||
if let Some(original_binding_site) = variable_map.get(&var.name) {
|
if let Some(original_binding_site) = variable_map.get(&var.original_name().to_string()) {
|
||||||
warnings.push(Warning::ShadowedVariable(
|
warnings.push(Warning::ShadowedVariable(
|
||||||
original_binding_site.clone(),
|
original_binding_site.clone(),
|
||||||
loc.clone(),
|
loc.clone(),
|
||||||
@@ -201,11 +201,11 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
Expression::Function(_, name, arguments, _, body) => {
|
Expression::Function(_, name, arguments, _, body) => {
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
variable_map.insert(name.name.clone(), name.location.clone());
|
variable_map.insert(name.original_name().to_string(), name.location().clone());
|
||||||
}
|
}
|
||||||
variable_map.new_scope();
|
variable_map.new_scope();
|
||||||
for (arg, _) in arguments.iter() {
|
for (arg, _) in arguments.iter() {
|
||||||
variable_map.insert(arg.name.clone(), arg.location.clone());
|
variable_map.insert(arg.original_name().to_string(), arg.location().clone());
|
||||||
}
|
}
|
||||||
let result = body.validate(variable_map);
|
let result = body.validate(variable_map);
|
||||||
variable_map.release_scope();
|
variable_map.release_scope();
|
||||||
|
|||||||
@@ -191,20 +191,21 @@ impl InferenceEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
syntax::Expression::Reference(loc, name) => {
|
syntax::Expression::Reference(mut name) => {
|
||||||
let iname = ArcIntern::new(name);
|
if let Some(rename) = renames.get(name.current_interned()) {
|
||||||
let final_name = renames.get(&iname).cloned().unwrap_or(iname);
|
name.rename(rename);
|
||||||
|
}
|
||||||
let result_type = self
|
let result_type = self
|
||||||
.variable_types
|
.variable_types
|
||||||
.get(&final_name)
|
.get(name.current_interned())
|
||||||
.cloned()
|
.cloned()
|
||||||
.expect("variable bound before use");
|
.expect("variable bound before use");
|
||||||
let expression = ir::Expression::Atomic(ir::ValueOrRef::Ref(
|
let expression = ir::Expression::Atomic(ir::ValueOrRef::Ref(
|
||||||
loc,
|
name.location().clone(),
|
||||||
result_type.clone(),
|
result_type.clone(),
|
||||||
final_name.clone(),
|
name.current_interned().clone(),
|
||||||
));
|
));
|
||||||
let free_variables = HashSet::from([final_name]);
|
let free_variables = HashSet::from([name.current_interned().clone()]);
|
||||||
|
|
||||||
ExpressionInfo {
|
ExpressionInfo {
|
||||||
expression,
|
expression,
|
||||||
@@ -260,7 +261,7 @@ impl InferenceEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
syntax::Expression::Primitive(loc, name) => {
|
syntax::Expression::Primitive(loc, name) => {
|
||||||
let primop = ir::Primitive::from_str(&name.name).expect("valid primitive");
|
let primop = ir::Primitive::from_str(&name.current_name()).expect("valid primitive");
|
||||||
|
|
||||||
match primop {
|
match primop {
|
||||||
ir::Primitive::Plus | ir::Primitive::Times | ir::Primitive::Divide => {
|
ir::Primitive::Plus | ir::Primitive::Times | ir::Primitive::Divide => {
|
||||||
@@ -404,12 +405,12 @@ impl InferenceEngine {
|
|||||||
expr_info
|
expr_info
|
||||||
}
|
}
|
||||||
|
|
||||||
syntax::Expression::Function(_, name, args, _, expr) => {
|
syntax::Expression::Function(loc, name, args, _, expr) => {
|
||||||
// First, at some point we're going to want to know a location for this function,
|
// First, at some point we're going to want to know a location for this function,
|
||||||
// which should either be the name if we have one, or the body if we don't.
|
// which should either be the name if we have one, or the body if we don't.
|
||||||
let function_location = match name {
|
let function_location = match name {
|
||||||
None => expr.location().clone(),
|
None => expr.location().clone(),
|
||||||
Some(ref name) => name.location.clone(),
|
Some(ref name) => loc,
|
||||||
};
|
};
|
||||||
// Next, let us figure out what we're going to name this function. If the user
|
// Next, let us figure out what we're going to name this function. If the user
|
||||||
// didn't provide one, we'll just call it "function:<something>" for them. (We'll
|
// didn't provide one, we'll just call it "function:<something>" for them. (We'll
|
||||||
@@ -440,7 +441,7 @@ impl InferenceEngine {
|
|||||||
.map(|(name, mut declared_type)| {
|
.map(|(name, mut declared_type)| {
|
||||||
let new_type = ir::TypeOrVar::new();
|
let new_type = ir::TypeOrVar::new();
|
||||||
self.constraints.push(Constraint::IsSomething(
|
self.constraints.push(Constraint::IsSomething(
|
||||||
name.location.clone(),
|
name.location().clone(),
|
||||||
new_type.clone(),
|
new_type.clone(),
|
||||||
));
|
));
|
||||||
let new_name = self.finalize_name(renames, name.clone());
|
let new_name = self.finalize_name(renames, name.clone());
|
||||||
@@ -450,7 +451,7 @@ impl InferenceEngine {
|
|||||||
if let Some(declared_type) = declared_type.take() {
|
if let Some(declared_type) = declared_type.take() {
|
||||||
let declared_type = self.convert_type(declared_type);
|
let declared_type = self.convert_type(declared_type);
|
||||||
self.constraints.push(Constraint::Equivalent(
|
self.constraints.push(Constraint::Equivalent(
|
||||||
name.location.clone(),
|
name.location().clone(),
|
||||||
new_type.clone(),
|
new_type.clone(),
|
||||||
declared_type,
|
declared_type,
|
||||||
));
|
));
|
||||||
@@ -495,11 +496,11 @@ impl InferenceEngine {
|
|||||||
|
|
||||||
fn convert_type(&mut self, ty: syntax::Type) -> ir::TypeOrVar {
|
fn convert_type(&mut self, ty: syntax::Type) -> ir::TypeOrVar {
|
||||||
match ty {
|
match ty {
|
||||||
syntax::Type::Named(x) => match PrimitiveType::from_str(x.name.as_str()) {
|
syntax::Type::Named(x) => match PrimitiveType::from_str(x.current_name()) {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let retval = ir::TypeOrVar::new_located(x.location.clone());
|
let retval = ir::TypeOrVar::new_located(x.location().clone());
|
||||||
self.constraints.push(Constraint::NamedTypeIs(
|
self.constraints.push(Constraint::NamedTypeIs(
|
||||||
x.location.clone(),
|
x.location().clone(),
|
||||||
x.intern(),
|
x.intern(),
|
||||||
retval.clone(),
|
retval.clone(),
|
||||||
));
|
));
|
||||||
@@ -529,10 +530,10 @@ impl InferenceEngine {
|
|||||||
) -> ArcIntern<String> {
|
) -> ArcIntern<String> {
|
||||||
if self
|
if self
|
||||||
.variable_types
|
.variable_types
|
||||||
.contains_key(&ArcIntern::new(name.name.clone()))
|
.contains_key(name.current_interned())
|
||||||
{
|
{
|
||||||
let new_name = ir::gensym(&name.name);
|
let new_name = ir::gensym(&name.original_name());
|
||||||
renames.insert(ArcIntern::new(name.name.to_string()), new_name.clone());
|
renames.insert(name.current_interned().clone(), new_name.clone());
|
||||||
new_name
|
new_name
|
||||||
} else {
|
} else {
|
||||||
ArcIntern::new(name.to_string())
|
ArcIntern::new(name.to_string())
|
||||||
|
|||||||
Reference in New Issue
Block a user