Accessors
This commit is contained in:
parent
f0e4b50c99
commit
de741448e0
@ -4,7 +4,7 @@ use crate::{
|
||||
ast,
|
||||
builtin::Builtin,
|
||||
symbol_table::{DefId, SymbolSpec, SymbolTable},
|
||||
type_inference::TypeContext,
|
||||
type_inference::{TypeContext, TypeId},
|
||||
};
|
||||
|
||||
mod test;
|
||||
@ -135,23 +135,14 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
||||
}),
|
||||
NamedStruct { name, fields } => {
|
||||
self.symbol_table.debug();
|
||||
println!("Namedstruct name {} id: {}", name, name.id);
|
||||
let symbol = self.symbol_table.lookup_symbol(&name.id).unwrap();
|
||||
let (tag, type_id) = match symbol.spec() {
|
||||
SymbolSpec::RecordConstructor { tag, members: _, type_id } => (tag, type_id),
|
||||
e => return Expression::ReductionError(format!("Bad symbol for NamedStruct: {:?}", e)),
|
||||
};
|
||||
|
||||
// Eventually, the ReducedIR should decide what field ordering is optimal.
|
||||
// For now, just do it alphabetically.
|
||||
let mut field_order: Vec<String> = self
|
||||
.type_context
|
||||
.lookup_record_members(&type_id, tag)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|(field, _type_id)| field)
|
||||
.cloned()
|
||||
.collect();
|
||||
field_order.sort_unstable();
|
||||
let field_order = compute_field_orderings(&self.type_context, &type_id, tag).unwrap();
|
||||
|
||||
let mut field_map = HashMap::new();
|
||||
for (name, expr) in fields.iter() {
|
||||
@ -179,7 +170,8 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
||||
WhileExpression { .. } => Expression::ReductionError("While expr not implemented".to_string()),
|
||||
ForExpression { .. } => Expression::ReductionError("For expr not implemented".to_string()),
|
||||
ListLiteral { .. } => Expression::ReductionError("ListLiteral expr not implemented".to_string()),
|
||||
Access { .. } => unimplemented!(),
|
||||
Access { name, expr } =>
|
||||
Expression::Access { name: name.as_ref().to_string(), expr: Box::new(self.expression(expr)) },
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,3 +381,21 @@ impl ast::Pattern {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Given the type context and a variant, compute what order the fields on it were stored.
|
||||
/// This needs to be public until type-checking is fully implemented because the type information
|
||||
/// is only available at runtime.
|
||||
pub fn compute_field_orderings(
|
||||
type_context: &TypeContext,
|
||||
type_id: &TypeId,
|
||||
tag: u32,
|
||||
) -> Option<Vec<String>> {
|
||||
// Eventually, the ReducedIR should decide what field ordering is optimal.
|
||||
// For now, just do it alphabetically.
|
||||
|
||||
let record_members = type_context.lookup_record_members(type_id, tag)?;
|
||||
let mut field_order: Vec<String> =
|
||||
record_members.iter().map(|(field, _type_id)| field).cloned().collect();
|
||||
field_order.sort_unstable();
|
||||
Some(field_order)
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ pub enum Expression {
|
||||
Tuple(Vec<Expression>),
|
||||
Lookup(Lookup),
|
||||
Assign { lval: DefId, rval: Box<Expression> },
|
||||
Access { name: String, expr: Box<Expression> },
|
||||
Callable(Callable),
|
||||
Call { f: Box<Expression>, args: Vec<Expression> },
|
||||
Conditional { cond: Box<Expression>, then_clause: Vec<Statement>, else_clause: Vec<Statement> },
|
||||
|
@ -126,6 +126,28 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
||||
Expression::CaseMatch { box cond, alternatives } =>
|
||||
self.case_match_expression(cond, alternatives)?,
|
||||
Expression::ReductionError(e) => return Err(e.into()),
|
||||
Expression::Access { name, box expr } => {
|
||||
let expr = self.expression(expr)?;
|
||||
match expr {
|
||||
Primitive::Object { items, ordered_fields: Some(ordered_fields), .. } => {
|
||||
let idx = match ordered_fields.iter().position(|s| s == &name) {
|
||||
Some(idx) => idx,
|
||||
None => return Err(format!("Field `{}` not found", name).into()),
|
||||
};
|
||||
|
||||
let item = match items.get(idx) {
|
||||
Some(item) => item,
|
||||
None => return Err(format!("Field lookup `{}` failed", name).into()),
|
||||
};
|
||||
|
||||
item.clone()
|
||||
}
|
||||
e =>
|
||||
return Err(
|
||||
format!("Trying to do a field lookup on a non-object value: {:?}", e).into()
|
||||
),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![cfg(test)]
|
||||
use test_case::test_case;
|
||||
use pretty_assertions::assert_eq;
|
||||
use test_case::test_case;
|
||||
|
||||
use crate::{
|
||||
symbol_table::SymbolTable,
|
||||
@ -367,3 +367,14 @@ import Option::*
|
||||
let x = Some(9); if x is Some(q) then { q } else { 0 }"#;
|
||||
eval_assert(source, "9");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accessors() {
|
||||
let source = r#"
|
||||
type Klewos = Klewos { a: Int, b: String }
|
||||
let value = Klewos::Klewos { a: 50, b: "nah" }
|
||||
(value.a, value.b)
|
||||
"#;
|
||||
|
||||
eval_assert(source, r#"(50, "nah")"#);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user