start work on type resolver
This commit is contained in:
parent
b07eb248f1
commit
c3db966765
3 changed files with 152 additions and 12 deletions
|
@ -18,6 +18,18 @@ impl<'a> Command<'a> {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|def| TypeDef::from_internal(self.namespace, def))
|
.map(|def| TypeDef::from_internal(self.namespace, def))
|
||||||
}
|
}
|
||||||
|
// get a count of inputs required
|
||||||
|
pub fn input_count(&self) -> usize {
|
||||||
|
self.namespace.commands.borrow()[self.id]
|
||||||
|
.input
|
||||||
|
.as_ref()
|
||||||
|
.map(|inputs| match inputs {
|
||||||
|
InternalTypeDef::Single(_) => 1,
|
||||||
|
InternalTypeDef::List(list) => list.len(),
|
||||||
|
InternalTypeDef::Record(rec) => rec.len(),
|
||||||
|
})
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
pub fn get_output_types(&self) -> Option<TypeDef> {
|
pub fn get_output_types(&self) -> Option<TypeDef> {
|
||||||
self.namespace.commands.borrow()[self.id]
|
self.namespace.commands.borrow()[self.id]
|
||||||
.output
|
.output
|
||||||
|
|
|
@ -101,6 +101,18 @@ impl Debug for TypeDef<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Type<'a>> for TypeDef<'a> {
|
||||||
|
fn from(value: Type<'a>) -> Self {
|
||||||
|
TypeDef::Type(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Trait<'a>> for TypeDef<'a> {
|
||||||
|
fn from(value: Trait<'a>) -> Self {
|
||||||
|
TypeDef::Trait(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) enum InternalTypeDef {
|
pub(super) enum InternalTypeDef {
|
||||||
Single(TypeNamespaceId),
|
Single(TypeNamespaceId),
|
||||||
List(Vec<InternalTypeDef>),
|
List(Vec<InternalTypeDef>),
|
||||||
|
|
138
src/typed.rs
138
src/typed.rs
|
@ -1,9 +1,15 @@
|
||||||
use core::panic;
|
use core::panic;
|
||||||
|
use std::process::CommandEnvs;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
builtins::{TYPE_FLOAT, TYPE_INTEGER, TYPE_STRING},
|
builtins::{TYPE_FLOAT, TYPE_INTEGER, TYPE_STRING},
|
||||||
error::Errors,
|
error::Errors,
|
||||||
namespace::{command::Command, r#type::Type, GlobalNamespace},
|
namespace::{
|
||||||
|
command::{self, Command},
|
||||||
|
r#type::Type,
|
||||||
|
typedef::TypeDef,
|
||||||
|
GlobalNamespace,
|
||||||
|
},
|
||||||
syntax::{CommandPart, CommandPartKind, PipelineElement, PipelineElementKind},
|
syntax::{CommandPart, CommandPartKind, PipelineElement, PipelineElementKind},
|
||||||
Span,
|
Span,
|
||||||
};
|
};
|
||||||
|
@ -15,13 +21,57 @@ pub struct Expr<'a> {
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> Expr<'a> {
|
||||||
|
fn try_find_concrete(&'a self, ns: &'a GlobalNamespace) -> IoTypes<'a> {
|
||||||
|
let Self { ref kind, .. } = self;
|
||||||
|
kind.try_find_concrete(ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_input_typedef(&'a self) -> Option<TypeDef<'a>> {
|
||||||
|
match &self.kind {
|
||||||
|
ExprKind::Command(c) => c.command.get_input_types(),
|
||||||
|
ExprKind::Literal(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ExprKind<'a> {
|
pub enum ExprKind<'a> {
|
||||||
Command {
|
Command(CommandExpr<'a>),
|
||||||
|
Literal(LiteralKind),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ExprKind<'a> {
|
||||||
|
fn try_find_concrete(&'a self, ns: &'a GlobalNamespace) -> IoTypes<'a> {
|
||||||
|
match self {
|
||||||
|
ExprKind::Literal(lit) => IoTypes::Concrete(lit.get_type(ns)),
|
||||||
|
ExprKind::Command(c) => c.try_find_concrete(ns),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct CommandExpr<'a> {
|
||||||
command: Command<'a>,
|
command: Command<'a>,
|
||||||
args: Vec<Expr<'a>>,
|
args: Vec<Expr<'a>>,
|
||||||
},
|
}
|
||||||
Literal(LiteralKind),
|
|
||||||
|
impl<'a> CommandExpr<'a> {
|
||||||
|
fn try_find_concrete(&'a self, ns: &'a GlobalNamespace) -> IoTypes<'a> {
|
||||||
|
let Self { command, args } = self;
|
||||||
|
|
||||||
|
match command.get_output_types() {
|
||||||
|
None => IoTypes::Empty,
|
||||||
|
Some(def) => {
|
||||||
|
if let Some(concrete) = ConcreteTypeDef::try_from_typedef(&def) {
|
||||||
|
IoTypes::Concrete(concrete)
|
||||||
|
} else {
|
||||||
|
// TODO: make it possible to get clear output type
|
||||||
|
IoTypes::Unclear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -31,17 +81,26 @@ pub enum LiteralKind {
|
||||||
String(String),
|
String(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum IoTypes<'a> {
|
||||||
|
/// expression does not expect/return anything
|
||||||
|
Empty,
|
||||||
|
/// expression does expect/return something, but some types are unclear
|
||||||
|
Unclear,
|
||||||
|
/// we know for sure what types the expression expects/returns
|
||||||
|
Concrete(ConcreteTypeDef<'a>),
|
||||||
|
}
|
||||||
|
|
||||||
impl LiteralKind {
|
impl LiteralKind {
|
||||||
#[allow(
|
#[allow(
|
||||||
clippy::unwrap_used,
|
clippy::unwrap_used,
|
||||||
reason = "these are fetched by type name constants used for keeping names consistent in codebase, which cannot be None"
|
reason = "these are fetched by type name constants used for keeping names consistent in codebase, which cannot be None"
|
||||||
)]
|
)]
|
||||||
pub fn get_type<'a>(&self, ns: &'a GlobalNamespace) -> Type<'a> {
|
pub fn get_type<'a>(&self, ns: &'a GlobalNamespace) -> ConcreteTypeDef<'a> {
|
||||||
match self {
|
ConcreteTypeDef::Single(match self {
|
||||||
LiteralKind::Int(_) => ns.get_type_by_name(TYPE_INTEGER).unwrap(),
|
LiteralKind::Int(_) => ns.get_type_by_name(TYPE_INTEGER).unwrap(),
|
||||||
LiteralKind::Float(_) => ns.get_type_by_name(TYPE_FLOAT).unwrap(),
|
LiteralKind::Float(_) => ns.get_type_by_name(TYPE_FLOAT).unwrap(),
|
||||||
LiteralKind::String(_) => ns.get_type_by_name(TYPE_STRING).unwrap(),
|
LiteralKind::String(_) => ns.get_type_by_name(TYPE_STRING).unwrap(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +120,7 @@ pub fn into_typed_repr(
|
||||||
|
|
||||||
res.push(Expr {
|
res.push(Expr {
|
||||||
kind: match kind {
|
kind: match kind {
|
||||||
CommandPartKind::Word(val) => ExprKind::Command {
|
CommandPartKind::Word(val) => ExprKind::Command(CommandExpr {
|
||||||
command: {
|
command: {
|
||||||
let Some(c) = ns.get_command_by_name(val) else {
|
let Some(c) = ns.get_command_by_name(val) else {
|
||||||
errs.push(span);
|
errs.push(span);
|
||||||
|
@ -70,7 +129,7 @@ pub fn into_typed_repr(
|
||||||
c
|
c
|
||||||
},
|
},
|
||||||
args: Vec::new(),
|
args: Vec::new(),
|
||||||
},
|
}),
|
||||||
CommandPartKind::Integer(val) => {
|
CommandPartKind::Integer(val) => {
|
||||||
ExprKind::Literal(LiteralKind::Int(*val))
|
ExprKind::Literal(LiteralKind::Int(*val))
|
||||||
}
|
}
|
||||||
|
@ -93,7 +152,7 @@ pub fn into_typed_repr(
|
||||||
};
|
};
|
||||||
|
|
||||||
res.push(Expr {
|
res.push(Expr {
|
||||||
kind: ExprKind::Command {
|
kind: ExprKind::Command(CommandExpr {
|
||||||
command: {
|
command: {
|
||||||
let Some(c) = ns.get_command_by_name(name) else {
|
let Some(c) = ns.get_command_by_name(name) else {
|
||||||
errs.push(span.clone());
|
errs.push(span.clone());
|
||||||
|
@ -116,7 +175,7 @@ pub fn into_typed_repr(
|
||||||
span: span.clone(),
|
span: span.clone(),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
},
|
}),
|
||||||
span: span.clone(),
|
span: span.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -131,3 +190,60 @@ pub fn into_typed_repr(
|
||||||
Err(Errors::new(crate::error::ErrorKind::CommandNotFound, errs))
|
Err(Errors::new(crate::error::ErrorKind::CommandNotFound, errs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ConcreteTypeDef<'a> {
|
||||||
|
Single(Type<'a>),
|
||||||
|
List(Vec<ConcreteTypeDef<'a>>),
|
||||||
|
Record(Vec<(String, ConcreteTypeDef<'a>)>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ConcreteTypeDef<'a> {
|
||||||
|
fn try_from_typedef(val: &TypeDef<'a>) -> Option<Self> {
|
||||||
|
match val {
|
||||||
|
TypeDef::Type(typ) => Some(Self::Single(*typ)),
|
||||||
|
TypeDef::Trait(_) => None,
|
||||||
|
TypeDef::List(list) => {
|
||||||
|
let out: Vec<ConcreteTypeDef<'a>> =
|
||||||
|
list.iter().filter_map(Self::try_from_typedef).collect();
|
||||||
|
|
||||||
|
(out.len() == list.len()).then_some(ConcreteTypeDef::List(out))
|
||||||
|
}
|
||||||
|
TypeDef::Record(rec) => {
|
||||||
|
let out: Vec<(String, ConcreteTypeDef<'a>)> = rec
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(name, def)| {
|
||||||
|
Self::try_from_typedef(def).map(|def| (name.clone(), def))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
(out.len() == rec.len()).then_some(ConcreteTypeDef::Record(out))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TypeChecker<'a> {
|
||||||
|
global_ns: &'a GlobalNamespace,
|
||||||
|
typed_syntax: Vec<Expr<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TypeChecker<'a> {
|
||||||
|
fn new(ns: &'a GlobalNamespace, syntax: Vec<Expr<'a>>) -> TypeChecker<'a> {
|
||||||
|
Self {
|
||||||
|
global_ns: ns,
|
||||||
|
typed_syntax: syntax,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not sure if this is the optimal alg, or even a working one, but lets see
|
||||||
|
fn check_forward(&self) {
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
// loop {
|
||||||
|
// let maybe_concrete = match self.typed_syntax[i].kind {
|
||||||
|
// ExprKind::Literal(l) => todo!(),
|
||||||
|
// ExprKind::Command(c) => todo!(),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue