mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-25 18:49:50 -04:00
snapshot
This commit is contained in:
parent
ce928b7bd2
commit
ff3ae77ab2
@ -372,6 +372,7 @@ impl Shape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(jwall): This needs to move wholesale into the Checker
|
||||||
pub fn narrow(&self, right: &Shape, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Self {
|
pub fn narrow(&self, right: &Shape, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Self {
|
||||||
match (self, right) {
|
match (self, right) {
|
||||||
(Shape::Str(_), Shape::Str(_))
|
(Shape::Str(_), Shape::Str(_))
|
||||||
|
@ -27,23 +27,30 @@ use super::{
|
|||||||
NarrowedShape, NotDef, Position, PositionedItem, SelectDef,
|
NarrowedShape, NotDef, Position, PositionedItem, SelectDef,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME(jwall): This needs to just go away.
|
||||||
/// Trait for shape derivation.
|
/// Trait for shape derivation.
|
||||||
pub trait DeriveShape {
|
pub trait DeriveShape {
|
||||||
/// Derive a shape using a provided symbol table.
|
/// Derive a shape using a provided symbol table.
|
||||||
fn derive_shape(&self, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape;
|
fn derive_shape(&self, symbol_table: &mut Vec<BTreeMap<Rc<str>, Shape>>) -> Shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeriveShape for FuncDef {
|
impl DeriveShape for FuncDef {
|
||||||
fn derive_shape(&self, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
fn derive_shape(&self, symbol_table: &mut Vec<BTreeMap<Rc<str>, Shape>>) -> Shape {
|
||||||
|
// FIXME(jwall): This is *all* wrong here.
|
||||||
// 1. First set up our symbols.
|
// 1. First set up our symbols.
|
||||||
let mut sym_table = self
|
let mut sym_table = self
|
||||||
.argdefs
|
.argdefs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|sym| (sym.val.clone(), dbg!(Shape::Hole(sym.clone()))))
|
.map(|sym| (sym.val.clone(), dbg!(Shape::Hole(sym.clone()))))
|
||||||
.collect::<BTreeMap<Rc<str>, Shape>>();
|
.collect::<BTreeMap<Rc<str>, Shape>>();
|
||||||
sym_table.append(&mut symbol_table.clone());
|
sym_table.append(
|
||||||
|
&mut (symbol_table
|
||||||
|
.last()
|
||||||
|
.expect("We should definitely have a symbol_table here")
|
||||||
|
.clone()),
|
||||||
|
);
|
||||||
// 2.Then determine the shapes of those symbols in our expression.
|
// 2.Then determine the shapes of those symbols in our expression.
|
||||||
let shape = self.fields.derive_shape(&mut sym_table);
|
let shape = self.fields.derive_shape(&mut vec![sym_table]);
|
||||||
// 3. Finally determine what the return shape can be.
|
// 3. Finally determine what the return shape can be.
|
||||||
// only include the closed over shapes.
|
// only include the closed over shapes.
|
||||||
let table = self
|
let table = self
|
||||||
@ -68,7 +75,7 @@ impl DeriveShape for FuncDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DeriveShape for ModuleDef {
|
impl DeriveShape for ModuleDef {
|
||||||
fn derive_shape(&self, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
fn derive_shape(&self, symbol_table: &mut Vec<BTreeMap<Rc<str>, Shape>>) -> Shape {
|
||||||
let sym_table: BTreeMap<Rc<str>, Shape> = self
|
let sym_table: BTreeMap<Rc<str>, Shape> = self
|
||||||
.arg_set
|
.arg_set
|
||||||
.iter()
|
.iter()
|
||||||
@ -102,15 +109,12 @@ impl DeriveShape for ModuleDef {
|
|||||||
.clone(),
|
.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Shape::Module(ModuleShape {
|
Shape::Module(ModuleShape { items, ret })
|
||||||
items,
|
|
||||||
ret,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeriveShape for SelectDef {
|
impl DeriveShape for SelectDef {
|
||||||
fn derive_shape(&self, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
fn derive_shape(&self, symbol_table: &mut Vec<BTreeMap<Rc<str>, Shape>>) -> Shape {
|
||||||
let SelectDef {
|
let SelectDef {
|
||||||
val: _,
|
val: _,
|
||||||
default: _,
|
default: _,
|
||||||
@ -123,12 +127,18 @@ impl DeriveShape for SelectDef {
|
|||||||
};
|
};
|
||||||
for (_, expr) in tuple {
|
for (_, expr) in tuple {
|
||||||
let shape = expr.derive_shape(symbol_table);
|
let shape = expr.derive_shape(symbol_table);
|
||||||
narrowed_shape.merge_in_shape(shape, symbol_table);
|
narrowed_shape.merge_in_shape(
|
||||||
|
shape,
|
||||||
|
symbol_table
|
||||||
|
.last_mut()
|
||||||
|
.expect("We should definitely have a symbol table here"),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Shape::Narrowed(narrowed_shape)
|
Shape::Narrowed(narrowed_shape)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(jwall): This needs to move wholesale into the Checker
|
||||||
fn derive_include_shape(
|
fn derive_include_shape(
|
||||||
IncludeDef {
|
IncludeDef {
|
||||||
pos,
|
pos,
|
||||||
@ -145,7 +155,8 @@ fn derive_include_shape(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_not_shape(def: &NotDef, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
// FIXME(jwall): This needs to move wholesale into the Checker
|
||||||
|
fn derive_not_shape(def: &NotDef, symbol_table: &mut Vec<BTreeMap<Rc<str>, Shape>>) -> Shape {
|
||||||
let shape = def.expr.as_ref().derive_shape(symbol_table);
|
let shape = def.expr.as_ref().derive_shape(symbol_table);
|
||||||
if let Shape::Boolean(_) = &shape {
|
if let Shape::Boolean(_) = &shape {
|
||||||
return Shape::Boolean(def.pos.clone());
|
return Shape::Boolean(def.pos.clone());
|
||||||
@ -167,7 +178,158 @@ fn derive_not_shape(def: &NotDef, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derive_copy_shape(def: &CopyDef, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
impl DeriveShape for Expression {
|
||||||
|
fn derive_shape(&self, symbol_table: &mut Vec<BTreeMap<Rc<str>, Shape>>) -> Shape {
|
||||||
|
match self {
|
||||||
|
Expression::Simple(v) => v.derive_shape(symbol_table),
|
||||||
|
Expression::Format(def) => Shape::Str(def.pos.clone()),
|
||||||
|
Expression::Not(def) => derive_not_shape(def, symbol_table),
|
||||||
|
Expression::Grouped(v, _pos) => v.as_ref().derive_shape(symbol_table),
|
||||||
|
Expression::Range(def) => Shape::List(NarrowedShape::new_with_pos(
|
||||||
|
vec![Shape::Int(def.start.pos().clone())],
|
||||||
|
def.pos.clone(),
|
||||||
|
)),
|
||||||
|
Expression::Cast(def) => match def.cast_type {
|
||||||
|
CastType::Int => Shape::Int(def.pos.clone()),
|
||||||
|
CastType::Str => Shape::Str(def.pos.clone()),
|
||||||
|
CastType::Float => Shape::Float(def.pos.clone()),
|
||||||
|
CastType::Bool => Shape::Boolean(def.pos.clone()),
|
||||||
|
},
|
||||||
|
Expression::Import(def) => Shape::Import(ImportShape::Unresolved(PositionedItem::new(
|
||||||
|
def.path.fragment.clone(),
|
||||||
|
def.path.pos.clone(),
|
||||||
|
))),
|
||||||
|
Expression::Binary(def) => {
|
||||||
|
let left_shape = def.left.derive_shape(symbol_table);
|
||||||
|
let right_shape = def.right.derive_shape(symbol_table);
|
||||||
|
// We need to do somethig different if it's a ShapeKind::DOT
|
||||||
|
if def.kind == BinaryExprType::DOT {
|
||||||
|
dbg!(&def);
|
||||||
|
// left_shape can be assumed to be of type tuple.
|
||||||
|
// If left_shape is not known it can be inferred to be a tuple with right
|
||||||
|
// shapes symbol as a field name.
|
||||||
|
if let Shape::Hole(p) = left_shape {
|
||||||
|
dbg!(&p);
|
||||||
|
if let Shape::Hole(pi) = right_shape {
|
||||||
|
dbg!(&pi);
|
||||||
|
let derived_shape = Shape::Tuple(PositionedItem::new(
|
||||||
|
// TODO(jeremy): This needs to be a token...
|
||||||
|
vec![(
|
||||||
|
pi.into(),
|
||||||
|
Shape::Narrowed(NarrowedShape {
|
||||||
|
pos: p.pos.clone(),
|
||||||
|
types: Vec::new(),
|
||||||
|
}),
|
||||||
|
)],
|
||||||
|
p.pos.clone(),
|
||||||
|
));
|
||||||
|
symbol_table.insert(p.val.clone(), derived_shape);
|
||||||
|
return Shape::Narrowed(NarrowedShape {
|
||||||
|
pos: p.pos.clone(),
|
||||||
|
types: Vec::new(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if let Shape::Tuple(fields_pi) = left_shape {
|
||||||
|
dbg!(&fields_pi);
|
||||||
|
if let Shape::Hole(pi) = right_shape {
|
||||||
|
dbg!(&pi);
|
||||||
|
for (sym, shape) in fields_pi.val {
|
||||||
|
if pi.val == sym.val {
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Shape::TypeErr(def.pos.clone(), "Invalid Tuple field selector".to_owned())
|
||||||
|
} else {
|
||||||
|
left_shape.narrow(&right_shape, symbol_table)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::Copy(def) => derive_copy_shape(def, symbol_table),
|
||||||
|
Expression::Include(def) => derive_include_shape(def),
|
||||||
|
Expression::Call(_) => todo!(),
|
||||||
|
Expression::Func(def) => def.derive_shape(symbol_table),
|
||||||
|
Expression::Select(def) => def.derive_shape(symbol_table),
|
||||||
|
Expression::FuncOp(_) => todo!(),
|
||||||
|
Expression::Module(def) => def.derive_shape(symbol_table),
|
||||||
|
Expression::Fail(_) => todo!(),
|
||||||
|
Expression::Debug(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn derive_field_list_shape(
|
||||||
|
flds: &Vec<(super::Token, Expression)>,
|
||||||
|
pos: &Position,
|
||||||
|
symbol_table: &mut Vec<BTreeMap<Rc<str>, Shape>>,
|
||||||
|
) -> Shape {
|
||||||
|
let mut field_shapes = Vec::new();
|
||||||
|
for &(ref tok, ref expr) in flds {
|
||||||
|
field_shapes.push((
|
||||||
|
PositionedItem::new(tok.fragment.clone(), tok.pos.clone()),
|
||||||
|
expr.derive_shape(symbol_table),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Shape::Tuple(PositionedItem::new(field_shapes, pos.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Checker {
|
||||||
|
symbol_table: Vec<BTreeMap<Rc<str>, Shape>>,
|
||||||
|
err_stack: Vec<BuildError>,
|
||||||
|
shape_stack: Vec<Shape>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jwall): I am beginning to suspect that derive_shape should be a Trait.
|
||||||
|
// It would allow me to specify the contract a little more specifically now that
|
||||||
|
// I'm basically implementing the method all over the place.
|
||||||
|
|
||||||
|
// TODO(jwall): The symbol table contract also needs to be fleshed out a little better.
|
||||||
|
// I need to acccount for scopes syntactic scopes a bit. packages, functions and modules all are a
|
||||||
|
// factor.
|
||||||
|
|
||||||
|
impl Checker {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
return Self {
|
||||||
|
symbol_table: vec![BTreeMap::new()],
|
||||||
|
err_stack: Vec::new(),
|
||||||
|
shape_stack: Vec::new(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_symbol_table(mut self, symbol_table: BTreeMap<Rc<str>, Shape>) -> Self {
|
||||||
|
self.symbol_table = vec![symbol_table];
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lookup_symbol<'a>(&'a self, sym: Rc<str>) -> Option<&'a Shape> {
|
||||||
|
for table in self.symbol_table.iter().rev() {
|
||||||
|
if let Some(shape) = table.get(&sym) {
|
||||||
|
return Some(shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_symbol(&mut self, sym: Rc<str>, shape: Shape) {
|
||||||
|
self.symbol_table.last_mut().map(|t| t.insert(sym, shape));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_shape(&mut self) -> Option<Shape> {
|
||||||
|
self.shape_stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn result(mut self) -> Result<BTreeMap<Rc<str>, Shape>, BuildError> {
|
||||||
|
if let Some(err) = self.err_stack.pop() {
|
||||||
|
Err(err)
|
||||||
|
} else {
|
||||||
|
Ok(self
|
||||||
|
.symbol_table
|
||||||
|
.pop()
|
||||||
|
.expect("We should have a symbol table here somehwere"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn derive_copy_shape(&mut self, def: &CopyDef) -> Shape {
|
||||||
let base_shape = def.selector.derive_shape(symbol_table);
|
let base_shape = def.selector.derive_shape(symbol_table);
|
||||||
match &base_shape {
|
match &base_shape {
|
||||||
// TODO(jwall): Should we allow a stack of these?
|
// TODO(jwall): Should we allow a stack of these?
|
||||||
@ -262,167 +424,6 @@ fn derive_copy_shape(def: &CopyDef, symbol_table: &mut BTreeMap<Rc<str>, Shape>)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DeriveShape for Expression {
|
|
||||||
fn derive_shape(&self, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
|
||||||
match self {
|
|
||||||
Expression::Simple(v) => v.derive_shape(symbol_table),
|
|
||||||
Expression::Format(def) => Shape::Str(def.pos.clone()),
|
|
||||||
Expression::Not(def) => derive_not_shape(def, symbol_table),
|
|
||||||
Expression::Grouped(v, _pos) => v.as_ref().derive_shape(symbol_table),
|
|
||||||
Expression::Range(def) => Shape::List(NarrowedShape::new_with_pos(
|
|
||||||
vec![Shape::Int(def.start.pos().clone())],
|
|
||||||
def.pos.clone(),
|
|
||||||
)),
|
|
||||||
Expression::Cast(def) => match def.cast_type {
|
|
||||||
CastType::Int => Shape::Int(def.pos.clone()),
|
|
||||||
CastType::Str => Shape::Str(def.pos.clone()),
|
|
||||||
CastType::Float => Shape::Float(def.pos.clone()),
|
|
||||||
CastType::Bool => Shape::Boolean(def.pos.clone()),
|
|
||||||
},
|
|
||||||
Expression::Import(def) => Shape::Import(ImportShape::Unresolved(PositionedItem::new(
|
|
||||||
def.path.fragment.clone(),
|
|
||||||
def.path.pos.clone(),
|
|
||||||
))),
|
|
||||||
Expression::Binary(def) => {
|
|
||||||
let left_shape = def.left.derive_shape(symbol_table);
|
|
||||||
let right_shape = def.right.derive_shape(symbol_table);
|
|
||||||
// We need to do somethig different if it's a ShapeKind::DOT
|
|
||||||
if def.kind == BinaryExprType::DOT {
|
|
||||||
dbg!(&def);
|
|
||||||
// left_shape can be assumed to be of type tuple.
|
|
||||||
// If left_shape is not known it can be inferred to be a tuple with right
|
|
||||||
// shapes symbol as a field name.
|
|
||||||
if let Shape::Hole(p) = left_shape {
|
|
||||||
dbg!(&p);
|
|
||||||
if let Shape::Hole(pi) = right_shape {
|
|
||||||
dbg!(&pi);
|
|
||||||
let derived_shape = Shape::Tuple(PositionedItem::new(
|
|
||||||
// TODO(jeremy): This needs to be a token...
|
|
||||||
vec![(
|
|
||||||
pi.into(),
|
|
||||||
Shape::Narrowed(NarrowedShape {
|
|
||||||
pos: p.pos.clone(),
|
|
||||||
types: Vec::new(),
|
|
||||||
}),
|
|
||||||
)],
|
|
||||||
p.pos.clone(),
|
|
||||||
));
|
|
||||||
symbol_table.insert(p.val.clone(), derived_shape);
|
|
||||||
return Shape::Narrowed(NarrowedShape {
|
|
||||||
pos: p.pos.clone(),
|
|
||||||
types: Vec::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else if let Shape::Tuple(fields_pi) = left_shape {
|
|
||||||
dbg!(&fields_pi);
|
|
||||||
if let Shape::Hole(pi) = right_shape {
|
|
||||||
dbg!(&pi);
|
|
||||||
for (sym, shape) in fields_pi.val {
|
|
||||||
if pi.val == sym.val {
|
|
||||||
return shape;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Shape::TypeErr(def.pos.clone(), "Invalid Tuple field selector".to_owned())
|
|
||||||
} else {
|
|
||||||
left_shape.narrow(&right_shape, symbol_table)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expression::Copy(def) => derive_copy_shape(def, symbol_table),
|
|
||||||
Expression::Include(def) => derive_include_shape(def),
|
|
||||||
Expression::Call(_) => todo!(),
|
|
||||||
Expression::Func(def) => def.derive_shape(symbol_table),
|
|
||||||
Expression::Select(def) => def.derive_shape(symbol_table),
|
|
||||||
Expression::FuncOp(_) => todo!(),
|
|
||||||
Expression::Module(def) => def.derive_shape(symbol_table),
|
|
||||||
Expression::Fail(_) => todo!(),
|
|
||||||
Expression::Debug(_) => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DeriveShape for Value {
|
|
||||||
fn derive_shape(&self, symbol_table: &mut BTreeMap<Rc<str>, Shape>) -> Shape {
|
|
||||||
match self {
|
|
||||||
Value::Empty(p) => Shape::Narrowed(NarrowedShape::new_with_pos(vec![], p.clone())),
|
|
||||||
Value::Boolean(p) => Shape::Boolean(p.pos.clone()),
|
|
||||||
Value::Int(p) => Shape::Int(p.pos.clone()),
|
|
||||||
Value::Float(p) => Shape::Float(p.pos.clone()),
|
|
||||||
Value::Str(p) => Shape::Str(p.pos.clone()),
|
|
||||||
Value::Symbol(p) => {
|
|
||||||
if let Some(s) = symbol_table.get(&p.val) {
|
|
||||||
s.clone()
|
|
||||||
} else {
|
|
||||||
Shape::Hole(p.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value::Tuple(flds) => derive_field_list_shape(&flds.val, &flds.pos, symbol_table),
|
|
||||||
Value::List(flds) => {
|
|
||||||
let mut field_shapes = Vec::new();
|
|
||||||
for f in &flds.elems {
|
|
||||||
field_shapes.push(f.derive_shape(symbol_table));
|
|
||||||
}
|
|
||||||
Shape::List(NarrowedShape::new_with_pos(field_shapes, flds.pos.clone()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn derive_field_list_shape(
|
|
||||||
flds: &Vec<(super::Token, Expression)>,
|
|
||||||
pos: &Position,
|
|
||||||
symbol_table: &mut BTreeMap<Rc<str>, Shape>,
|
|
||||||
) -> Shape {
|
|
||||||
let mut field_shapes = Vec::new();
|
|
||||||
for &(ref tok, ref expr) in flds {
|
|
||||||
field_shapes.push((
|
|
||||||
PositionedItem::new(tok.fragment.clone(), tok.pos.clone()),
|
|
||||||
expr.derive_shape(symbol_table),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Shape::Tuple(PositionedItem::new(field_shapes, pos.clone()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Checker {
|
|
||||||
symbol_table: BTreeMap<Rc<str>, Shape>,
|
|
||||||
err_stack: Vec<BuildError>,
|
|
||||||
shape_stack: Vec<Shape>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(jwall): I am beginning to suspect that derive_shape should be a Trait.
|
|
||||||
// It would allow me to specify the contract a little more specifically now that
|
|
||||||
// I'm basically implementing the method all over the place.
|
|
||||||
|
|
||||||
// TODO(jwall): The symbol table contract also needs to be fleshed out a little better.
|
|
||||||
// I need to acccount for scopes syntactic scopes a bit. packages, functions and modules all are a
|
|
||||||
// factor.
|
|
||||||
|
|
||||||
impl Checker {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
return Self {
|
|
||||||
symbol_table: BTreeMap::new(),
|
|
||||||
err_stack: Vec::new(),
|
|
||||||
shape_stack: Vec::new(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_symbol_table(mut self, symbol_table: BTreeMap<Rc<str>, Shape>) -> Self {
|
|
||||||
self.symbol_table = symbol_table;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop_shape(&mut self) -> Option<Shape> {
|
|
||||||
self.shape_stack.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn result(mut self) -> Result<BTreeMap<Rc<str>, Shape>, BuildError> {
|
|
||||||
if let Some(err) = self.err_stack.pop() {
|
|
||||||
Err(err)
|
|
||||||
} else {
|
|
||||||
Ok(self.symbol_table)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Visitor for Checker {
|
impl Visitor for Checker {
|
||||||
@ -451,28 +452,31 @@ impl Visitor for Checker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_value(&mut self, val: &mut Value) {
|
fn visit_value(&mut self, val: &mut Value) {
|
||||||
match val {
|
let shape = match val {
|
||||||
Value::Empty(p) => self
|
Value::Empty(p) => Shape::Narrowed(NarrowedShape::new_with_pos(vec![], p.clone())),
|
||||||
.shape_stack
|
Value::Boolean(p) => Shape::Boolean(p.pos.clone()),
|
||||||
.push(Shape::Narrowed(NarrowedShape::new_with_pos(
|
Value::Int(p) => Shape::Int(p.pos.clone()),
|
||||||
vec![],
|
Value::Float(p) => Shape::Float(p.pos.clone()),
|
||||||
p.clone(),
|
Value::Str(p) => Shape::Str(p.pos.clone()),
|
||||||
))),
|
Value::Symbol(p) => {
|
||||||
Value::Boolean(p) => self.shape_stack.push(Shape::Boolean(p.pos.clone())),
|
if let Some(s) = self.lookup_symbol(p.val.clone()) {
|
||||||
Value::Int(p) => self.shape_stack.push(Shape::Int(p.pos.clone())),
|
s.clone()
|
||||||
Value::Float(p) => self.shape_stack.push(Shape::Float(p.pos.clone())),
|
} else {
|
||||||
Value::Str(p) => self.shape_stack.push(Shape::Str(p.pos.clone())),
|
Shape::Hole(p.clone())
|
||||||
// Symbols in a shape are placeholders. They allow a form of genericity
|
|
||||||
// in the shape. They can be any type and are only refined down.
|
|
||||||
// by their presence in an expression.
|
|
||||||
Value::Symbol(p) => self.shape_stack.push(Shape::Hole(p.clone())),
|
|
||||||
Value::List(_) => {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
Value::Tuple(_) => {
|
|
||||||
// noop
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// FIXME(jwall): This needs to be handled differently
|
||||||
|
Value::Tuple(flds) => derive_field_list_shape(&flds.val, &flds.pos, symbol_table),
|
||||||
|
// FIXME(jwall): This needs to be handled differently
|
||||||
|
Value::List(flds) => {
|
||||||
|
let mut field_shapes = Vec::new();
|
||||||
|
for f in &flds.elems {
|
||||||
|
field_shapes.push(f.derive_shape(&mut self.symbol_table));
|
||||||
|
}
|
||||||
|
Shape::List(NarrowedShape::new_with_pos(field_shapes, flds.pos.clone()))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.shape_stack.push(shape)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave_value(&mut self, _val: &Value) {
|
fn leave_value(&mut self, _val: &Value) {
|
||||||
@ -507,7 +511,11 @@ impl Visitor for Checker {
|
|||||||
pos.clone(),
|
pos.clone(),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
self.symbol_table.insert(name.clone(), shape.clone());
|
// FIXME(jwall): Should this insert a new symbol_tableif it doesn't exist?
|
||||||
|
self.symbol_table
|
||||||
|
.last_mut()
|
||||||
|
.map(|t| t.insert(name.clone(), shape.clone()))
|
||||||
|
.expect("We should already have a symbol table here");
|
||||||
self.shape_stack.push(shape);
|
self.shape_stack.push(shape);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,8 @@ macro_rules! assert_type_success {
|
|||||||
let mut expr = parse($e.into(), None).unwrap();
|
let mut expr = parse($e.into(), None).unwrap();
|
||||||
checker.walk_statement_list(expr.iter_mut().collect());
|
checker.walk_statement_list(expr.iter_mut().collect());
|
||||||
let maybe_shape = checker.pop_shape();
|
let maybe_shape = checker.pop_shape();
|
||||||
assert_eq!(checker.symbol_table[$expected_sym], $shape);
|
// FIXME?(jwall): We should probably just use an symbol table lookup api here.
|
||||||
|
assert_eq!(checker.symbol_table.last().map(|t| t[$expected_sym]), Some($shape));
|
||||||
let result = checker.result();
|
let result = checker.result();
|
||||||
assert!(result.is_ok(), "We expect this to typecheck successfully.");
|
assert!(result.is_ok(), "We expect this to typecheck successfully.");
|
||||||
assert!(maybe_shape.is_some(), "We got a shape out of it");
|
assert!(maybe_shape.is_some(), "We got a shape out of it");
|
||||||
@ -154,7 +155,7 @@ macro_rules! infer_symbol_test {
|
|||||||
let symbol = $sym_list[idx].0.clone();
|
let symbol = $sym_list[idx].0.clone();
|
||||||
checker
|
checker
|
||||||
.symbol_table
|
.symbol_table
|
||||||
.insert(symbol.clone(), shape.clone());
|
.last_mut(|t| t.insert(symbol.clone(), shape.clone()));
|
||||||
}
|
}
|
||||||
let tokens = tokenize(expr, None).unwrap();
|
let tokens = tokenize(expr, None).unwrap();
|
||||||
let token_iter = SliceIter::new(&tokens);
|
let token_iter = SliceIter::new(&tokens);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user