Some improvements to the type system
This commit is contained in:
@ -31,7 +31,7 @@ pub enum Step {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Type {
|
||||
pub enum BaseType {
|
||||
Int,
|
||||
Float,
|
||||
String,
|
||||
@ -41,57 +41,143 @@ pub enum Type {
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl ToString for Type {
|
||||
impl ToString for BaseType {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Type::Int => "int".to_string(),
|
||||
Type::Float => "float".to_string(),
|
||||
Type::String => "string".to_string(),
|
||||
Type::Bool => "bool".to_string(),
|
||||
Type::Bytes => "bytes".to_string(),
|
||||
Type::Void => "void".to_string(),
|
||||
Type::Custom(name) => name.clone(),
|
||||
BaseType::Int => "int".to_string(),
|
||||
BaseType::Float => "float".to_string(),
|
||||
BaseType::String => "string".to_string(),
|
||||
BaseType::Bool => "bool".to_string(),
|
||||
BaseType::Bytes => "bytes".to_string(),
|
||||
BaseType::Void => "void".to_string(),
|
||||
BaseType::Custom(name) => name.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Type {
|
||||
impl Hash for BaseType {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.to_string().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&String> for Type {
|
||||
impl From<&String> for BaseType {
|
||||
fn from(value: &String) -> Self {
|
||||
Self::from(value.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Type {
|
||||
impl From<String> for BaseType {
|
||||
fn from(value: String) -> Self {
|
||||
Self::from(value.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Type {
|
||||
impl From<&str> for BaseType {
|
||||
fn from(s: &str) -> Self {
|
||||
match s {
|
||||
"int" => Type::Int,
|
||||
"float" => Type::Float,
|
||||
"string" => Type::String,
|
||||
"bool" => Type::Bool,
|
||||
"boolean" => Type::Bool,
|
||||
"bytes" => Type::Bytes,
|
||||
"void" => Type::Void,
|
||||
_ => Type::Custom(s.to_string()),
|
||||
"int" => BaseType::Int,
|
||||
"float" => BaseType::Float,
|
||||
"string" => BaseType::String,
|
||||
"bool" => BaseType::Bool,
|
||||
"boolean" => BaseType::Bool,
|
||||
"bytes" => BaseType::Bytes,
|
||||
"void" => BaseType::Void,
|
||||
_ => BaseType::Custom(s.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum TypeModifier {
|
||||
None,
|
||||
Array,
|
||||
Optional,
|
||||
Map(BaseType),
|
||||
OptionalArray,
|
||||
OptionalMap(BaseType),
|
||||
OptionalMapArray(BaseType),
|
||||
MapArray(BaseType),
|
||||
}
|
||||
|
||||
impl TypeModifier {
|
||||
pub fn from_flags(optional: bool, array: bool, map: Option<BaseType>) -> Self {
|
||||
match (optional, array, map) {
|
||||
(false, false, None) => Self::None,
|
||||
(false, true, None) => Self::Array,
|
||||
(true, false, None) => Self::Optional,
|
||||
(true, true, None) => Self::OptionalArray,
|
||||
(false, false, Some(map)) => Self::Map(map),
|
||||
(false, true, Some(map)) => Self::MapArray(map),
|
||||
(true, false, Some(map)) => Self::OptionalMap(map),
|
||||
(true, true, Some(map)) => Self::OptionalMapArray(map),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> (bool, bool, Option<BaseType>) {
|
||||
match self.clone() {
|
||||
Self::None => (false, false, None),
|
||||
Self::Array => (false, true, None),
|
||||
Self::Optional => (true, false, None),
|
||||
Self::OptionalArray => (true, true, None),
|
||||
Self::Map(map) => (false, false, Some(map)),
|
||||
Self::MapArray(map) => (false, true, Some(map)),
|
||||
Self::OptionalMap(map) => (true, false, Some(map)),
|
||||
Self::OptionalMapArray(map) => (true, true, Some(map)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Type(pub BaseType, pub TypeModifier);
|
||||
|
||||
impl Type {
|
||||
pub fn from_flags(base: BaseType, optional: bool, array: bool, map: Option<BaseType>) -> Self {
|
||||
Self(base, TypeModifier::from_flags(optional, array, map))
|
||||
}
|
||||
|
||||
/// Returns flags in the order of: (OPTIONAL, ARRAY, MAP)
|
||||
pub fn into_flags(self) -> (BaseType, bool, bool, Option<BaseType>) {
|
||||
let b = self.0.clone();
|
||||
match self.1 {
|
||||
TypeModifier::None => (b, false, false, None),
|
||||
TypeModifier::Array => (b, false, true, None),
|
||||
TypeModifier::Optional => (b, true, false, None),
|
||||
TypeModifier::OptionalArray => (b, true, true, None),
|
||||
TypeModifier::Map(map) => (b, false, false, Some(map)),
|
||||
TypeModifier::MapArray(map) => (b, false, true, Some(map)),
|
||||
TypeModifier::OptionalMap(map) => (b, true, false, Some(map)),
|
||||
TypeModifier::OptionalMapArray(map) => (b, true, true, Some(map)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_optional(&self) -> bool {
|
||||
self.1.get_flags().0
|
||||
}
|
||||
|
||||
pub fn is_array(&self) -> bool {
|
||||
self.1.get_flags().1
|
||||
}
|
||||
|
||||
pub fn is_map(&self) -> bool {
|
||||
self.1.get_flags().2.is_some()
|
||||
}
|
||||
|
||||
pub fn get_map(&self) -> Option<BaseType> {
|
||||
self.1.get_flags().2.clone()
|
||||
}
|
||||
}
|
||||
// {
|
||||
// pub base: BaseType,
|
||||
// pub array: bool,
|
||||
// pub optional: bool,
|
||||
// pub map: Option<BaseType>,
|
||||
// }
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TypeDefinition {
|
||||
pub name: String,
|
||||
pub depends: HashSet<Type>,
|
||||
pub depends: HashSet<BaseType>,
|
||||
pub fields: Vec<Field>,
|
||||
pub position: ParserPosition,
|
||||
}
|
||||
@ -106,9 +192,6 @@ impl Definition for TypeDefinition {
|
||||
pub struct Field {
|
||||
pub name: String,
|
||||
pub typ: Type,
|
||||
pub array: bool,
|
||||
pub optional: bool,
|
||||
pub map: Option<Type>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -133,7 +216,7 @@ pub struct EnumField {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ServiceDefinition {
|
||||
pub name: String,
|
||||
pub depends: HashSet<Type>,
|
||||
pub depends: HashSet<BaseType>,
|
||||
pub methods: Vec<Method>,
|
||||
pub position: ParserPosition,
|
||||
}
|
||||
@ -156,14 +239,11 @@ pub struct Method {
|
||||
pub struct MethodInput {
|
||||
pub name: String,
|
||||
pub typ: Type,
|
||||
pub array: bool,
|
||||
pub optional: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MethodOutput {
|
||||
pub typ: Type,
|
||||
pub array: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -182,7 +262,7 @@ fn build_type(stmt: &TypeStatement) -> Result<TypeDefinition> {
|
||||
};
|
||||
|
||||
for field in &stmt.fields {
|
||||
let typ = Type::from(&field.fieldtype);
|
||||
let typ = BaseType::from(&field.fieldtype);
|
||||
typedef.depends.insert(typ.clone());
|
||||
|
||||
if let Some(maptype) = &field.map {
|
||||
@ -193,10 +273,12 @@ fn build_type(stmt: &TypeStatement) -> Result<TypeDefinition> {
|
||||
|
||||
typedef.fields.push(Field {
|
||||
name: field.name.clone(),
|
||||
typ: typ.clone(),
|
||||
array: field.array,
|
||||
optional: field.optional,
|
||||
map: field.map.as_ref().map(|s| Type::from(s)),
|
||||
typ: Type::from_flags(
|
||||
typ.clone(),
|
||||
field.optional,
|
||||
field.array,
|
||||
field.map.as_ref().map(|s| BaseType::from(s)),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
@ -247,14 +329,11 @@ fn build_service(stmt: &ServiceStatement) -> Result<ServiceDefinition> {
|
||||
name: method.name.clone(),
|
||||
inputs: Vec::new(),
|
||||
output: method.return_type.as_ref().map(|rt| {
|
||||
let typ = Type::from(&rt.fieldtype);
|
||||
if typ != Type::Void {
|
||||
servdef.depends.insert(typ.clone());
|
||||
}
|
||||
MethodOutput {
|
||||
typ,
|
||||
array: rt.array,
|
||||
let typ = Type::from_flags(BaseType::from(&rt.fieldtype), false, rt.array, None);
|
||||
if typ.0 != BaseType::Void {
|
||||
servdef.depends.insert(typ.0.clone());
|
||||
}
|
||||
MethodOutput { typ }
|
||||
}),
|
||||
decorators: MethodDecorators {
|
||||
description: None,
|
||||
@ -265,7 +344,7 @@ fn build_service(stmt: &ServiceStatement) -> Result<ServiceDefinition> {
|
||||
|
||||
let mut optional_starts = false;
|
||||
for inp in &method.inputs {
|
||||
let typ = Type::from(&inp.fieldtype);
|
||||
let typ = BaseType::from(&inp.fieldtype);
|
||||
servdef.depends.insert(typ.clone());
|
||||
|
||||
if optional_starts && !inp.optional {
|
||||
@ -280,9 +359,7 @@ fn build_service(stmt: &ServiceStatement) -> Result<ServiceDefinition> {
|
||||
|
||||
methoddef.inputs.push(MethodInput {
|
||||
name: inp.name.clone(),
|
||||
typ,
|
||||
array: inp.array,
|
||||
optional: inp.optional,
|
||||
typ: Type::from_flags(typ.clone(), inp.optional, inp.array, None),
|
||||
});
|
||||
}
|
||||
|
||||
@ -426,7 +503,7 @@ pub fn build_ir(root: &Vec<RootNode>) -> Result<IR> {
|
||||
match step {
|
||||
Step::Type(typedef) => {
|
||||
for dep in &typedef.depends {
|
||||
if let Type::Custom(dep) = dep {
|
||||
if let BaseType::Custom(dep) = dep {
|
||||
if !all_types.contains(dep) {
|
||||
return Err(IRError::new_from_def(
|
||||
&format!("Type {} depends on unknown type {}", typedef.name, dep),
|
||||
@ -439,7 +516,7 @@ pub fn build_ir(root: &Vec<RootNode>) -> Result<IR> {
|
||||
}
|
||||
Step::Service(servdef) => {
|
||||
for dep in &servdef.depends {
|
||||
if let Type::Custom(dep) = dep {
|
||||
if let BaseType::Custom(dep) = dep {
|
||||
if !all_types.contains(dep) {
|
||||
return Err(IRError::new_from_def(
|
||||
&format!(
|
||||
|
Reference in New Issue
Block a user