forked from M-Labs/nac3
core: Move some SymbolValue functions to symbol_resolver.rs
This commit is contained in:
parent
c93ad152d7
commit
b6dfcfcc38
|
@ -1,11 +1,12 @@
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{collections::HashMap, fmt::Display};
|
use std::{collections::HashMap, fmt::Display};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::typecheck::typedef::TypeEnum;
|
use crate::typecheck::typedef::TypeEnum;
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::CodeGenContext,
|
codegen::CodeGenContext,
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef, type_annotation::TypeAnnotation},
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::CodeGenerator,
|
codegen::CodeGenerator,
|
||||||
|
@ -16,7 +17,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use inkwell::values::{BasicValueEnum, FloatValue, IntValue, PointerValue, StructValue};
|
use inkwell::values::{BasicValueEnum, FloatValue, IntValue, PointerValue, StructValue};
|
||||||
use itertools::{chain, izip};
|
use itertools::{chain, izip};
|
||||||
use nac3parser::ast::{Expr, Location, StrRef};
|
use nac3parser::ast::{Constant, Expr, Location, StrRef};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
@ -33,6 +34,147 @@ pub enum SymbolValue {
|
||||||
OptionNone,
|
OptionNone,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SymbolValue {
|
||||||
|
/// Creates a [SymbolValue] from a [Constant].
|
||||||
|
///
|
||||||
|
/// * `constant` - The constant to create the value from.
|
||||||
|
/// * `expected_ty` - The expected type of the [SymbolValue].
|
||||||
|
pub fn from_constant(
|
||||||
|
constant: &Constant,
|
||||||
|
expected_ty: Type,
|
||||||
|
primitives: &PrimitiveStore,
|
||||||
|
unifier: &mut Unifier
|
||||||
|
) -> Result<Self, String> {
|
||||||
|
match constant {
|
||||||
|
Constant::None => {
|
||||||
|
if unifier.unioned(expected_ty, primitives.option) {
|
||||||
|
Ok(SymbolValue::OptionNone)
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected {:?}, but got Option", expected_ty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constant::Bool(b) => {
|
||||||
|
if unifier.unioned(expected_ty, primitives.bool) {
|
||||||
|
Ok(SymbolValue::Bool(*b))
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected {:?}, but got bool", expected_ty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constant::Str(s) => {
|
||||||
|
if unifier.unioned(expected_ty, primitives.str) {
|
||||||
|
Ok(SymbolValue::Str(s.to_string()))
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected {:?}, but got str", expected_ty))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Constant::Int(i) => {
|
||||||
|
if unifier.unioned(expected_ty, primitives.int32) {
|
||||||
|
i32::try_from(*i)
|
||||||
|
.map(|val| SymbolValue::I32(val))
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
} else if unifier.unioned(expected_ty, primitives.int64) {
|
||||||
|
i64::try_from(*i)
|
||||||
|
.map(|val| SymbolValue::I64(val))
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
} else if unifier.unioned(expected_ty, primitives.uint32) {
|
||||||
|
u32::try_from(*i)
|
||||||
|
.map(|val| SymbolValue::U32(val))
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
} else if unifier.unioned(expected_ty, primitives.uint64) {
|
||||||
|
u64::try_from(*i)
|
||||||
|
.map(|val| SymbolValue::U64(val))
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected {:?}, but got int", expected_ty))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Constant::Tuple(t) => {
|
||||||
|
let expected_ty = unifier.get_ty(expected_ty);
|
||||||
|
let TypeEnum::TTuple { ty } = expected_ty.as_ref() else {
|
||||||
|
return Err(format!("Expected {:?}, but got Tuple", expected_ty.get_type_name()))
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(ty.len(), t.len());
|
||||||
|
|
||||||
|
let elems = t.into_iter()
|
||||||
|
.zip(ty)
|
||||||
|
.map(|(constant, ty)| Self::from_constant(constant, *ty, primitives, unifier))
|
||||||
|
.collect::<Result<Vec<SymbolValue>, _>>()?;
|
||||||
|
Ok(SymbolValue::Tuple(elems))
|
||||||
|
}
|
||||||
|
Constant::Float(f) => {
|
||||||
|
if unifier.unioned(expected_ty, primitives.float) {
|
||||||
|
Ok(SymbolValue::Double(*f))
|
||||||
|
} else {
|
||||||
|
Err(format!("Expected {:?}, but got float", expected_ty))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => Err(format!("Unsupported value type {:?}", constant)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [Type] representing the data type of this value.
|
||||||
|
pub fn get_type(&self, primitives: &PrimitiveStore, unifier: &mut Unifier) -> Type {
|
||||||
|
match self {
|
||||||
|
SymbolValue::I32(_) => primitives.int32,
|
||||||
|
SymbolValue::I64(_) => primitives.int64,
|
||||||
|
SymbolValue::U32(_) => primitives.uint32,
|
||||||
|
SymbolValue::U64(_) => primitives.uint64,
|
||||||
|
SymbolValue::Str(_) => primitives.str,
|
||||||
|
SymbolValue::Double(_) => primitives.float,
|
||||||
|
SymbolValue::Bool(_) => primitives.bool,
|
||||||
|
SymbolValue::Tuple(vs) => {
|
||||||
|
let vs_tys = vs
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.get_type(primitives, unifier))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
unifier.add_ty(TypeEnum::TTuple {
|
||||||
|
ty: vs_tys,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
SymbolValue::OptionSome(_) => primitives.option,
|
||||||
|
SymbolValue::OptionNone => primitives.option,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [TypeAnnotation] representing the data type of this value.
|
||||||
|
pub fn get_type_annotation(&self, primitives: &PrimitiveStore, unifier: &mut Unifier) -> TypeAnnotation {
|
||||||
|
match self {
|
||||||
|
SymbolValue::Bool(..) => TypeAnnotation::Primitive(primitives.bool),
|
||||||
|
SymbolValue::Double(..) => TypeAnnotation::Primitive(primitives.float),
|
||||||
|
SymbolValue::I32(..) => TypeAnnotation::Primitive(primitives.int32),
|
||||||
|
SymbolValue::I64(..) => TypeAnnotation::Primitive(primitives.int64),
|
||||||
|
SymbolValue::U32(..) => TypeAnnotation::Primitive(primitives.uint32),
|
||||||
|
SymbolValue::U64(..) => TypeAnnotation::Primitive(primitives.uint64),
|
||||||
|
SymbolValue::Str(..) => TypeAnnotation::Primitive(primitives.str),
|
||||||
|
SymbolValue::Tuple(vs) => {
|
||||||
|
let vs_tys = vs
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.get_type_annotation(primitives, unifier))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
TypeAnnotation::Tuple(vs_tys)
|
||||||
|
}
|
||||||
|
SymbolValue::OptionNone => TypeAnnotation::CustomClass {
|
||||||
|
id: primitives.option.get_obj_id(unifier),
|
||||||
|
params: Default::default(),
|
||||||
|
},
|
||||||
|
SymbolValue::OptionSome(v) => {
|
||||||
|
let ty = v.get_type_annotation(primitives, unifier);
|
||||||
|
TypeAnnotation::CustomClass {
|
||||||
|
id: primitives.option.get_obj_id(unifier),
|
||||||
|
params: vec![ty],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [TypeEnum] representing the data type of this value.
|
||||||
|
pub fn get_type_enum(&self, primitives: &PrimitiveStore, unifier: &mut Unifier) -> Rc<TypeEnum> {
|
||||||
|
let ty = self.get_type(primitives, unifier);
|
||||||
|
unifier.get_ty(ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for SymbolValue {
|
impl Display for SymbolValue {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -416,40 +416,6 @@ impl TopLevelComposer {
|
||||||
primitive: &PrimitiveStore,
|
primitive: &PrimitiveStore,
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
fn type_default_param(
|
|
||||||
val: &SymbolValue,
|
|
||||||
primitive: &PrimitiveStore,
|
|
||||||
unifier: &mut Unifier,
|
|
||||||
) -> TypeAnnotation {
|
|
||||||
match val {
|
|
||||||
SymbolValue::Bool(..) => TypeAnnotation::Primitive(primitive.bool),
|
|
||||||
SymbolValue::Double(..) => TypeAnnotation::Primitive(primitive.float),
|
|
||||||
SymbolValue::I32(..) => TypeAnnotation::Primitive(primitive.int32),
|
|
||||||
SymbolValue::I64(..) => TypeAnnotation::Primitive(primitive.int64),
|
|
||||||
SymbolValue::U32(..) => TypeAnnotation::Primitive(primitive.uint32),
|
|
||||||
SymbolValue::U64(..) => TypeAnnotation::Primitive(primitive.uint64),
|
|
||||||
SymbolValue::Str(..) => TypeAnnotation::Primitive(primitive.str),
|
|
||||||
SymbolValue::Tuple(vs) => {
|
|
||||||
let vs_tys = vs
|
|
||||||
.iter()
|
|
||||||
.map(|v| type_default_param(v, primitive, unifier))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
TypeAnnotation::Tuple(vs_tys)
|
|
||||||
}
|
|
||||||
SymbolValue::OptionNone => TypeAnnotation::CustomClass {
|
|
||||||
id: primitive.option.get_obj_id(unifier),
|
|
||||||
params: Default::default(),
|
|
||||||
},
|
|
||||||
SymbolValue::OptionSome(v) => {
|
|
||||||
let ty = type_default_param(v, primitive, unifier);
|
|
||||||
TypeAnnotation::CustomClass {
|
|
||||||
id: primitive.option.get_obj_id(unifier),
|
|
||||||
params: vec![ty],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_compatible(
|
fn is_compatible(
|
||||||
found: &TypeAnnotation,
|
found: &TypeAnnotation,
|
||||||
expect: &TypeAnnotation,
|
expect: &TypeAnnotation,
|
||||||
|
@ -481,7 +447,7 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let found = type_default_param(val, primitive, unifier);
|
let found = val.get_type_annotation(primitive, unifier);
|
||||||
if !is_compatible(&found, ty, unifier, primitive) {
|
if !is_compatible(&found, ty, unifier, primitive) {
|
||||||
Err(format!(
|
Err(format!(
|
||||||
"incompatible default parameter type, expect {}, found {}",
|
"incompatible default parameter type, expect {}, found {}",
|
||||||
|
|
Loading…
Reference in New Issue