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:
parent
09f255577b
commit
3eb820b7d7
14
src/error.rs
14
src/error.rs
@ -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")
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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(..)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user