Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions crates/graphcal-cli/src/json_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -730,10 +730,10 @@ fn convert_indexed(obj: &ExactJsonObject, param_name: &str) -> Result<Expr, Json
// Overrides are lowered to HIR (which carries resolution inline),
// so synthetic spans need no uniqueness tricks here.
Ok(MapEntry {
keys: NonEmpty::singleton(MapEntryKey {
keys: NonEmpty::singleton(MapEntryKey::Discrete {
index: Spanned::new(MapEntryIndex::Named(index_path.clone()), SYNTH_SPAN),
additional_index_spans: Vec::new(),
variant: Spanned::new(
entry: Spanned::new(
IndexEntryKey::named(IndexVariantName::try_new(variant.clone()).map_err(
|reason| JsonInputError::InvalidName {
param: format!("{param_name}[{variant}]"),
Expand Down Expand Up @@ -909,7 +909,10 @@ mod tests {
match &expr.kind {
ExprKind::MapLiteral { entries } => {
assert_eq!(entries.len(), 3);
assert_eq!(entries[0].keys[0].index.value.to_string(), "Maneuver");
let MapEntryKey::Discrete { index, .. } = &entries[0].keys[0] else {
panic!("expected a discrete map key")
};
assert_eq!(index.value.to_string(), "Maneuver");
}
other => panic!("expected MapLiteral, got {other:?}"),
}
Expand Down Expand Up @@ -971,7 +974,10 @@ mod tests {

match &overrides[&DeclName::expect_valid("series")].kind {
ExprKind::MapLiteral { entries } => {
assert_eq!(entries[0].keys[0].index.value.to_string(), "lib.Phase");
let MapEntryKey::Discrete { index, .. } = &entries[0].keys[0] else {
panic!("expected a discrete map key")
};
assert_eq!(index.value.to_string(), "lib.Phase");
}
other => panic!("expected MapLiteral, got {other:?}"),
}
Expand Down
18 changes: 17 additions & 1 deletion crates/graphcal-compiler/src/desugar/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,23 @@ impl From<ExprKind<Raw>> for ExprKind<Desugared> {
impl From<MapEntry<Raw>> for MapEntry<Desugared> {
fn from(m: MapEntry<Raw>) -> Self {
Self {
keys: m.keys,
keys: m.keys.map(|key| match key {
crate::syntax::ast::MapEntryKey::Discrete {
index,
additional_index_spans,
entry,
} => crate::syntax::ast::MapEntryKey::Discrete {
index,
additional_index_spans,
entry,
},
crate::syntax::ast::MapEntryKey::Expression { axis, expr } => {
crate::syntax::ast::MapEntryKey::Expression {
axis,
expr: expr.into(),
}
}
}),
value: m.value.into(),
}
}
Expand Down
9 changes: 5 additions & 4 deletions crates/graphcal-compiler/src/desugar/desugared_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub type IndexDeclKind = crate::syntax::ast::IndexDeclKind<Desugared>;
pub type Expr = crate::syntax::ast::Expr<Desugared>;
pub type ExprKind = crate::syntax::ast::ExprKind<Desugared>;
pub(crate) type MapEntry = crate::syntax::ast::MapEntry<Desugared>;
pub(crate) type MapEntryKey = crate::syntax::ast::MapEntryKey<Desugared>;
pub(crate) type IndexArg = crate::syntax::ast::IndexArg<Desugared>;
pub(crate) type FieldInit = crate::syntax::ast::FieldInit<Desugared>;
pub(crate) type MatchArm = crate::syntax::ast::MatchArm<Desugared>;
Expand All @@ -73,8 +74,8 @@ pub type FieldDecl = crate::syntax::ast::FieldDecl<Desugared>;
pub use crate::syntax::ast::{
AmbiguousGenericArg, Attribute, AttributeArg, BaseDimDecl, BinOp, BindableVisibility,
DomainBoundKind, EncodingChannel, ForBinding, ForBindingIndex, GenericConstraint, Ident,
ImportDecl, ImportItem, ImportItemNamespace, ImportKind, MapEntryKey, MarkType, MatchPattern,
ModulePath, MulDivOp, MultiDataRow, MultiDecl, MultiDeclSlice, MultiDeclSlot, MultiHeaderCell,
MultiSlotAxis, MultiSlotColumnSpan, MultiSlotKind, NatExpr, PatternBinding, TableIndexSpec,
UnaryOp, UnitExpr, UnitExprItem, Visibility,
ImportDecl, ImportItem, ImportItemNamespace, ImportKind, MapKeyAxisSyntax, MarkType,
MatchPattern, ModulePath, MulDivOp, MultiDataRow, MultiDecl, MultiDeclSlice, MultiDeclSlot,
MultiHeaderCell, MultiSlotAxis, MultiSlotColumnSpan, MultiSlotKind, NatExpr, PatternBinding,
TableIndexSpec, UnaryOp, UnitExpr, UnitExprItem, Visibility,
};
106 changes: 81 additions & 25 deletions crates/graphcal-compiler/src/hir/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,11 @@ fn collect_expr_dependencies_into_inner(expr: &Expr, deps: &mut ExprDependencies
}
ExprKind::MapLiteral { entries } => {
for entry in entries {
for key in &entry.keys {
if let MapEntryKey::Expression { expr, .. } = key {
collect_expr_dependencies_into(expr, deps);
}
}
collect_expr_dependencies_into(&entry.value, deps);
}
}
Expand Down Expand Up @@ -893,9 +898,14 @@ fn visit_expr_inner(expr: &Expr, visitor: &mut impl FnMut(&Expr)) {
ExprKind::ConstructorCall { fields, .. } => fields
.iter()
.for_each(|field| visit_expr(&field.value, visitor)),
ExprKind::MapLiteral { entries } => entries
.iter()
.for_each(|entry| visit_expr(&entry.value, visitor)),
ExprKind::MapLiteral { entries } => entries.iter().for_each(|entry| {
entry.keys.iter().for_each(|key| {
if let MapEntryKey::Expression { expr, .. } = key {
visit_expr(expr, visitor);
}
});
visit_expr(&entry.value, visitor);
}),
ExprKind::ForComp { body, .. } => visit_expr(body, visitor),
ExprKind::IndexAccess { expr: inner, args } => {
visit_expr(inner, visitor);
Expand Down Expand Up @@ -1100,9 +1110,16 @@ fn find_extern_call_inner(expr: &Expr) -> Option<(&ExternFnRef, Span)> {
ExprKind::ConstructorCall { fields, .. } => fields
.iter()
.find_map(|field| find_extern_call(&field.value)),
ExprKind::MapLiteral { entries } => entries
.iter()
.find_map(|entry| find_extern_call(&entry.value)),
ExprKind::MapLiteral { entries } => entries.iter().find_map(|entry| {
entry
.keys
.iter()
.find_map(|key| match key {
MapEntryKey::Expression { expr, .. } => find_extern_call(expr),
MapEntryKey::IndexVariant(_) | MapEntryKey::FinitePosition { .. } => None,
})
.or_else(|| find_extern_call(&entry.value))
}),
ExprKind::ForComp { body, .. } => find_extern_call(body),
ExprKind::IndexAccess { expr: inner, args } => find_extern_call(inner).or_else(|| {
args.iter().find_map(|arg| match arg {
Expand Down Expand Up @@ -1160,10 +1177,18 @@ pub struct MapEntry {
}

/// A single resolved map key.
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone)]
pub enum MapEntryKey {
IndexVariant(IndexVariantRef),
FinitePosition { size: u64, position: Spanned<u64> },
Expression { axis: MapKeyAxis, expr: Box<Expr> },
}

/// Where an expression-shaped map key obtains its semantic axis.
#[derive(Debug, Clone)]
pub enum MapKeyAxis {
Explicit(Spanned<ResolvedIndexName>),
Contextual,
}

/// A resolved for-comprehension binding.
Expand Down Expand Up @@ -1315,9 +1340,19 @@ impl<'a> ExprLowerer<'a> {
ast::ExprKind::ConstructorCall { fields, .. } => {
fields.iter().map(|field| &field.value).collect()
}
ast::ExprKind::MapLiteral { entries } => {
entries.iter().map(|entry| &entry.value).collect()
}
ast::ExprKind::MapLiteral { entries } => entries
.iter()
.flat_map(|entry| {
entry
.keys
.iter()
.filter_map(|key| match key {
ast::MapEntryKey::Expression { expr, .. } => Some(expr),
ast::MapEntryKey::Discrete { .. } => None,
})
.chain(std::iter::once(&entry.value))
})
.collect(),
ast::ExprKind::ForComp { body, .. } => vec![body],
ast::ExprKind::IndexAccess { expr, args } => std::iter::once(expr.as_ref())
.chain(args.iter().filter_map(|arg| match arg {
Expand Down Expand Up @@ -2348,22 +2383,45 @@ impl<'a> ExprLowerer<'a> {
}

fn lower_map_entry_key(
&self,
&mut self,
key: &ast::MapEntryKey,
map_span: Span,
) -> Result<MapEntryKey, ExprLowerError> {
match (&key.index.value, &key.variant.value) {
if let ast::MapEntryKey::Expression { axis, expr } = key {
let axis = match axis {
ast::MapKeyAxisSyntax::Explicit(index) => {
let resolved = self
.ctx
.resolver
.resolve_index_path(self.ctx.owner, &index.value)
.map_err(|source| ExprLowerError::ModuleResolve {
source,
span: index.span,
})?;
MapKeyAxis::Explicit(Spanned::new(resolved, index.span))
}
ast::MapKeyAxisSyntax::Contextual => MapKeyAxis::Contextual,
};
return Ok(MapEntryKey::Expression {
axis,
expr: Box::new(self.lower_expr(expr)),
});
}
let ast::MapEntryKey::Discrete {
index,
additional_index_spans,
entry,
} = key
else {
return Err(ExprLowerError::InvalidMapEntryKey { span: map_span });
};
match (&index.value, &entry.value) {
(
crate::syntax::ast::MapEntryIndex::Named(index_path),
IndexEntryKey::Named(variant_name),
) => {
let variant = self
.resolve_index_variant_parts(
index_path,
variant_name,
key.index.span,
key.variant.span,
)
.resolve_index_variant_parts(index_path, variant_name, index.span, entry.span)
.map_err(|err| match err {
ExprLowerError::ModuleResolve {
source: ModuleResolveError::UnknownIndexVariant { index, variant },
Expand All @@ -2377,23 +2435,21 @@ impl<'a> ExprLowerer<'a> {
})?;
Ok(MapEntryKey::IndexVariant(IndexVariantRef {
variant,
index_span: Some(key.index.span),
additional_index_spans: key.additional_index_spans.clone(),
variant_span: key.variant.span,
index_span: Some(index.span),
additional_index_spans: additional_index_spans.clone(),
variant_span: entry.span,
}))
}
(
crate::syntax::ast::MapEntryIndex::Finite(size),
IndexEntryKey::Position(position),
) => Ok(MapEntryKey::FinitePosition {
size: *size,
position: Spanned::new(*position, key.variant.span),
position: Spanned::new(*position, entry.span),
}),
(crate::syntax::ast::MapEntryIndex::Named(_), IndexEntryKey::Position(_))
| (crate::syntax::ast::MapEntryIndex::Finite(_), IndexEntryKey::Named(_)) => {
Err(ExprLowerError::InvalidMapEntryKey {
span: key.variant.span,
})
Err(ExprLowerError::InvalidMapEntryKey { span: entry.span })
}
}
}
Expand Down
Loading