Skip to content

Commit ed35467

Browse files
authored
(feat) AST->HIR Code prep (#53)
This PR solves a bunch of problems in the DSL/HIR to allow for the initial transformation from AST -> HIR. Notably: 1. Adds `$` and `*` type extensions in the parser & type system. `Type$` stands for Costed(Type) is covariant and inherits Stored(Type) `Type* `stands for Stored(Type) is covariant and inherits Type. 2. Adds an implementation of map in the HIR and the engine where the keys are allowed to be hashed and compared against each other. 3. Adds `#` to distinguish between field accesses in structs, and member function calls (with `.`). 4. Fixes the `Call` evaluate engine function to include indexing arrays, tuples, maps, and operators (including a group/goal expansion when field access is needed). 5. Added the `Never` type for the Fail expression in the type system.
1 parent f7f9b9f commit ed35467

File tree

29 files changed

+2686
-805
lines changed

29 files changed

+2686
-805
lines changed

optd-core/src/bridge/from_cir.rs

+23-21
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub(crate) fn partial_logical_to_value(plan: &PartialLogicalPlan) -> Value {
1414
match plan {
1515
PartialLogicalPlan::UnMaterialized(group_id) => {
1616
// For unmaterialized logical operators, we create a `Value` with the group ID.
17-
Value(Logical(UnMaterialized(hir::GroupId(group_id.0))))
17+
Value::new(Logical(UnMaterialized(hir::GroupId(group_id.0))))
1818
}
1919
PartialLogicalPlan::Materialized(node) => {
2020
// For materialized logical operators, we create a `Value` with the operator data.
@@ -24,7 +24,7 @@ pub(crate) fn partial_logical_to_value(plan: &PartialLogicalPlan) -> Value {
2424
children: convert_children_to_values(&node.children, partial_logical_to_value),
2525
};
2626

27-
Value(Logical(Materialized(LogicalOp::logical(operator))))
27+
Value::new(Logical(Materialized(LogicalOp::logical(operator))))
2828
}
2929
}
3030
}
@@ -35,7 +35,7 @@ pub(crate) fn partial_physical_to_value(plan: &PartialPhysicalPlan) -> Value {
3535
PartialPhysicalPlan::UnMaterialized(goal) => {
3636
// For unmaterialized physical operators, we create a `Value` with the goal
3737
let hir_goal = cir_goal_to_hir(goal);
38-
Value(Physical(UnMaterialized(hir_goal)))
38+
Value::new(Physical(UnMaterialized(hir_goal)))
3939
}
4040
PartialPhysicalPlan::Materialized(node) => {
4141
// For materialized physical operators, we create a Value with the operator data
@@ -45,7 +45,7 @@ pub(crate) fn partial_physical_to_value(plan: &PartialPhysicalPlan) -> Value {
4545
children: convert_children_to_values(&node.children, partial_physical_to_value),
4646
};
4747

48-
Value(Physical(Materialized(PhysicalOp::physical(operator))))
48+
Value::new(Physical(Materialized(PhysicalOp::physical(operator))))
4949
}
5050
}
5151
}
@@ -54,9 +54,9 @@ pub(crate) fn partial_physical_to_value(plan: &PartialPhysicalPlan) -> Value {
5454
/// Converts a [`PartialPhysicalPlan`] with its cost into a [`Value`].
5555
pub(crate) fn costed_physical_to_value(plan: PartialPhysicalPlan, cost: Cost) -> Value {
5656
let operator = partial_physical_to_value(&plan);
57-
Value(Tuple(vec![
57+
Value::new(Tuple(vec![
5858
partial_physical_to_value(&plan),
59-
Value(Literal(Float64(cost.0))),
59+
Value::new(Literal(Float64(cost.0))),
6060
]))
6161
}
6262

@@ -65,15 +65,15 @@ pub(crate) fn costed_physical_to_value(plan: PartialPhysicalPlan, cost: Cost) ->
6565
pub(crate) fn logical_properties_to_value(properties: &LogicalProperties) -> Value {
6666
match &properties.0 {
6767
Some(data) => properties_data_to_value(data),
68-
Option::None => Value(None),
68+
Option::None => Value::new(None),
6969
}
7070
}
7171

7272
/// Converts [`PhysicalProperties`] into a [`Value`].
7373
pub(crate) fn physical_properties_to_value(properties: &PhysicalProperties) -> Value {
7474
match &properties.0 {
7575
Some(data) => properties_data_to_value(data),
76-
Option::None => Value(None),
76+
Option::None => Value::new(None),
7777
}
7878
}
7979

@@ -104,7 +104,7 @@ where
104104
.map(|child| match child {
105105
Child::Singleton(item) => converter(item),
106106
Child::VarLength(items) => {
107-
Value(Array(items.iter().map(|item| converter(item)).collect()))
107+
Value::new(Array(items.iter().map(|item| converter(item)).collect()))
108108
}
109109
})
110110
.collect()
@@ -118,32 +118,34 @@ fn convert_operator_data_to_values(data: &[OperatorData]) -> Vec<Value> {
118118
/// Converts an [`OperatorData`] into a [`Value`].
119119
fn operator_data_to_value(data: &OperatorData) -> Value {
120120
match data {
121-
OperatorData::Int64(i) => Value(Literal(Int64(*i))),
122-
OperatorData::Float64(f) => Value(Literal(Float64(**f))),
123-
OperatorData::String(s) => Value(Literal(String(s.clone()))),
124-
OperatorData::Bool(b) => Value(Literal(Bool(*b))),
125-
OperatorData::Struct(name, elements) => Value(Struct(
121+
OperatorData::Int64(i) => Value::new(Literal(Int64(*i))),
122+
OperatorData::Float64(f) => Value::new(Literal(Float64(**f))),
123+
OperatorData::String(s) => Value::new(Literal(String(s.clone()))),
124+
OperatorData::Bool(b) => Value::new(Literal(Bool(*b))),
125+
OperatorData::Struct(name, elements) => Value::new(Struct(
126126
name.clone(),
127127
convert_operator_data_to_values(elements),
128128
)),
129-
OperatorData::Array(elements) => Value(Array(convert_operator_data_to_values(elements))),
129+
OperatorData::Array(elements) => {
130+
Value::new(Array(convert_operator_data_to_values(elements)))
131+
}
130132
}
131133
}
132134

133135
/// Converts a [`PropertiesData`] into a [`Value`].
134136
fn properties_data_to_value(data: &PropertiesData) -> Value {
135137
match data {
136-
PropertiesData::Int64(i) => Value(Literal(Int64(*i))),
137-
PropertiesData::Float64(f) => Value(Literal(Float64(**f))),
138-
PropertiesData::String(s) => Value(Literal(String(s.clone()))),
139-
PropertiesData::Bool(b) => Value(Literal(Bool(*b))),
138+
PropertiesData::Int64(i) => Value::new(Literal(Int64(*i))),
139+
PropertiesData::Float64(f) => Value::new(Literal(Float64(**f))),
140+
PropertiesData::String(s) => Value::new(Literal(String(s.clone()))),
141+
PropertiesData::Bool(b) => Value::new(Literal(Bool(*b))),
140142
PropertiesData::Struct(name, elements) => {
141143
let values = elements.iter().map(properties_data_to_value).collect();
142-
Value(Struct(name.clone(), values))
144+
Value::new(Struct(name.clone(), values))
143145
}
144146
PropertiesData::Array(elements) => {
145147
let values = elements.iter().map(properties_data_to_value).collect();
146-
Value(Array(values))
148+
Value::new(Array(values))
147149
}
148150
}
149151
}

optd-core/src/bridge/into_cir.rs

+18-15
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::sync::Arc;
1414
///
1515
/// Panics if the [`Value`] is not a [`Logical`] variant.
1616
pub(crate) fn value_to_partial_logical(value: &Value) -> PartialLogicalPlan {
17-
match &value.0 {
17+
match &value.data {
1818
Logical(logical_op) => match logical_op {
1919
UnMaterialized(group_id) => {
2020
PartialLogicalPlan::UnMaterialized(hir_group_id_to_cir(group_id))
@@ -28,7 +28,7 @@ pub(crate) fn value_to_partial_logical(value: &Value) -> PartialLogicalPlan {
2828
),
2929
}),
3030
},
31-
_ => panic!("Expected Logical CoreData variant, found: {:?}", value.0),
31+
_ => panic!("Expected Logical CoreData variant, found: {:?}", value.data),
3232
}
3333
}
3434

@@ -38,7 +38,7 @@ pub(crate) fn value_to_partial_logical(value: &Value) -> PartialLogicalPlan {
3838
///
3939
/// Panics if the [`Value`] is not a [`Physical`] variant.
4040
pub(crate) fn value_to_partial_physical(value: &Value) -> PartialPhysicalPlan {
41-
match &value.0 {
41+
match &value.data {
4242
Physical(physical_op) => match physical_op {
4343
UnMaterialized(hir_goal) => {
4444
PartialPhysicalPlan::UnMaterialized(hir_goal_to_cir(hir_goal))
@@ -52,7 +52,10 @@ pub(crate) fn value_to_partial_physical(value: &Value) -> PartialPhysicalPlan {
5252
),
5353
}),
5454
},
55-
_ => panic!("Expected Physical CoreData variant, found: {:?}", value.0),
55+
_ => panic!(
56+
"Expected Physical CoreData variant, found: {:?}",
57+
value.data
58+
),
5659
}
5760
}
5861

@@ -62,23 +65,23 @@ pub(crate) fn value_to_partial_physical(value: &Value) -> PartialPhysicalPlan {
6265
///
6366
/// Panics if the [`Value`] is not a [`Literal`] variant with a [`Float64`] value.
6467
pub(crate) fn value_to_cost(value: &Value) -> Cost {
65-
match &value.0 {
68+
match &value.data {
6669
Literal(Float64(f)) => Cost(*f),
67-
_ => panic!("Expected Float64 literal, found: {:?}", value.0),
70+
_ => panic!("Expected Float64 literal, found: {:?}", value.data),
6871
}
6972
}
7073

7174
/// Converts an HIR properties [`Value`] into a CIR [`LogicalProperties`].
7275
pub(crate) fn value_to_logical_properties(properties_value: &Value) -> LogicalProperties {
73-
match &properties_value.0 {
76+
match &properties_value.data {
7477
None => LogicalProperties(Option::None),
7578
_ => LogicalProperties(Some(value_to_properties_data(properties_value))),
7679
}
7780
}
7881

7982
/// Convert an HIR properties [`Value`] into a CIR [`PhysicalProperties`].
8083
fn value_to_physical_properties(properties_value: &Value) -> PhysicalProperties {
81-
match &properties_value.0 {
84+
match &properties_value.data {
8285
None => PhysicalProperties(Option::None),
8386
_ => PhysicalProperties(Some(value_to_properties_data(properties_value))),
8487
}
@@ -108,7 +111,7 @@ pub(crate) fn hir_goal_to_cir(hir_goal: &hir::Goal) -> Goal {
108111
/// Panics if the [`Value`] is not a [`Logical`] variant or if the [`Logical`] variant is not a
109112
/// [`Materialized`] variant.
110113
fn value_to_logical(value: &Value) -> LogicalPlan {
111-
match &value.0 {
114+
match &value.data {
112115
Logical(logical_op) => match logical_op {
113116
UnMaterialized(_) => {
114117
panic!("Cannot convert UnMaterialized LogicalOperator to LogicalPlan")
@@ -119,7 +122,7 @@ fn value_to_logical(value: &Value) -> LogicalPlan {
119122
children: convert_values_to_children(&log_op.operator.children, value_to_logical),
120123
}),
121124
},
122-
_ => panic!("Expected Logical CoreData variant, found: {:?}", value.0),
125+
_ => panic!("Expected Logical CoreData variant, found: {:?}", value.data),
123126
}
124127
}
125128

@@ -132,7 +135,7 @@ where
132135
{
133136
values
134137
.iter()
135-
.map(|value| match &value.0 {
138+
.map(|value| match &value.data {
136139
Array(elements) => VarLength(
137140
elements
138141
.iter()
@@ -160,7 +163,7 @@ fn convert_values_to_properties_data(values: &[Value]) -> Vec<PropertiesData> {
160163
///
161164
/// Panics if the [`Value`] cannot be converted to [`OperatorData`], such as a [`Unit`] literal.
162165
fn value_to_operator_data(value: &Value) -> OperatorData {
163-
match &value.0 {
166+
match &value.data {
164167
Literal(constant) => match constant {
165168
Int64(i) => OperatorData::Int64(*i),
166169
Float64(f) => OperatorData::Float64((*f).into()),
@@ -172,7 +175,7 @@ fn value_to_operator_data(value: &Value) -> OperatorData {
172175
Struct(name, elements) => {
173176
OperatorData::Struct(name.clone(), convert_values_to_operator_data(elements))
174177
}
175-
_ => panic!("Cannot convert {:?} to OperatorData", value.0),
178+
_ => panic!("Cannot convert {:?} to OperatorData", value.data),
176179
}
177180
}
178181

@@ -182,7 +185,7 @@ fn value_to_operator_data(value: &Value) -> OperatorData {
182185
///
183186
/// Panics if the [`Value`] cannot be converted to [`PropertiesData`], such as a [`Unit`] literal.
184187
fn value_to_properties_data(value: &Value) -> PropertiesData {
185-
match &value.0 {
188+
match &value.data {
186189
Literal(constant) => match constant {
187190
Int64(i) => PropertiesData::Int64(*i),
188191
Float64(f) => PropertiesData::Float64((*f).into()),
@@ -194,6 +197,6 @@ fn value_to_properties_data(value: &Value) -> PropertiesData {
194197
Struct(name, elements) => {
195198
PropertiesData::Struct(name.clone(), convert_values_to_properties_data(elements))
196199
}
197-
_ => panic!("Cannot convert {:?} to PropertyData content", value.0),
200+
_ => panic!("Cannot convert {:?} to PropertyData content", value.data),
198201
}
199202
}

optd-dsl/src/analyzer/context.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::hir::Identifier;
1+
use super::hir::{ExprMetadata, Identifier, NoMetadata};
22
use crate::analyzer::hir::Value;
33
use std::{collections::HashMap, sync::Arc};
44

@@ -12,15 +12,15 @@ use std::{collections::HashMap, sync::Arc};
1212
/// The current (innermost) scope is mutable, while all previous scopes
1313
/// are immutable and stored as Arc for efficient cloning.
1414
#[derive(Debug, Clone, Default)]
15-
pub struct Context {
15+
pub struct Context<M: ExprMetadata = NoMetadata> {
1616
/// Previous scopes (outer lexical scopes), stored as immutable Arc references
17-
previous_scopes: Vec<Arc<HashMap<Identifier, Value>>>,
17+
previous_scopes: Vec<Arc<HashMap<Identifier, Value<M>>>>,
1818

1919
/// Current scope (innermost) that can be directly modified
20-
current_scope: HashMap<Identifier, Value>,
20+
current_scope: HashMap<Identifier, Value<M>>,
2121
}
2222

23-
impl Context {
23+
impl<M: ExprMetadata> Context<M> {
2424
/// Creates a new context with the given initial bindings as the global scope.
2525
///
2626
/// # Arguments
@@ -30,7 +30,7 @@ impl Context {
3030
/// # Returns
3131
///
3232
/// A new `Context` instance with one scope containing the initial bindings
33-
pub fn new(initial_bindings: HashMap<Identifier, Value>) -> Self {
33+
pub fn new(initial_bindings: HashMap<Identifier, Value<M>>) -> Self {
3434
Self {
3535
previous_scopes: Vec::new(),
3636
current_scope: initial_bindings,
@@ -59,7 +59,7 @@ impl Context {
5959
/// # Returns
6060
///
6161
/// Some reference to the value if found, None otherwise
62-
pub fn lookup(&self, name: &str) -> Option<&Value> {
62+
pub fn lookup(&self, name: &str) -> Option<&Value<M>> {
6363
// First check the current scope
6464
if let Some(value) = self.current_scope.get(name) {
6565
return Some(value);
@@ -84,7 +84,7 @@ impl Context {
8484
/// # Arguments
8585
///
8686
/// * `other` - The context to merge from (consumed by this operation)
87-
pub fn merge(&mut self, other: Context) {
87+
pub fn merge(&mut self, other: Context<M>) {
8888
// Move bindings from other's current scope into our current scope
8989
for (name, val) in other.current_scope {
9090
self.current_scope.insert(name, val);
@@ -100,7 +100,7 @@ impl Context {
100100
///
101101
/// * `name` - The name of the variable to bind
102102
/// * `val` - The value to bind to the variable
103-
pub fn bind(&mut self, name: String, val: Value) {
103+
pub fn bind(&mut self, name: String, val: Value<M>) {
104104
self.current_scope.insert(name, val);
105105
}
106106
}

0 commit comments

Comments
 (0)