1
1
mirror of https://github.com/tweag/nickel.git synced 2024-09-20 16:08:14 +03:00

Add position to Ident

This commit is contained in:
Yannik Sander 2021-11-02 11:04:52 +01:00 committed by Yannik Sander
parent 09f255577b
commit 3eb820b7d7
12 changed files with 66 additions and 38 deletions

View File

@ -959,7 +959,7 @@ impl ToDiagnostic<FileId> for EvalError {
.enumerate()
.map(|(i, (id_opt, pos))| {
let name = id_opt
.map(|Ident(id)| id)
.map(|Ident(id, _)| id)
.unwrap_or_else(|| String::from("<func>"));
Diagnostic::note().with_labels(vec![secondary(&pos)
.with_message(format!("({}) calling {}", i + 1, name))])
@ -1073,7 +1073,7 @@ impl ToDiagnostic<FileId> for EvalError {
.with_message("Non mergeable terms")
.with_labels(labels)]
}
EvalError::UnboundIdentifier(Ident(ident), span_opt) => vec![Diagnostic::error()
EvalError::UnboundIdentifier(Ident(ident, _), span_opt) => vec![Diagnostic::error()
.with_message("Unbound identifier")
.with_labels(vec![primary_alt(span_opt.into_opt(), ident.clone(), files)
.with_message("this identifier is unbound")])],
@ -1214,7 +1214,7 @@ impl ToDiagnostic<FileId> for TypecheckError {
.with_message("Ill-formed type")
.with_labels(vec![label])]
}
TypecheckError::MissingRow(Ident(ident), expd, actual, span_opt) =>
TypecheckError::MissingRow(Ident(ident,_), expd, actual, span_opt) =>
vec![Diagnostic::error()
.with_message(format!("Type error: missing row `{}`", ident))
.with_labels(mk_expr_label(span_opt))
@ -1233,7 +1233,7 @@ impl ToDiagnostic<FileId> for TypecheckError {
])]
,
TypecheckError::ExtraRow(Ident(ident), expd, actual, span_opt) =>
TypecheckError::ExtraRow(Ident(ident,_), expd, actual, span_opt) =>
vec![Diagnostic::error()
.with_message(format!("Type error: extra row `{}`", ident))
.with_labels(mk_expr_label(span_opt))
@ -1252,7 +1252,7 @@ impl ToDiagnostic<FileId> for TypecheckError {
])]
,
TypecheckError::UnboundTypeVariable(Ident(ident), span_opt) =>
TypecheckError::UnboundTypeVariable(Ident(ident,_), span_opt) =>
vec![Diagnostic::error()
.with_message(String::from("Unbound type variable"))
.with_labels(vec![primary_alt(span_opt.into_opt(), ident.clone(), files).with_message("this type variable is unbound")])
@ -1271,7 +1271,7 @@ impl ToDiagnostic<FileId> for TypecheckError {
String::from("These types are not compatible"),
])]
,
TypecheckError::RowKindMismatch(Ident(ident), expd, actual, span_opt) => {
TypecheckError::RowKindMismatch(Ident(ident,_), expd, actual, span_opt) => {
let (expd_str, actual_str) = match (expd, actual) {
(Some(_), None) => ("an enum type", "a record type"),
(None, Some(_)) => ("a record type", "an enum type"),
@ -1334,7 +1334,7 @@ impl ToDiagnostic<FileId> for TypecheckError {
}));
diags
}
TypecheckError::RowConflict(Ident(ident), conflict, _expd, _actual, span_opt) => {
TypecheckError::RowConflict(Ident(ident,_), conflict, _expd, _actual, span_opt) => {
vec![
Diagnostic::error()
.with_message("Multiple rows declaration")

View File

@ -253,7 +253,7 @@ Pattern: Ident = {
Ident,
};
Ident: Ident = "identifier" => Ident(<>.to_string());
Ident: Ident = <l:@L><i: "identifier"><r:@R> => Ident(i.to_string(), Some(mk_pos(src_id, l, r)));
Bool: bool = {
"true" => true,

View File

@ -1,13 +1,41 @@
//! Define the type of an identifier.
use serde::{Deserialize, Serialize};
use std::fmt;
use std::{fmt, hash::Hash};
#[derive(Debug, Eq, Hash, PartialEq, Ord, PartialOrd, Clone, Serialize, Deserialize)]
pub struct Ident(pub String);
use crate::position::TermPos;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Ident(pub String, #[serde(skip)] pub Option<TermPos>);
impl PartialOrd for Ident {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
impl Ord for Ident {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl PartialEq for Ident {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Eq for Ident {}
impl Hash for Ident {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Ident(ident) = self;
let Ident(ident, _) = self;
write!(f, "{}", ident)
}
}
@ -17,6 +45,6 @@ where
String: From<F>,
{
fn from(val: F) -> Self {
Ident(String::from(val))
Ident(String::from(val), None)
}
}

View File

@ -92,7 +92,7 @@ pub mod ty_path {
(AbsType::Forall(_, _), Some(_)) => {
// The length of "forall" plus the final separating dot and whitespace ". "
let mut result = 8;
while let AbsType::Forall(Ident(id), body) = &ty.0 {
while let AbsType::Forall(Ident(id, _), body) = &ty.0 {
// The length of the identifier plus the preceding whitespace
result += id.len() + 1;
ty = body.as_ref();

View File

@ -478,7 +478,7 @@ fn process_unary_operation(
}
UnaryOp::FieldsOf() => {
if let Term::Record(map, _) = *t {
let mut fields: Vec<String> = map.keys().map(|Ident(id)| id.clone()).collect();
let mut fields: Vec<String> = map.keys().map(|Ident(id, _)| id.clone()).collect();
fields.sort();
let terms = fields.into_iter().map(mk_term::string).collect();
Ok(Closure::atomic_closure(RichTerm::new(
@ -604,10 +604,10 @@ fn process_unary_operation(
let rec = rec
.into_iter()
.map(|e| {
let (Ident(s), t) = e;
let (Ident(s, ident_pos), t) = e;
let pos = t.pos.into_inherited();
(
Ident(s.clone()),
Ident(s.clone(), ident_pos),
mk_app!(f_as_var.clone(), mk_term::string(s), t)
.closurize(&mut shared_env, env.clone())
.with_pos(pos),
@ -938,7 +938,7 @@ fn process_unary_operation(
let re = regex::Regex::new("_?[a-zA-Z][_a-zA-Z0-9]*").unwrap();
if re.is_match(&s) {
Ok(Closure::atomic_closure(RichTerm::new(
Term::Enum(Ident(s)),
Term::Enum(Ident(s, None)),
pos_op_inh,
)))
} else {
@ -1506,7 +1506,7 @@ fn process_binary_operation(
BinaryOp::GoField() => {
if let Term::Str(field) = *t1 {
if let Term::Lbl(mut l) = *t2 {
l.path.push(ty_path::Elem::Field(Ident(field)));
l.path.push(ty_path::Elem::Field(Ident(field, None)));
Ok(Closure::atomic_closure(RichTerm::new(
Term::Lbl(l),
pos_op_inh,
@ -1538,7 +1538,7 @@ fn process_binary_operation(
BinaryOp::DynAccess() => {
if let Term::Str(id) = *t1 {
if let Term::Record(mut static_map, attrs) = *t2 {
match static_map.remove(&Ident(id.clone())) {
match static_map.remove(&Ident(id.clone(), None)) {
Some(e) => Ok(Closure { body: e, env: env2 }),
None => Err(EvalError::FieldMissing(
id,
@ -1581,7 +1581,7 @@ fn process_binary_operation(
if let Term::Str(id) = *t1 {
if let Term::Record(mut static_map, attrs) = *t2 {
let as_var = clos.body.closurize(&mut env2, clos.env);
match static_map.insert(Ident(id.clone()), as_var) {
match static_map.insert(Ident(id.clone(), None), as_var) {
Some(_) => Err(EvalError::Other(format!("$[ .. ]: tried to extend record with the field {}, but it already exists", id), pos_op)),
None => Ok(Closure {
body: Term::Record(static_map, attrs).into(),
@ -1614,7 +1614,7 @@ fn process_binary_operation(
BinaryOp::DynRemove() => {
if let Term::Str(id) = *t1 {
if let Term::Record(mut static_map, attrs) = *t2 {
match static_map.remove(&Ident(id.clone())) {
match static_map.remove(&Ident(id.clone(), None)) {
None => Err(EvalError::FieldMissing(
id,
String::from("(-$)"),
@ -1656,7 +1656,7 @@ fn process_binary_operation(
if let Term::Str(id) = *t1 {
if let Term::Record(static_map, _) = *t2 {
Ok(Closure::atomic_closure(RichTerm::new(
Term::Bool(static_map.contains_key(&Ident(id))),
Term::Bool(static_map.contains_key(&Ident(id, None))),
pos_op_inh,
)))
} else {

View File

@ -375,24 +375,24 @@ fn unbound_type_variables() {
// should fail, "a" is unbound
assert_matches!(
parse("1 | a"),
Err(ParseError::UnboundTypeVariables(unbound_vars, _)) if (unbound_vars.contains(&Ident("a".into())) && unbound_vars.len() == 1)
Err(ParseError::UnboundTypeVariables(unbound_vars, _)) if (unbound_vars.contains(&Ident("a".into(), None)) && unbound_vars.len() == 1)
);
// should fail, "d" is unbound
assert_matches!(
parse("null: forall a b c. a -> (b -> List c) -> {foo : List {_ : d}, bar: b | Dyn}"),
Err(ParseError::UnboundTypeVariables(unbound_vars, _)) if (unbound_vars.contains(&Ident("d".into())) && unbound_vars.len() == 1)
Err(ParseError::UnboundTypeVariables(unbound_vars, _)) if (unbound_vars.contains(&Ident("d".into(), None)) && unbound_vars.len() == 1)
);
// should fail, "e" is unbound
assert_matches!(
parse("null: forall a b c. a -> (b -> List c) -> {foo : List {_ : a}, bar: b | e}"),
Err(ParseError::UnboundTypeVariables(unbound_vars, _)) if (unbound_vars.contains(&Ident("e".into())) && unbound_vars.len() == 1)
Err(ParseError::UnboundTypeVariables(unbound_vars, _)) if (unbound_vars.contains(&Ident("e".into(), None)) && unbound_vars.len() == 1)
);
// should fail, "a" is unbound
assert_matches!(
parse("null: a -> (forall a. a -> a)"),
Err(ParseError::UnboundTypeVariables(unbound_vars, _)) if (unbound_vars.contains(&Ident("a".into())) && unbound_vars.len() == 1)
Err(ParseError::UnboundTypeVariables(unbound_vars, _)) if (unbound_vars.contains(&Ident("a".into(), None)) && unbound_vars.len() == 1)
);
}

View File

@ -132,7 +132,7 @@ where
});
if is_static.is_ok() {
insert_static_field(&mut static_map, Ident(buffer), t)
insert_static_field(&mut static_map, Ident(buffer, None), t)
} else {
dynamic_fields.push((e, t));
}

View File

@ -16,7 +16,7 @@ pub struct RawPos {
/// A position span identified by a starting byte offset and an ending byte offset in a file.
///
/// `end` is the offset of the last character plus one.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub struct RawSpan {
pub src_id: FileId,
pub start: ByteIndex,
@ -24,7 +24,7 @@ pub struct RawSpan {
}
/// The position span of a term.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum TermPos {
/// The term exactly corresponds to an original expression in the source, or is a construct
/// introduced by program transformation that correponds to an original span in the source.

View File

@ -404,7 +404,7 @@ impl Term {
}
Term::Fun(_, _) => String::from("<func>"),
Term::Lbl(_) => String::from("<label>"),
Term::Enum(Ident(s)) => format!("`{}", s),
Term::Enum(Ident(s, _)) => format!("`{}", s),
Term::Record(..) | Term::RecRecord(..) => String::from("{ ... }"),
Term::List(_) => String::from("[ ... ]"),
Term::Sym(_) => String::from("<sym>"),
@ -432,7 +432,7 @@ impl Term {
format!("<{}{}={}>", content, value_label, value)
}
Term::Var(Ident(id)) => id.clone(),
Term::Var(Ident(id, _)) => id.clone(),
Term::Let(_, _, _)
| Term::App(_, _)
| Term::Switch(..)

View File

@ -337,7 +337,7 @@ where
/// Generate a new fresh variable which do not clash with user-defined variables.
pub fn fresh_var() -> Ident {
Ident(format!("%{}", FreshVarCounter::next()))
Ident(format!("%{}", FreshVarCounter::next()), None)
}
/// Structures which can be packed together with their environment as a closure.

View File

@ -1485,7 +1485,7 @@ pub mod reporting {
name = format!("{}{}", name, suffix);
}
let ident = Ident(name);
let ident = Ident(name, None);
name_reg.reg.insert(id, ident.clone());
ident
}

View File

@ -376,11 +376,11 @@ impl fmt::Display for Types {
}
AbsType::Sym() => write!(f, "Sym"),
AbsType::Flat(ref t) => write!(f, "#{}", t.as_ref().shallow_repr()),
AbsType::Var(Ident(ref var)) => write!(f, "{}", var),
AbsType::Forall(Ident(ref i), ref ty) => {
AbsType::Var(Ident(ref var, _)) => write!(f, "{}", var),
AbsType::Forall(Ident(ref i, _), ref ty) => {
let mut curr: &Types = ty.as_ref();
write!(f, "forall {}", i)?;
while let Types(AbsType::Forall(Ident(ref i), ref ty)) = curr {
while let Types(AbsType::Forall(Ident(ref i, _), ref ty)) = curr {
write!(f, " {}", i)?;
curr = ty;
}
@ -390,7 +390,7 @@ impl fmt::Display for Types {
AbsType::StaticRecord(row) => write!(f, "{{{}}}", row),
AbsType::DynRecord(ty) => write!(f, "{{_: {}}}", ty),
AbsType::RowEmpty() => Ok(()),
AbsType::RowExtend(Ident(id), ty_opt, tail) => {
AbsType::RowExtend(Ident(id, _), ty_opt, tail) => {
write!(f, "{}", id)?;
if let Some(ty) = ty_opt {