Skip to content
5 changes: 4 additions & 1 deletion cobalt-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ pub trait AST<'src>: ASTClone<'src> + std::fmt::Debug {
1
}
// AST properties
fn is_const(&self) -> bool {
fn is_const(&self, _ctx: &CompCtx<'src, '_>) -> bool {
false
}
fn has_const_call(&self, _ctx: &CompCtx<'src, '_>) -> bool {
false
}
// pretty printing
Expand Down
19 changes: 19 additions & 0 deletions cobalt-ast/src/ast/funcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1730,6 +1730,9 @@ impl<'src> AST<'src> for CallAST<'src> {
fn nodes(&self) -> usize {
self.target.nodes() + self.args.iter().map(|x| x.nodes()).sum::<usize>() + 1
}
fn is_const(&self, ctx: &CompCtx<'src, '_>) -> bool {
self.target.has_const_call(ctx) && self.args.iter().all(|a| a.is_const(ctx))
}
fn codegen_impl<'ctx>(
&self,
ctx: &CompCtx<'src, 'ctx>,
Expand Down Expand Up @@ -1776,6 +1779,22 @@ impl<'src> AST<'src> for IntrinsicAST<'src> {
fn loc(&self) -> SourceSpan {
self.loc
}
fn is_const(&self, _ctx: &CompCtx<'src, '_>) -> bool {
intrinsics::VALUE_INTRINSICS
.pin()
.get(&*self.name)
.map_or(false, |i| i.is_const)
|| intrinsics::FUNCTION_INTRINSICS
.pin()
.get(&*self.name)
.map_or(false, |i| i.is_const)
}
fn has_const_call(&self, _ctx: &CompCtx<'src, '_>) -> bool {
intrinsics::FUNCTION_INTRINSICS
.pin()
.get(&*self.name)
.map_or(false, |i| i.is_const)
}
fn codegen_impl<'ctx>(
&self,
_ctx: &CompCtx<'src, 'ctx>,
Expand Down
8 changes: 4 additions & 4 deletions cobalt-ast/src/ast/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl<'src> AST<'src> for IntLiteralAST<'src> {
fn loc(&self) -> SourceSpan {
self.loc
}
fn is_const(&self) -> bool {
fn is_const(&self, _ctx: &CompCtx<'src, '_>) -> bool {
true
}
fn codegen_impl<'ctx>(
Expand Down Expand Up @@ -117,7 +117,7 @@ impl<'src> AST<'src> for FloatLiteralAST<'src> {
fn loc(&self) -> SourceSpan {
self.loc
}
fn is_const(&self) -> bool {
fn is_const(&self, _ctx: &CompCtx<'src, '_>) -> bool {
true
}
fn codegen_impl<'ctx>(
Expand Down Expand Up @@ -185,7 +185,7 @@ impl<'src> AST<'src> for CharLiteralAST<'src> {
fn loc(&self) -> SourceSpan {
self.loc
}
fn is_const(&self) -> bool {
fn is_const(&self, _ctx: &CompCtx<'src, '_>) -> bool {
true
}
fn codegen_impl<'ctx>(
Expand Down Expand Up @@ -293,7 +293,7 @@ impl<'src> AST<'src> for StringLiteralAST<'src> {
fn loc(&self) -> SourceSpan {
self.loc
}
fn is_const(&self) -> bool {
fn is_const(&self, _ctx: &CompCtx<'src, '_>) -> bool {
true
}
fn codegen_impl<'ctx>(
Expand Down
4 changes: 2 additions & 2 deletions cobalt-ast/src/ast/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,8 @@ impl<'src> AST<'src> for ParenAST<'src> {
fn nodes(&self) -> usize {
self.base.nodes() + 1
}
fn is_const(&self) -> bool {
self.base.is_const()
fn is_const(&self, ctx: &CompCtx<'src, '_>) -> bool {
self.base.is_const(ctx)
}
fn codegen_impl<'ctx>(
&self,
Expand Down
4 changes: 3 additions & 1 deletion cobalt-ast/src/ast/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,9 @@ impl<'src> AST<'src> for PrefixAST<'src> {
return Value::error();
}
if self.op == "&" {
if let Some(ty) = v.data_type.downcast::<types::Reference>() {
if let Ok(val) = v.data_type.pre_op(v.clone(), "&", self.loc, ctx, true) {
val
} else if let Some(ty) = v.data_type.downcast::<types::Reference>() {
Value {
data_type: types::Pointer::new(ty.base()),
..v
Expand Down
6 changes: 5 additions & 1 deletion cobalt-ast/src/ast/vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ impl<'src> AST<'src> for VarDefAST<'src> {
Value::error()
}
}
} else if self.val.is_const() && self.type_.is_none() {
} else if self.val.is_const(ctx) && self.type_.is_none() {
let mut val = self.val.codegen(ctx, errs);
let dt = if let Some(t) = self.type_.as_ref().map(|t| {
let oic = ctx.is_const.replace(true);
Expand Down Expand Up @@ -1852,6 +1852,10 @@ impl<'src> AST<'src> for VarGetAST<'src> {
fn loc(&self) -> SourceSpan {
self.loc
}
fn is_const<'ctx>(&self, ctx: &CompCtx<'src, '_>) -> bool {
ctx.lookup(&self.name, self.global)
.map_or(true, |v| v.0.inter_val.is_some())
}
fn codegen_impl<'ctx>(
&self,
ctx: &CompCtx<'src, 'ctx>,
Expand Down
25 changes: 21 additions & 4 deletions cobalt-ast/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,37 @@ pub struct ValueIntrinsic {
pub name: &'static str,
pub wraps: ValueCallType,
pub ret: fn() -> TypeRef,
pub is_const: bool,
}
impl ValueIntrinsic {
pub const fn new(name: &'static str, wraps: ValueCallType, ret: fn() -> TypeRef) -> Self {
Self { name, wraps, ret }
pub const fn new(
name: &'static str,
wraps: ValueCallType,
ret: fn() -> TypeRef,
is_const: bool,
) -> Self {
Self {
name,
wraps,
ret,
is_const,
}
}
}

#[derive(Debug, Clone, Copy)]
pub struct FunctionIntrinsic {
pub name: &'static str,
pub wraps: FunctionCallType,
pub is_const: bool,
}
impl FunctionIntrinsic {
pub const fn new(name: &'static str, wraps: FunctionCallType) -> Self {
Self { name, wraps }
pub const fn new(name: &'static str, wraps: FunctionCallType, is_const: bool) -> Self {
Self {
name,
wraps,
is_const,
}
}
}

Expand Down Expand Up @@ -48,6 +64,7 @@ pub static FUNCTION_INTRINSICS: Lazy<flurry::HashMap<&'static str, FunctionIntri
.collect()
});

pub mod enums;
pub mod misc;
pub mod types;
pub mod version;
111 changes: 111 additions & 0 deletions cobalt-ast/src/intrinsics/enums.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use super::*;
use crate::types::{self, *};

static ENUM_AGG: EnumAggregator = EnumAggregator(false);
static UNION_AGG: EnumAggregator = EnumAggregator(true);

#[derive(Debug, Display, ConstIdentify, PartialEq, Eq, Hash)]
#[display("<{} aggregator>", if _0 {"union"} else {"enum"})]
struct EnumAggregator(bool);
impl TypeSerde for EnumAggregator {
no_type_header!();
impl_type_proxy!(bool, this => this.0, s => if s {&UNION_AGG} else {&ENUM_AGG});
}
impl Type for EnumAggregator {
fn size(&self) -> SizeType {
SizeType::Meta
}
fn align(&self) -> u16 {
0
}
fn decay(&self) -> TypeRef {
types::TypeData::new()
}
fn _can_iconv_to(&self, other: TypeRef, _ctx: &CompCtx) -> bool {
other == types::TypeData::new()
}
fn _iconv_to<'src, 'ctx>(
&'static self,
val: Value<'src, 'ctx>,
target: (TypeRef, Option<SourceSpan>),
_ctx: &CompCtx<'src, 'ctx>,
) -> Result<Value<'src, 'ctx>, CobaltError<'src>> {
if target.0 == types::TypeData::new() {
if let Some(InterData::Array(vec)) = val.inter_val {
let res = vec
.into_iter()
.map(|t| {
let InterData::Spanned(_, i) = t else {
unreachable!()
};
let InterData::Type(t) = *i else {
unreachable!()
};
t
})
.collect::<Vec<_>>();
Ok(Value::make_type(EnumOrUnion::new(res, self.0)))
} else {
unreachable!()
}
} else {
Err(cant_iconv(&val, target.0, target.1))
}
}
fn _has_bin_lhs(
&self,
other: TypeRef,
op: &str,
ctx: &CompCtx,
_move_left: bool,
_move_right: bool,
) -> bool {
op == "|" && other.impl_convertible(types::TypeData::new(), ctx)
}
fn _bin_lhs<'src, 'ctx>(
&'static self,
mut lhs: Value<'src, 'ctx>,
rhs: Value<'src, 'ctx>,
op: (&'static str, SourceSpan),
ctx: &CompCtx<'src, 'ctx>,
_move_left: bool,
_move_right: bool,
) -> Result<Value<'src, 'ctx>, CobaltError<'src>> {
if op.0 == "|" && rhs.data_type.impl_convertible(types::TypeData::new(), ctx) {
let curr = rhs.loc;
let rt = rhs.into_type(ctx)?;
let Some(InterData::Array(vec)) = &mut lhs.inter_val else {
unreachable!()
};
if let Some(prev) = vec.iter().filter_map(|i| {
let InterData::Spanned(s, t) = i else {
unreachable!()
};
let InterData::Type(t) = &**t else {
unreachable!()
};
(rt == *t).then_some(*s)
}).next() {
Err(CobaltError::DuplicateEnumVariant {
is_union: self.0,
prev, curr,
ty: rt.to_string(),
})
} else {
vec.push(InterData::Spanned(curr, Box::new(InterData::Type(rt))));
Ok(lhs)
}
} else {
Err(invalid_binop(&lhs, &rhs, op.0, op.1))
}
}
}

inventory::submit! {
ValueIntrinsic::new("enum", |_| Value::metaval(InterData::Array(vec![]), &ENUM_AGG), || &ENUM_AGG, true)
}
inventory::submit! {
ValueIntrinsic::new("union", |_| Value::metaval(InterData::Array(vec![]), &UNION_AGG), || &UNION_AGG, true)
}

submit_types!(EnumAggregator);
4 changes: 2 additions & 2 deletions cobalt-ast/src/intrinsics/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,8 @@ fn alloca<'src, 'ctx>(
}
}
inventory::submit! {
FunctionIntrinsic::new("asm", asm)
FunctionIntrinsic::new("asm", asm, true)
}
inventory::submit! {
FunctionIntrinsic::new("alloca", alloca)
FunctionIntrinsic::new("alloca", alloca, false)
}
10 changes: 5 additions & 5 deletions cobalt-ast/src/intrinsics/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::*;
inventory::submit! {
FunctionIntrinsic::new("type", |v, c, a, _| {
extract_single("@type", v, c, a).map(|v| Value::make_type(v.data_type))
})
}, true)
}
inventory::submit! {
FunctionIntrinsic::new("size", |v, c, a, ctx| {
Expand All @@ -14,7 +14,7 @@ inventory::submit! {
)
})
})
})
}, true)
}
inventory::submit! {
FunctionIntrinsic::new("sized", |v, c, a, ctx| {
Expand All @@ -30,7 +30,7 @@ inventory::submit! {
)
})
})
})
}, true)
}
inventory::submit! {
FunctionIntrinsic::new("align", |v, c, a, ctx| {
Expand All @@ -42,15 +42,15 @@ inventory::submit! {
)
})
})
})
}, true)
}
inventory::submit! {
FunctionIntrinsic::new("typename", |v, c, a, ctx| {
extract_single("@typename", v, c, a).and_then(|v| {
v.into_type(ctx)
.map(|t| Value::make_str(t.to_string(), ctx))
})
})
}, true)
}
fn extract_single<'src, 'ctx>(
name: &'static str,
Expand Down
15 changes: 10 additions & 5 deletions cobalt-ast/src/intrinsics/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ inventory::submit! {
InterData::Int(*VERSION_MAJOR as _),
types::IntLiteral::new(),
),
|| types::IntLiteral::new()
|| types::IntLiteral::new(),
true
)
}
inventory::submit! {
Expand All @@ -21,7 +22,8 @@ inventory::submit! {
InterData::Int(*VERSION_MINOR as _),
types::IntLiteral::new(),
),
|| types::IntLiteral::new()
|| types::IntLiteral::new(),
true
)
}
inventory::submit! {
Expand All @@ -31,14 +33,16 @@ inventory::submit! {
InterData::Int(*VERSION_PATCH as _),
types::IntLiteral::new(),
),
|| types::IntLiteral::new()
|| types::IntLiteral::new(),
true
)
}
inventory::submit! {
ValueIntrinsic::new(
"version_string",
|ctx| Value::make_str(env!("CARGO_PKG_VERSION"), ctx),
|| types::SizedArray::new(types::Int::unsigned(8), env!("CARGO_PKG_VERSION").len() as _)
|| types::SizedArray::new(types::Int::unsigned(8), env!("CARGO_PKG_VERSION").len() as _),
true
)
}
inventory::submit! {
Expand All @@ -56,7 +60,8 @@ inventory::submit! {
.into_iter()
.collect(),
)
}
},
true
)
}
fn make_version<'src, 'ctx>(ctx: &CompCtx<'src, 'ctx>) -> Value<'src, 'ctx> {
Expand Down
Loading