conlang: add lang items, remove Empty
, and shuffle typeck
This commit is contained in:
parent
ead1f351a7
commit
f41e5fc49a
@ -224,7 +224,6 @@ pub struct Ty {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum TyKind {
|
pub enum TyKind {
|
||||||
Never,
|
Never,
|
||||||
Empty,
|
|
||||||
Infer,
|
Infer,
|
||||||
Path(Path),
|
Path(Path),
|
||||||
Array(TyArray),
|
Array(TyArray),
|
||||||
|
@ -165,7 +165,6 @@ impl Display for Function {
|
|||||||
let Self { name, gens, sign: sign @ TyFn { args, rety }, bind, body } = self;
|
let Self { name, gens, sign: sign @ TyFn { args, rety }, bind, body } = self;
|
||||||
let types = match args.kind {
|
let types = match args.kind {
|
||||||
TyKind::Tuple(TyTuple { ref types }) => types.as_slice(),
|
TyKind::Tuple(TyTuple { ref types }) => types.as_slice(),
|
||||||
TyKind::Empty => Default::default(),
|
|
||||||
_ => {
|
_ => {
|
||||||
write!(f, "Invalid function signature: {sign}")?;
|
write!(f, "Invalid function signature: {sign}")?;
|
||||||
Default::default()
|
Default::default()
|
||||||
@ -191,7 +190,9 @@ impl Display for Function {
|
|||||||
write!(f, "{arg}: {ty}")?;
|
write!(f, "{arg}: {ty}")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if TyKind::Empty != rety.kind {
|
if let TyKind::Tuple(TyTuple { types }) = &rety.kind
|
||||||
|
&& !types.as_slice().is_empty()
|
||||||
|
{
|
||||||
write!(f, " -> {rety}")?
|
write!(f, " -> {rety}")?
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,7 +296,6 @@ impl Display for TyKind {
|
|||||||
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 {
|
||||||
TyKind::Never => "!".fmt(f),
|
TyKind::Never => "!".fmt(f),
|
||||||
TyKind::Empty => "()".fmt(f),
|
|
||||||
TyKind::Infer => "_".fmt(f),
|
TyKind::Infer => "_".fmt(f),
|
||||||
TyKind::Path(v) => v.fmt(f),
|
TyKind::Path(v) => v.fmt(f),
|
||||||
TyKind::Array(v) => v.fmt(f),
|
TyKind::Array(v) => v.fmt(f),
|
||||||
@ -349,8 +349,10 @@ impl Display for TyFn {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let Self { args, rety } = self;
|
let Self { args, rety } = self;
|
||||||
write!(f, "fn {args}")?;
|
write!(f, "fn {args}")?;
|
||||||
if TyKind::Empty != rety.kind {
|
if let TyKind::Tuple(TyTuple { types }) = &rety.kind
|
||||||
write!(f, " -> {rety}")?;
|
&& !types.as_slice().is_empty()
|
||||||
|
{
|
||||||
|
write!(f, " -> {rety}")?
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ impl WeightOf for Ty {
|
|||||||
impl WeightOf for TyKind {
|
impl WeightOf for TyKind {
|
||||||
fn weight_of(&self) -> usize {
|
fn weight_of(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
TyKind::Never | TyKind::Empty | TyKind::Infer => size_of_val(self),
|
TyKind::Never | TyKind::Infer => size_of_val(self),
|
||||||
TyKind::Path(v) => v.weight_of(),
|
TyKind::Path(v) => v.weight_of(),
|
||||||
TyKind::Array(v) => v.weight_of(),
|
TyKind::Array(v) => v.weight_of(),
|
||||||
TyKind::Slice(v) => v.weight_of(),
|
TyKind::Slice(v) => v.weight_of(),
|
||||||
|
@ -531,7 +531,6 @@ pub fn or_fold_use_tree<F: Fold + ?Sized>(folder: &mut F, tree: UseTree) -> UseT
|
|||||||
pub fn or_fold_ty_kind<F: Fold + ?Sized>(folder: &mut F, kind: TyKind) -> TyKind {
|
pub fn or_fold_ty_kind<F: Fold + ?Sized>(folder: &mut F, kind: TyKind) -> TyKind {
|
||||||
match kind {
|
match kind {
|
||||||
TyKind::Never => TyKind::Never,
|
TyKind::Never => TyKind::Never,
|
||||||
TyKind::Empty => TyKind::Empty,
|
|
||||||
TyKind::Infer => TyKind::Infer,
|
TyKind::Infer => TyKind::Infer,
|
||||||
TyKind::Path(p) => TyKind::Path(folder.fold_path(p)),
|
TyKind::Path(p) => TyKind::Path(folder.fold_path(p)),
|
||||||
TyKind::Array(a) => TyKind::Array(folder.fold_ty_array(a)),
|
TyKind::Array(a) => TyKind::Array(folder.fold_ty_array(a)),
|
||||||
|
@ -369,7 +369,6 @@ impl Walk for TyKind {
|
|||||||
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
fn children<'a, V: Visit<'a>>(&'a self, v: &mut V) {
|
||||||
match self {
|
match self {
|
||||||
TyKind::Never => {}
|
TyKind::Never => {}
|
||||||
TyKind::Empty => {}
|
|
||||||
TyKind::Infer => {}
|
TyKind::Infer => {}
|
||||||
TyKind::Path(value) => value.visit_in(v),
|
TyKind::Path(value) => value.visit_in(v),
|
||||||
TyKind::Array(value) => value.visit_in(v),
|
TyKind::Array(value) => value.visit_in(v),
|
||||||
|
@ -723,9 +723,12 @@ impl Interpret for Cast {
|
|||||||
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
|
||||||
let Cast { head, ty } = self;
|
let Cast { head, ty } = self;
|
||||||
let value = head.interpret(env)?;
|
let value = head.interpret(env)?;
|
||||||
if TyKind::Empty == ty.kind {
|
|
||||||
|
if let TyKind::Tuple(TyTuple { types }) = &ty.kind
|
||||||
|
&& types.as_slice().is_empty()
|
||||||
|
{
|
||||||
return Ok(ConValue::Empty);
|
return Ok(ConValue::Empty);
|
||||||
};
|
}
|
||||||
let TyKind::Path(Path { absolute: false, parts }) = &ty.kind else {
|
let TyKind::Path(Path { absolute: false, parts }) = &ty.kind else {
|
||||||
Err(Error::TypeError())?
|
Err(Error::TypeError())?
|
||||||
};
|
};
|
||||||
|
@ -464,13 +464,18 @@ impl Parse<'_> for Function {
|
|||||||
let gens = Generics::parse(p)?;
|
let gens = Generics::parse(p)?;
|
||||||
let ((bind, types), span) = delim(Spanned::<FnSig>::parse, PARENS, P)(p)?;
|
let ((bind, types), span) = delim(Spanned::<FnSig>::parse, PARENS, P)(p)?;
|
||||||
let sign = TyFn {
|
let sign = TyFn {
|
||||||
args: Box::new(match types.len() {
|
args: Box::new(Ty {
|
||||||
0 => Ty { span, kind: TyKind::Empty, gens: Default::default() },
|
span,
|
||||||
_ => Ty { span, kind: TyKind::Tuple(TyTuple { types }), gens: Default::default() },
|
kind: TyKind::Tuple(TyTuple { types }),
|
||||||
|
gens: Default::default(),
|
||||||
}),
|
}),
|
||||||
rety: Box::new(match p.match_type(TokenKind::Arrow, Parsing::TyFn) {
|
rety: Box::new(match p.match_type(TokenKind::Arrow, Parsing::TyFn) {
|
||||||
Ok(_) => Ty::parse(p)?,
|
Ok(_) => Ty::parse(p)?,
|
||||||
Err(_) => Ty { span, kind: TyKind::Empty, gens: Generics { vars: vec![] } },
|
Err(_) => Ty {
|
||||||
|
span,
|
||||||
|
kind: TyKind::Tuple(TyTuple { types: vec![] }),
|
||||||
|
gens: Generics { vars: vec![] },
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
Ok(Function {
|
Ok(Function {
|
||||||
@ -736,10 +741,7 @@ impl Parse<'_> for TyKind {
|
|||||||
}
|
}
|
||||||
TokenKind::LParen => {
|
TokenKind::LParen => {
|
||||||
let out = TyTuple::parse(p)?;
|
let out = TyTuple::parse(p)?;
|
||||||
match out.types.is_empty() {
|
TyKind::Tuple(out)
|
||||||
true => TyKind::Empty,
|
|
||||||
false => TyKind::Tuple(out),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TokenKind::Fn => TyFn::parse(p)?.into(),
|
TokenKind::Fn => TyFn::parse(p)?.into(),
|
||||||
path_like!() => {
|
path_like!() => {
|
||||||
@ -802,15 +804,18 @@ impl Parse<'_> for TyFn {
|
|||||||
let span = Span(head, p.loc());
|
let span = Span(head, p.loc());
|
||||||
|
|
||||||
Ok(TyFn {
|
Ok(TyFn {
|
||||||
args: Box::new(match args {
|
args: Box::new(Ty {
|
||||||
t if t.is_empty() => Ty { kind: TyKind::Empty, span, gens: Default::default() },
|
kind: TyKind::Tuple(TyTuple { types: args }),
|
||||||
types => {
|
span,
|
||||||
Ty { kind: TyKind::Tuple(TyTuple { types }), span, gens: Default::default() }
|
gens: Default::default(),
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
rety: Box::new(match p.match_type(TokenKind::Arrow, Parsing::TyFn) {
|
rety: Box::new(match p.match_type(TokenKind::Arrow, Parsing::TyFn) {
|
||||||
Ok(_) => Ty::parse(p)?,
|
Ok(_) => Ty::parse(p)?,
|
||||||
Err(_) => Ty { span, kind: TyKind::Empty, gens: Generics { vars: vec![] } },
|
Err(_) => Ty {
|
||||||
|
span,
|
||||||
|
kind: TyKind::Tuple(TyTuple { types: vec![] }),
|
||||||
|
gens: Generics { vars: vec![] },
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,6 @@ pub mod clangify {
|
|||||||
let TyFn { args, rety } = sign;
|
let TyFn { args, rety } = sign;
|
||||||
let types = match &args.kind {
|
let types = match &args.kind {
|
||||||
TyKind::Tuple(TyTuple { types }) => types.as_slice(),
|
TyKind::Tuple(TyTuple { types }) => types.as_slice(),
|
||||||
TyKind::Empty => &[],
|
|
||||||
_ => panic!("Unsupported function args: {args}"),
|
_ => panic!("Unsupported function args: {args}"),
|
||||||
};
|
};
|
||||||
let bind = match bind {
|
let bind = match bind {
|
||||||
@ -472,7 +471,6 @@ pub mod clangify {
|
|||||||
TyKind::Fn(TyFn { args, rety }) => {
|
TyKind::Fn(TyFn { args, rety }) => {
|
||||||
y.nest("(").p(rety).p(" *").p(mutable).p(name).p(")(");
|
y.nest("(").p(rety).p(" *").p(mutable).p(name).p(")(");
|
||||||
match &args.kind {
|
match &args.kind {
|
||||||
TyKind::Empty => {}
|
|
||||||
TyKind::Tuple(TyTuple { types }) => {
|
TyKind::Tuple(TyTuple { types }) => {
|
||||||
for (idx, ty) in types.iter().enumerate() {
|
for (idx, ty) in types.iter().enumerate() {
|
||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
@ -799,7 +797,6 @@ pub mod clangify {
|
|||||||
fn print(&self, y: &mut CLangifier) {
|
fn print(&self, y: &mut CLangifier) {
|
||||||
match self {
|
match self {
|
||||||
TyKind::Never => y.p("Never"),
|
TyKind::Never => y.p("Never"),
|
||||||
TyKind::Empty => y.p("Empty"),
|
|
||||||
TyKind::Infer => y.p("auto"),
|
TyKind::Infer => y.p("auto"),
|
||||||
TyKind::Path(t) => y.p(t),
|
TyKind::Path(t) => y.p(t),
|
||||||
TyKind::Tuple(t) => y.p(t),
|
TyKind::Tuple(t) => y.p(t),
|
||||||
@ -880,7 +877,6 @@ pub mod clangify {
|
|||||||
// TODO: function pointer syntax
|
// TODO: function pointer syntax
|
||||||
y.nest("(").p(rety).p(" *)(");
|
y.nest("(").p(rety).p(" *)(");
|
||||||
match &args.kind {
|
match &args.kind {
|
||||||
TyKind::Empty => y,
|
|
||||||
TyKind::Tuple(TyTuple { types }) => {
|
TyKind::Tuple(TyTuple { types }) => {
|
||||||
for (idx, ty) in types.iter().enumerate() {
|
for (idx, ty) in types.iter().enumerate() {
|
||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
|
@ -649,7 +649,6 @@ pub mod yamlify {
|
|||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
match self {
|
match self {
|
||||||
TyKind::Never => y.value("Never"),
|
TyKind::Never => y.value("Never"),
|
||||||
TyKind::Empty => y.value("Empty"),
|
|
||||||
TyKind::Infer => y.value("_"),
|
TyKind::Infer => y.value("_"),
|
||||||
TyKind::Path(t) => y.yaml(t),
|
TyKind::Path(t) => y.yaml(t),
|
||||||
TyKind::Tuple(t) => y.yaml(t),
|
TyKind::Tuple(t) => y.yaml(t),
|
||||||
@ -713,8 +712,7 @@ pub mod yamlify {
|
|||||||
impl Yamlify for TyPtr {
|
impl Yamlify for TyPtr {
|
||||||
fn yaml(&self, y: &mut Yamler) {
|
fn yaml(&self, y: &mut Yamler) {
|
||||||
let Self { to } = self;
|
let Self { to } = self;
|
||||||
y.key("TyPtr")
|
y.key("TyPtr").pair("to", to);
|
||||||
.pair("to", to);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Yamlify for TyFn {
|
impl Yamlify for TyFn {
|
||||||
|
@ -205,4 +205,8 @@ impl<'t, 'a> EntryMut<'t, 'a> {
|
|||||||
pub fn mark_impl_item(&mut self) {
|
pub fn mark_impl_item(&mut self) {
|
||||||
self.table.mark_impl_item(self.id)
|
self.table.mark_impl_item(self.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mark_lang_item(&mut self, lang_item: &'static str) {
|
||||||
|
self.table.mark_lang_item(lang_item, self.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,6 @@ impl fmt::Display for Entry<'_, '_> {
|
|||||||
write!(f, "fn {} -> ", self.with_id(*args))?;
|
write!(f, "fn {} -> ", self.with_id(*args))?;
|
||||||
write_name_or(self.with_id(*rety), f)
|
write_name_or(self.with_id(*rety), f)
|
||||||
}
|
}
|
||||||
TypeKind::Empty => write!(f, "()"),
|
|
||||||
TypeKind::Never => write!(f, "!"),
|
|
||||||
TypeKind::Module => write!(f, "module?"),
|
TypeKind::Module => write!(f, "module?"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,8 +17,6 @@ pub fn categorize(table: &mut Table, node: Handle) -> CatResult<()> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match source {
|
match source {
|
||||||
Source::Alias(a) => cat_alias(table, node, a)?,
|
|
||||||
Source::Enum(e) => cat_enum(table, node, e)?,
|
|
||||||
Source::Variant(v) => cat_variant(table, node, v)?,
|
Source::Variant(v) => cat_variant(table, node, v)?,
|
||||||
Source::Struct(s) => cat_struct(table, node, s)?,
|
Source::Struct(s) => cat_struct(table, node, s)?,
|
||||||
Source::Const(c) => cat_const(table, node, c)?,
|
Source::Const(c) => cat_const(table, node, c)?,
|
||||||
@ -26,21 +24,8 @@ pub fn categorize(table: &mut Table, node: Handle) -> CatResult<()> {
|
|||||||
Source::Function(f) => cat_function(table, node, f)?,
|
Source::Function(f) => cat_function(table, node, f)?,
|
||||||
Source::Local(l) => cat_local(table, node, l)?,
|
Source::Local(l) => cat_local(table, node, l)?,
|
||||||
Source::Impl(i) => cat_impl(table, node, i)?,
|
Source::Impl(i) => cat_impl(table, node, i)?,
|
||||||
_ => {}
|
// Source::Alias(_) => {table.mark_unchecked(node)},
|
||||||
}
|
_ => return Ok(()),
|
||||||
|
|
||||||
if let Some(meta) = table.meta(node) {
|
|
||||||
for meta @ Meta { name, kind } in meta {
|
|
||||||
if let ("lang", MetaKind::Equals(Literal::String(s))) = (&**name, kind) {
|
|
||||||
if let Ok(prim) = s.parse() {
|
|
||||||
table.set_ty(node, TypeKind::Primitive(prim));
|
|
||||||
} else {
|
|
||||||
table.mark_lang_item(s.into(), node);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -49,20 +34,6 @@ fn parent(table: &Table, node: Handle) -> Handle {
|
|||||||
table.parent(node).copied().unwrap_or(node)
|
table.parent(node).copied().unwrap_or(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cat_alias(table: &mut Table, node: Handle, a: &Alias) -> CatResult<()> {
|
|
||||||
let parent = parent(table, node);
|
|
||||||
let kind = match &a.from {
|
|
||||||
Some(ty) => TypeKind::Instance(
|
|
||||||
ty.evaluate(table, parent)
|
|
||||||
.map_err(|e| Error::TypeEval(e, " while categorizing an alias"))?,
|
|
||||||
),
|
|
||||||
None => TypeKind::Empty,
|
|
||||||
};
|
|
||||||
table.set_ty(node, kind);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cat_struct(table: &mut Table, node: Handle, s: &Struct) -> CatResult<()> {
|
fn cat_struct(table: &mut Table, node: Handle, s: &Struct) -> CatResult<()> {
|
||||||
let Struct { name: _, gens: _, kind } = s;
|
let Struct { name: _, gens: _, kind } = s;
|
||||||
// TODO: Generics
|
// TODO: Generics
|
||||||
@ -99,7 +70,6 @@ fn cat_member(
|
|||||||
|
|
||||||
fn cat_enum<'a>(_table: &mut Table<'a>, _node: Handle, e: &'a Enum) -> CatResult<()> {
|
fn cat_enum<'a>(_table: &mut Table<'a>, _node: Handle, e: &'a Enum) -> CatResult<()> {
|
||||||
let Enum { name: _, gens: _, variants: _ } = e;
|
let Enum { name: _, gens: _, variants: _ } = e;
|
||||||
|
|
||||||
// table.set_ty(node, kind);
|
// table.set_ty(node, kind);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -107,17 +77,10 @@ fn cat_enum<'a>(_table: &mut Table<'a>, _node: Handle, e: &'a Enum) -> CatResult
|
|||||||
fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatResult<()> {
|
fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatResult<()> {
|
||||||
let Variant { name, kind, body } = v;
|
let Variant { name, kind, body } = v;
|
||||||
let parent = table.parent(node).copied().unwrap_or(table.root());
|
let parent = table.parent(node).copied().unwrap_or(table.root());
|
||||||
match (kind, body) {
|
match (kind) {
|
||||||
(StructKind::Empty, None) => {
|
(StructKind::Empty) => Ok(()),
|
||||||
table.set_ty(node, TypeKind::Adt(Adt::UnitStruct));
|
(StructKind::Empty) => Ok(()),
|
||||||
Ok(())
|
(StructKind::Tuple(ty)) => {
|
||||||
}
|
|
||||||
(StructKind::Empty, Some(c)) => {
|
|
||||||
table.set_body(node, c);
|
|
||||||
table.set_ty(node, TypeKind::Adt(Adt::UnitStruct));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(StructKind::Tuple(ty), None) => {
|
|
||||||
let ty = TypeKind::Adt(Adt::TupleStruct(
|
let ty = TypeKind::Adt(Adt::TupleStruct(
|
||||||
ty.iter()
|
ty.iter()
|
||||||
.map(|ty| ty.evaluate(table, node).map(|ty| (Visibility::Public, ty)))
|
.map(|ty| ty.evaluate(table, node).map(|ty| (Visibility::Public, ty)))
|
||||||
@ -126,7 +89,7 @@ fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatRe
|
|||||||
table.set_ty(node, ty);
|
table.set_ty(node, ty);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
(StructKind::Struct(members), None) => {
|
(StructKind::Struct(members)) => {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
for StructMember { vis, name, ty } in members {
|
for StructMember { vis, name, ty } in members {
|
||||||
let ty = ty.evaluate(table, node)?;
|
let ty = ty.evaluate(table, node)?;
|
||||||
@ -144,9 +107,6 @@ fn cat_variant<'a>(table: &mut Table<'a>, node: Handle, v: &'a Variant) -> CatRe
|
|||||||
table.set_ty(node, TypeKind::Adt(Adt::Struct(out)));
|
table.set_ty(node, TypeKind::Adt(Adt::Struct(out)));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
(_, Some(body)) => {
|
|
||||||
panic!("Unexpected body `{body}` in enum variant `{v}`")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
Source::Module(v) => v.infer(&mut eng),
|
Source::Module(v) => v.infer(&mut eng),
|
||||||
Source::Alias(v) => v.infer(&mut eng),
|
Source::Alias(v) => v.infer(&mut eng),
|
||||||
Source::Enum(v) => v.infer(&mut eng),
|
Source::Enum(v) => v.infer(&mut eng),
|
||||||
Source::Variant(v) => v.infer(&mut eng),
|
// Source::Variant(v) => v.infer(&mut eng),
|
||||||
Source::Struct(v) => v.infer(&mut eng),
|
Source::Struct(v) => v.infer(&mut eng),
|
||||||
Source::Const(v) => v.infer(&mut eng),
|
Source::Const(v) => v.infer(&mut eng),
|
||||||
Source::Static(v) => v.infer(&mut eng),
|
Source::Static(v) => v.infer(&mut eng),
|
||||||
@ -221,42 +221,37 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// All primitives must be predefined in the standard library.
|
/// All primitives must be predefined in the standard library.
|
||||||
pub fn primitive(&self, name: Sym) -> Option<Handle> {
|
pub fn primitive(&self, name: &'static str) -> Handle {
|
||||||
// TODO: keep a map of primitives in the table root
|
// TODO: keep a map of primitives in the table root
|
||||||
self.table.get_by_sym(self.table.root(), &name)
|
self.table.get_lang_item(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn never(&mut self) -> Handle {
|
pub fn never(&mut self) -> Handle {
|
||||||
self.table.anon_type(TypeKind::Never)
|
self.table.get_lang_item("never")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty(&mut self) -> Handle {
|
pub fn empty(&mut self) -> Handle {
|
||||||
self.table.anon_type(TypeKind::Empty)
|
self.table.anon_type(TypeKind::Tuple(vec![]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bool(&self) -> Handle {
|
pub fn bool(&self) -> Handle {
|
||||||
self.primitive("bool".into())
|
self.primitive("bool")
|
||||||
.expect("There should be a type named bool.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn char(&self) -> Handle {
|
pub fn char(&self) -> Handle {
|
||||||
self.primitive("char".into())
|
self.primitive("char")
|
||||||
.expect("There should be a type named char.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn str(&self) -> Handle {
|
pub fn str(&self) -> Handle {
|
||||||
self.primitive("str".into())
|
self.primitive("str")
|
||||||
.expect("There should be a type named str.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn u32(&self) -> Handle {
|
pub fn u32(&self) -> Handle {
|
||||||
self.primitive("u32".into())
|
self.primitive("u32")
|
||||||
.expect("There should be a type named u32.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn usize(&self) -> Handle {
|
pub fn usize(&self) -> Handle {
|
||||||
self.primitive("usize".into())
|
self.primitive("usize")
|
||||||
.expect("There should be a type named usize.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new inferred-integer literal
|
/// Creates a new inferred-integer literal
|
||||||
@ -344,7 +339,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
&TypeKind::FnSig { args, rety } => {
|
&TypeKind::FnSig { args, rety } => {
|
||||||
is_generic_rec(this, args, seen) || is_generic_rec(this, rety, seen)
|
is_generic_rec(this, args, seen) || is_generic_rec(this, rety, seen)
|
||||||
}
|
}
|
||||||
TypeKind::Empty | TypeKind::Never | TypeKind::Module => false,
|
TypeKind::Module => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is_generic_rec(self, ty, &mut HashSet::new())
|
is_generic_rec(self, ty, &mut HashSet::new())
|
||||||
@ -358,12 +353,12 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
return ty;
|
return ty;
|
||||||
};
|
};
|
||||||
let entry = self.table.entry(ty);
|
let entry = self.table.entry(ty);
|
||||||
let Some(ty) = entry.ty().cloned() else {
|
let Some(tykind) = entry.ty().cloned() else {
|
||||||
return ty;
|
return ty;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Parent the deep clone into a new "monomorphs" branch of tree
|
// TODO: Parent the deep clone into a new "monomorphs" branch of tree
|
||||||
match ty {
|
match tykind {
|
||||||
TypeKind::Variable => self.new_inferred(),
|
TypeKind::Variable => self.new_inferred(),
|
||||||
TypeKind::Array(h, s) => {
|
TypeKind::Array(h, s) => {
|
||||||
let ty = self.deep_clone(h);
|
let ty = self.deep_clone(h);
|
||||||
@ -405,6 +400,10 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
let ty = self.deep_clone(h);
|
let ty = self.deep_clone(h);
|
||||||
self.table.anon_type(TypeKind::Ref(ty))
|
self.table.anon_type(TypeKind::Ref(ty))
|
||||||
}
|
}
|
||||||
|
TypeKind::Ptr(handle) => {
|
||||||
|
let ty = self.deep_clone(handle);
|
||||||
|
self.table.anon_type(TypeKind::Ptr(ty))
|
||||||
|
}
|
||||||
TypeKind::Slice(h) => {
|
TypeKind::Slice(h) => {
|
||||||
let ty = self.deep_clone(h);
|
let ty = self.deep_clone(h);
|
||||||
self.table.anon_type(TypeKind::Slice(ty))
|
self.table.anon_type(TypeKind::Slice(ty))
|
||||||
@ -418,7 +417,7 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
let rety = self.deep_clone(rety);
|
let rety = self.deep_clone(rety);
|
||||||
self.table.anon_type(TypeKind::FnSig { args, rety })
|
self.table.anon_type(TypeKind::FnSig { args, rety })
|
||||||
}
|
}
|
||||||
_ => self.table.anon_type(ty),
|
_ => ty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,8 +471,6 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
| TypeKind::Variable
|
| TypeKind::Variable
|
||||||
| TypeKind::Adt(Adt::UnitStruct)
|
| TypeKind::Adt(Adt::UnitStruct)
|
||||||
| TypeKind::Primitive(_)
|
| TypeKind::Primitive(_)
|
||||||
| TypeKind::Empty
|
|
||||||
| TypeKind::Never
|
|
||||||
| TypeKind::Module => false,
|
| TypeKind::Module => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -490,6 +487,10 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match (a, b) {
|
match (a, b) {
|
||||||
|
(TypeKind::Variable, TypeKind::Variable) => {
|
||||||
|
self.set_instance(ah, bh);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
(TypeKind::Inferred, _) => {
|
(TypeKind::Inferred, _) => {
|
||||||
self.set_instance(ah, bh);
|
self.set_instance(ah, bh);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -602,12 +603,8 @@ impl<'table, 'a> InferenceEngine<'table, 'a> {
|
|||||||
self.unify(a1, a2)?;
|
self.unify(a1, a2)?;
|
||||||
self.unify(r1, r2)
|
self.unify(r1, r2)
|
||||||
}
|
}
|
||||||
(TypeKind::Empty, TypeKind::Tuple(t)) | (TypeKind::Tuple(t), TypeKind::Empty)
|
(TypeKind::Primitive(Primitive::Never), _)
|
||||||
if t.is_empty() =>
|
| (_, TypeKind::Primitive(Primitive::Never)) => Ok(()),
|
||||||
{
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
(TypeKind::Never, _) | (_, TypeKind::Never) => Ok(()),
|
|
||||||
(a, b) if a == b => Ok(()),
|
(a, b) if a == b => Ok(()),
|
||||||
_ => Err(InferenceError::Mismatch(ah, bh)),
|
_ => Err(InferenceError::Mismatch(ah, bh)),
|
||||||
}
|
}
|
||||||
|
@ -78,16 +78,31 @@ impl<'a> Inference<'a> for Module {
|
|||||||
|
|
||||||
impl<'a> Inference<'a> for Alias {
|
impl<'a> Inference<'a> for Alias {
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||||
Ok(e.empty())
|
let Self { name: _, from } = self;
|
||||||
|
// let this = e.by_name(name)?;
|
||||||
|
let alias = if let Some(from) = from {
|
||||||
|
TypeKind::Instance(e.infer(from)?)
|
||||||
|
} else {
|
||||||
|
TypeKind::Tuple(vec![])
|
||||||
|
};
|
||||||
|
|
||||||
|
// This node may be a lang item referring to a primitive.
|
||||||
|
let mut entry = e.at.to_entry_mut(e.table);
|
||||||
|
if entry.ty().is_some() {
|
||||||
|
return Ok(e.empty());
|
||||||
|
}
|
||||||
|
entry.set_ty(alias);
|
||||||
|
|
||||||
|
Ok(entry.id())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Const {
|
impl<'a> Inference<'a> for Const {
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||||
let Self { name, ty, init } = self;
|
let Self { name: _, ty, init } = self;
|
||||||
// Same as static
|
// Same as static
|
||||||
let node = e.by_name(name)?;
|
let node = e.at; //.by_name(name)?;
|
||||||
let ty = e.infer(ty)?;
|
let ty = e.infer(ty)?;
|
||||||
let mut scope = e.at(node);
|
let mut scope = e.at(node);
|
||||||
// infer body
|
// infer body
|
||||||
@ -103,7 +118,7 @@ impl<'a> Inference<'a> for Static {
|
|||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||||
let Static { mutable, name, ty, init } = self;
|
let Static { mutable, name, ty, init } = self;
|
||||||
let node = e.by_name(name)?;
|
let node = e.at; //e.by_name(name)?;
|
||||||
let ty = e.infer(ty)?;
|
let ty = e.infer(ty)?;
|
||||||
let mut scope = e.at(node);
|
let mut scope = e.at(node);
|
||||||
// infer body
|
// infer body
|
||||||
@ -120,7 +135,7 @@ impl<'a> Inference<'a> for Function {
|
|||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||||
let Self { name, gens, sign, bind, body } = self;
|
let Self { name, gens, sign, bind, body } = self;
|
||||||
// bind name to signature
|
// bind name to signature
|
||||||
let node = e.by_name(name)?;
|
let node = e.at; // e.by_name(name)?;
|
||||||
let node = e.deep_clone(node);
|
let node = e.deep_clone(node);
|
||||||
let fnty = e.by_name(sign)?;
|
let fnty = e.by_name(sign)?;
|
||||||
e.unify(node, fnty)?;
|
e.unify(node, fnty)?;
|
||||||
@ -154,14 +169,15 @@ impl<'a> Inference<'a> for Function {
|
|||||||
|
|
||||||
impl<'a> Inference<'a> for Enum {
|
impl<'a> Inference<'a> for Enum {
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||||
let Self { name, gens, variants } = self;
|
let Self { name: _, gens, variants } = self;
|
||||||
let node = e.by_name(name)?;
|
let node = e.at; //e.by_name(name)?;
|
||||||
let mut scope = e.at(node);
|
let mut scope = e.at(node);
|
||||||
|
|
||||||
scope.infer(gens)?;
|
scope.infer(gens)?;
|
||||||
for variant in variants {
|
for variant in variants {
|
||||||
|
println!("Inferring {variant}");
|
||||||
let var_ty = scope.infer(variant)?;
|
let var_ty = scope.infer(variant)?;
|
||||||
scope.unify(var_ty, node)?;
|
scope.unify(node, var_ty)?;
|
||||||
}
|
}
|
||||||
Ok(node)
|
Ok(node)
|
||||||
}
|
}
|
||||||
@ -169,31 +185,46 @@ impl<'a> Inference<'a> for Enum {
|
|||||||
|
|
||||||
impl<'a> Inference<'a> for Variant {
|
impl<'a> Inference<'a> for Variant {
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||||
let Self { name: _, kind: _, body } = self;
|
let Self { name, kind: _, body } = self;
|
||||||
let ty = e.new_inferred();
|
let node = e.by_name(name)?;
|
||||||
|
|
||||||
// TODO: evaluate kind
|
// TODO: this doesn't work when some variants have bodies and some don't
|
||||||
|
if e.table.ty(node).is_some() {
|
||||||
if let Some(body) = body {
|
println!("{node} has ty!");
|
||||||
let value = body.infer(e)?;
|
return Ok(node);
|
||||||
e.unify(ty, value)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ty)
|
match body {
|
||||||
|
Some(body) => {
|
||||||
|
let mut e = e.at(node);
|
||||||
|
let value = e.infer(body)?;
|
||||||
|
e.unify(node, value)?;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
e.table.entry_mut(node).set_ty(TypeKind::Inferred);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Struct {
|
impl<'a> Inference<'a> for Struct {
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||||
Ok(e.new_inferred())
|
let Self { name, gens, kind: _ } = self;
|
||||||
|
let node = e.by_name(name)?;
|
||||||
|
let mut e = e.at(node);
|
||||||
|
e.infer(gens)?;
|
||||||
|
|
||||||
|
Ok(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Inference<'a> for Impl {
|
impl<'a> Inference<'a> for Impl {
|
||||||
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
fn infer(&'a self, e: &mut InferenceEngine<'_, 'a>) -> IfResult {
|
||||||
let Self { gens: _, target, body } = self;
|
let Self { gens, target, body } = self;
|
||||||
// TODO: match gens to target gens
|
// TODO: match gens to target gens
|
||||||
// gens.infer(e)?;
|
gens.infer(e)?;
|
||||||
let instance = target.infer(e)?;
|
let instance = target.infer(e)?;
|
||||||
let instance = e.def_usage(instance);
|
let instance = e.def_usage(instance);
|
||||||
let mut scope = e.at(instance);
|
let mut scope = e.at(instance);
|
||||||
@ -527,8 +558,9 @@ impl<'a> Inference<'a> for Binary {
|
|||||||
e.unify(tail, bool)?;
|
e.unify(tail, bool)?;
|
||||||
Ok(bool)
|
Ok(bool)
|
||||||
}
|
}
|
||||||
Bk::RangeExc => todo!("Ranges in the type checker"),
|
// TODO: Don't return the generic form wholesale.
|
||||||
Bk::RangeInc => todo!("Ranges in the type checker"),
|
Bk::RangeExc => Ok(e.table.get_lang_item("range_exc")),
|
||||||
|
Bk::RangeInc => Ok(e.table.get_lang_item("range_exc")),
|
||||||
Bk::Shl | Bk::Shr => {
|
Bk::Shl | Bk::Shr => {
|
||||||
let shift_amount = e.u32();
|
let shift_amount = e.u32();
|
||||||
e.unify(tail, shift_amount)?;
|
e.unify(tail, shift_amount)?;
|
||||||
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
type_kind::TypeKind,
|
type_kind::TypeKind,
|
||||||
};
|
};
|
||||||
use cl_ast::{
|
use cl_ast::{
|
||||||
ItemKind, Sym,
|
ItemKind, Literal, Meta, MetaKind, Sym,
|
||||||
ast_visitor::{Visit, Walk},
|
ast_visitor::{Visit, Walk},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,6 +57,15 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
|
|||||||
entry.inner.set_span(*span);
|
entry.inner.set_span(*span);
|
||||||
entry.inner.set_meta(&attrs.meta);
|
entry.inner.set_meta(&attrs.meta);
|
||||||
|
|
||||||
|
for Meta { name, kind } in &attrs.meta {
|
||||||
|
if let ("lang", MetaKind::Equals(Literal::String(s))) = (name.to_ref(), kind) {
|
||||||
|
if let Ok(prim) = s.parse() {
|
||||||
|
entry.inner.set_ty(TypeKind::Primitive(prim));
|
||||||
|
}
|
||||||
|
entry.inner.mark_lang_item(Sym::from(s).to_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
entry.visit_children(i);
|
entry.visit_children(i);
|
||||||
|
|
||||||
if let (Some(name), child) = (entry.name, entry.inner.id()) {
|
if let (Some(name), child) = (entry.name, entry.inner.id()) {
|
||||||
@ -158,9 +167,17 @@ impl<'a> Visit<'a> for Populator<'_, 'a> {
|
|||||||
self.inner.set_source(Source::Variant(value));
|
self.inner.set_source(Source::Variant(value));
|
||||||
self.set_name(*name);
|
self.set_name(*name);
|
||||||
self.visit(kind);
|
self.visit(kind);
|
||||||
if let Some(body) = body {
|
match (kind, body) {
|
||||||
|
(cl_ast::StructKind::Empty, None) => {
|
||||||
|
self.inner.set_ty(TypeKind::Inferred);
|
||||||
|
}
|
||||||
|
(cl_ast::StructKind::Empty, Some(body)) => {
|
||||||
self.inner.set_body(body);
|
self.inner.set_body(body);
|
||||||
}
|
}
|
||||||
|
(cl_ast::StructKind::Tuple(_items), None) => {}
|
||||||
|
(cl_ast::StructKind::Struct(_struct_members), None) => {}
|
||||||
|
(_, Some(body)) => panic!("Unexpected body {body} in enum variant `{value}`"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_impl(&mut self, i: &'a cl_ast::Impl) {
|
fn visit_impl(&mut self, i: &'a cl_ast::Impl) {
|
||||||
|
@ -57,7 +57,7 @@ pub struct Table<'a> {
|
|||||||
sources: HashMap<Handle, Source<'a>>,
|
sources: HashMap<Handle, Source<'a>>,
|
||||||
impl_targets: HashMap<Handle, Handle>,
|
impl_targets: HashMap<Handle, Handle>,
|
||||||
anon_types: HashMap<TypeKind, Handle>,
|
anon_types: HashMap<TypeKind, Handle>,
|
||||||
lang_items: HashMap<Sym, Handle>,
|
lang_items: HashMap<&'static str, Handle>,
|
||||||
|
|
||||||
// --- Queues for algorithms ---
|
// --- Queues for algorithms ---
|
||||||
pub(crate) unchecked: Vec<Handle>,
|
pub(crate) unchecked: Vec<Handle>,
|
||||||
@ -129,10 +129,17 @@ impl<'a> Table<'a> {
|
|||||||
self.impls.push(item);
|
self.impls.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_lang_item(&mut self, name: Sym, item: Handle) {
|
pub fn mark_lang_item(&mut self, name: &'static str, item: Handle) {
|
||||||
self.lang_items.insert(name, item);
|
self.lang_items.insert(name, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_lang_item(&self, name: &str) -> Handle {
|
||||||
|
match self.lang_items.get(name).copied() {
|
||||||
|
Some(handle) => handle,
|
||||||
|
None => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_iter(&self) -> impl Iterator<Item = Handle> + use<> {
|
pub fn handle_iter(&self) -> impl Iterator<Item = Handle> + use<> {
|
||||||
self.kinds.keys()
|
self.kinds.keys()
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,7 @@ impl TypeExpression for Ty {
|
|||||||
impl TypeExpression for TyKind {
|
impl TypeExpression for TyKind {
|
||||||
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
|
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
|
||||||
match self {
|
match self {
|
||||||
TyKind::Never => Ok(table.anon_type(TypeKind::Never)),
|
TyKind::Never => Ok(table.get_lang_item("never")),
|
||||||
TyKind::Empty => Ok(table.anon_type(TypeKind::Empty)),
|
|
||||||
TyKind::Infer => Ok(table.inferred_type()),
|
TyKind::Infer => Ok(table.inferred_type()),
|
||||||
TyKind::Path(p) => p.evaluate(table, node),
|
TyKind::Path(p) => p.evaluate(table, node),
|
||||||
TyKind::Array(a) => a.evaluate(table, node),
|
TyKind::Array(a) => a.evaluate(table, node),
|
||||||
@ -97,10 +96,7 @@ impl TypeExpression for TySlice {
|
|||||||
impl TypeExpression for TyTuple {
|
impl TypeExpression for TyTuple {
|
||||||
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
|
fn evaluate(&self, table: &mut Table, node: Handle) -> Result<Handle, Error> {
|
||||||
let Self { types } = self;
|
let Self { types } = self;
|
||||||
let kind = match types.len() {
|
let kind = TypeKind::Tuple(types.evaluate(table, node)?);
|
||||||
0 => TypeKind::Empty,
|
|
||||||
_ => TypeKind::Tuple(types.evaluate(table, node)?),
|
|
||||||
};
|
|
||||||
Ok(table.anon_type(kind))
|
Ok(table.anon_type(kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,6 @@ pub enum TypeKind {
|
|||||||
Tuple(Vec<Handle>),
|
Tuple(Vec<Handle>),
|
||||||
/// A function which accepts multiple inputs and produces an output
|
/// A function which accepts multiple inputs and produces an output
|
||||||
FnSig { args: Handle, rety: Handle },
|
FnSig { args: Handle, rety: Handle },
|
||||||
/// The unit type
|
|
||||||
Empty,
|
|
||||||
/// The never type
|
|
||||||
Never,
|
|
||||||
/// An untyped module
|
/// An untyped module
|
||||||
Module,
|
Module,
|
||||||
}
|
}
|
||||||
@ -70,6 +66,7 @@ pub enum Primitive {
|
|||||||
Bool, // boolean value
|
Bool, // boolean value
|
||||||
Char, // Unicode codepoint
|
Char, // Unicode codepoint
|
||||||
Str, // UTF-8 string
|
Str, // UTF-8 string
|
||||||
|
Never, // The never type
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
@ -121,6 +118,7 @@ impl FromStr for Primitive {
|
|||||||
"bool" => Primitive::Bool,
|
"bool" => Primitive::Bool,
|
||||||
"char" => Primitive::Char,
|
"char" => Primitive::Char,
|
||||||
"str" => Primitive::Str,
|
"str" => Primitive::Str,
|
||||||
|
"never" => Primitive::Never,
|
||||||
_ => Err(())?,
|
_ => Err(())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,6 @@ impl Display for TypeKind {
|
|||||||
})(f.delimit_with("tuple (", ")"))
|
})(f.delimit_with("tuple (", ")"))
|
||||||
}
|
}
|
||||||
TypeKind::FnSig { args, rety } => write!(f, "fn (#{args}) -> #{rety}"),
|
TypeKind::FnSig { args, rety } => write!(f, "fn (#{args}) -> #{rety}"),
|
||||||
TypeKind::Empty => f.write_str("()"),
|
|
||||||
TypeKind::Never => f.write_str("!"),
|
|
||||||
TypeKind::Module => f.write_str("mod"),
|
TypeKind::Module => f.write_str("mod"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,6 +92,7 @@ impl Display for Primitive {
|
|||||||
Primitive::Bool => f.write_str("bool"),
|
Primitive::Bool => f.write_str("bool"),
|
||||||
Primitive::Char => f.write_str("char"),
|
Primitive::Char => f.write_str("char"),
|
||||||
Primitive::Str => f.write_str("str"),
|
Primitive::Str => f.write_str("str"),
|
||||||
|
Primitive::Never => f.write_str("!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
//! Implements format string evaluation in weak Conlang
|
||||||
|
|
||||||
fn f(__fmt: str) -> str {
|
|
||||||
|
/// Formats a string
|
||||||
|
fn f(__fmt: &str) -> &str {
|
||||||
let __out = "";
|
let __out = "";
|
||||||
let __expr = "";
|
let __expr = "";
|
||||||
let __label = "";
|
let __label = "";
|
||||||
|
@ -4,13 +4,11 @@
|
|||||||
// These two functions shouldn't actually be polymorphic, but
|
// These two functions shouldn't actually be polymorphic, but
|
||||||
// the AST interpreter doesn't know about type annotations
|
// the AST interpreter doesn't know about type annotations
|
||||||
// or operator overloading.
|
// or operator overloading.
|
||||||
#[generic("T")]
|
pub fn max<T>(a: T, b: T) -> T {
|
||||||
pub fn max(a: T, b: T) -> T {
|
|
||||||
(if a < b { b } else { a })
|
(if a < b { b } else { a })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generic("T")]
|
pub fn min<T>(a: T, b: T) -> T {
|
||||||
pub fn min(a: T, b: T) -> T {
|
|
||||||
(if a > b { b } else { a })
|
(if a > b { b } else { a })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,11 +13,11 @@ pub fn lfsr_next() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a pseudorandom byte
|
/// Returns a pseudorandom byte
|
||||||
pub fn rand() -> u8 {
|
pub fn rand() -> u64 {
|
||||||
for _ in 0..8 {
|
for _ in 0..8 {
|
||||||
lfsr_next()
|
lfsr_next()
|
||||||
}
|
};
|
||||||
state & 0xff
|
(state & 0xff) as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints a maze out of diagonal box drawing characters, ['╲', '╱']
|
// Prints a maze out of diagonal box drawing characters, ['╲', '╱']
|
||||||
|
@ -25,5 +25,7 @@ pub mod result;
|
|||||||
|
|
||||||
pub mod range;
|
pub mod range;
|
||||||
|
|
||||||
|
pub mod never;
|
||||||
|
|
||||||
// #[cfg("test")]
|
// #[cfg("test")]
|
||||||
// mod test;
|
// mod test;
|
||||||
|
4
stdlib/std/never.cl
Normal file
4
stdlib/std/never.cl
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//! Never: the return type of an infinite loop
|
||||||
|
|
||||||
|
#[lang = "never"]
|
||||||
|
type Never = !;
|
@ -1,6 +1,7 @@
|
|||||||
//! The optional type, representing the presence or absence of a thing.
|
//! The optional type, representing the presence or absence of a thing.
|
||||||
use super::preamble::*;
|
use super::preamble::*;
|
||||||
|
|
||||||
|
#[lang = "option"]
|
||||||
pub enum Option<T> {
|
pub enum Option<T> {
|
||||||
Some(T),
|
Some(T),
|
||||||
None,
|
None,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! The Result type, indicating a fallible operation.
|
//! The Result type, indicating a fallible operation.
|
||||||
use super::preamble::*;
|
use super::preamble::*;
|
||||||
|
|
||||||
|
#[lang = "result"]
|
||||||
pub enum Result<T, E> {
|
pub enum Result<T, E> {
|
||||||
Ok(T),
|
Ok(T),
|
||||||
Err(E),
|
Err(E),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user