changing the array sintax to be distinc from tuple

the arrays can be declared in a more natural way
type of the element can aso be inferred form the first element

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2024-12-20 10:17:34 +01:00
parent 6e8eb059f6
commit 8ad58ee6b6
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
5 changed files with 121 additions and 61 deletions

File diff suppressed because one or more lines are too long

View file

@ -2,8 +2,8 @@ use {
crate::{
lexer::{self, Lexer, TokenKind},
parser::{
self, CommentOr, CtorField, EnumField, Expr, FieldList, Poser, Radix, StructField,
UnionField,
self, CommentOr, CtorField, EnumField, Expr, FieldList, ListKind, Poser, Radix,
StructField, UnionField,
},
},
core::{
@ -60,7 +60,7 @@ fn token_group(kind: TokenKind) -> TokenGroup {
Colon => TG::Colon,
Semi | Comma => TG::Comma,
Dot => TG::Dot,
Ctor | Tupl | TArrow => TG::Ctor,
Ctor | Arr | Tupl | TArrow => TG::Ctor,
LParen | RParen => TG::Paren,
LBrace | RBrace | LBrack | RBrack => TG::Bracket,
Number | Float => TG::Number,
@ -391,35 +391,40 @@ impl<'a> Formatter<'a> {
},
)
}
Expr::Tupl {
Expr::List {
pos,
kind: term,
ty: Some(&Expr::Slice { pos: spos, size: Some(&Expr::Number { value, .. }), item }),
fields,
trailing_comma,
} if value as usize == fields.len() => self.fmt(
&Expr::Tupl {
&Expr::List {
pos,
kind: term,
ty: Some(&Expr::Slice { pos: spos, size: None, item }),
fields,
trailing_comma,
},
f,
),
Expr::Tupl { ty, fields, trailing_comma, .. } => {
Expr::List { ty, kind: term, fields, trailing_comma, .. } => {
if let Some(ty) = ty {
self.fmt_paren(ty, f, unary)?;
}
f.write_str(".(")?;
self.fmt_list(f, trailing_comma, ")", ",", fields, Self::fmt)
let (start, end) = match term {
ListKind::Tuple => (".(", ")"),
ListKind::Array => (".[", "]"),
};
f.write_str(start)?;
self.fmt_list(f, trailing_comma, end, ",", fields, Self::fmt)
}
Expr::Slice { item, size, .. } => {
f.write_str("[")?;
self.fmt(item, f)?;
if let Some(size) = size {
f.write_str("; ")?;
self.fmt(size, f)?;
}
f.write_str("]")
f.write_str("]")?;
self.fmt(item, f)
}
Expr::Index { base, index } => {
self.fmt(base, f)?;

View file

@ -138,6 +138,7 @@ pub enum TokenKind {
Ctor,
Tupl,
Arr,
TArrow,
Or,
@ -347,6 +348,7 @@ gen_token_kind! {
#[punkt]
Ctor = ".{",
Tupl = ".(",
Arr = ".[",
TArrow = "=>",
// #define OP: each `#[prec]` delimeters a level of precedence from lowest to highest
#[ops]
@ -550,6 +552,7 @@ impl<'a> Lexer<'a> {
}
b'.' if self.advance_if(b'{') => T::Ctor,
b'.' if self.advance_if(b'(') => T::Tupl,
b'.' if self.advance_if(b'[') => T::Arr,
b'=' if self.advance_if(b'>') => T::TArrow,
b'&' if self.advance_if(b'&') => T::And,
b'|' if self.advance_if(b'|') => T::Or,

View file

@ -486,14 +486,20 @@ impl<'a, 'b> Parser<'a, 'b> {
body: self.ptr_expr()?,
},
T::Ctor => self.ctor(pos, None),
T::Tupl => self.tupl(pos, None),
T::Tupl => self.tupl(pos, None, ListKind::Tuple),
T::Arr => self.tupl(pos, None, ListKind::Array),
T::LBrack => E::Slice {
item: self.ptr_unit_expr()?,
size: self.advance_if(T::Semi).then(|| self.ptr_expr()).trans()?,
pos: {
self.expect_advance(T::RBrack)?;
pos
size: {
if self.advance_if(T::RBrack) {
None
} else {
let adv = self.ptr_expr()?;
self.expect_advance(T::RBrack)?;
Some(adv)
}
},
item: self.ptr_unit_expr()?,
pos,
},
T::Band | T::Mul | T::Xor | T::Sub | T::Que | T::Not | T::Dot => E::UnOp {
pos,
@ -547,7 +553,7 @@ impl<'a, 'b> Parser<'a, 'b> {
loop {
let token = self.token;
if matches!(token.kind, T::LParen | T::Ctor | T::Dot | T::Tupl | T::LBrack) {
if matches!(token.kind, T::LParen | T::Ctor | T::Dot | T::Tupl | T::Arr | T::LBrack) {
self.next();
}
@ -558,7 +564,8 @@ impl<'a, 'b> Parser<'a, 'b> {
trailing_comma: core::mem::take(&mut self.trailing_sep),
},
T::Ctor => self.ctor(token.start, Some(expr)),
T::Tupl => self.tupl(token.start, Some(expr)),
T::Tupl => self.tupl(token.start, Some(expr), ListKind::Tuple),
T::Arr => self.tupl(token.start, Some(expr), ListKind::Array),
T::LBrack => E::Index {
base: self.arena.alloc(expr),
index: {
@ -586,11 +593,12 @@ impl<'a, 'b> Parser<'a, 'b> {
Some(expr)
}
fn tupl(&mut self, pos: Pos, ty: Option<Expr<'a>>) -> Expr<'a> {
Expr::Tupl {
fn tupl(&mut self, pos: Pos, ty: Option<Expr<'a>>, kind: ListKind) -> Expr<'a> {
Expr::List {
pos,
kind,
ty: ty.map(|ty| self.arena.alloc(ty)),
fields: self.collect_list(TokenKind::Comma, TokenKind::RParen, Self::expr),
fields: self.collect_list(TokenKind::Comma, kind.term(), Self::expr),
trailing_comma: core::mem::take(&mut self.trailing_sep),
}
}
@ -1029,8 +1037,9 @@ generate_expr! {
trailing_comma: bool,
},
/// `[Expr] LIST('.(', ',', ')', Ident [':' Expr])`
Tupl {
List {
pos: Pos,
kind: ListKind,
ty: Option<&'a Self>,
fields: &'a [Self],
trailing_comma: bool,
@ -1091,6 +1100,20 @@ generate_expr! {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ListKind {
Tuple,
Array,
}
impl ListKind {
fn term(self) -> TokenKind {
match self {
ListKind::Tuple => TokenKind::RParen,
ListKind::Array => TokenKind::RBrack,
}
}
}
impl Expr<'_> {
pub fn declares(&self, iden: DeclId, source: &str) -> Option<Ident> {
match *self {

View file

@ -11,7 +11,7 @@ use {
parser::{
self,
idfl::{self},
CommentOr, CtorField, DeclId, Expr, ExprRef, FieldList, MatchBranch, Pos,
CommentOr, CtorField, DeclId, Expr, ExprRef, FieldList, ListKind, MatchBranch, Pos,
},
ty::{
self, Arg, ArrayLen, CompState, ConstData, EnumData, EnumField, FTask, FuncData,
@ -1607,14 +1607,14 @@ impl<'a> Codegen<'a> {
Expr::Directive { name: "inline", args: [func, args @ ..], .. } => {
self.gen_call(func, args, true)
}
Expr::Tupl { pos, ty, fields, .. } => {
let ty = ty
Expr::List { pos, kind, ty, fields, .. } => {
let rty = ty
.map(|ty| self.ty(ty))
.or(ctx.ty.map(|ty| self.tys.inner_of(ty).unwrap_or(ty)))
.map(ty::Id::expand);
match ty {
None => {
match (rty, kind) {
(None, ListKind::Tuple) => {
let arg_base = self.tys.tmp.args.len();
let mut values = Vec::with_capacity(fields.len());
for field in fields {
@ -1651,7 +1651,35 @@ impl<'a> Codegen<'a> {
Some(Value::ptr(mem).ty(tupl.into()))
}
Some(ty::Kind::Struct(s)) => {
(None, ListKind::Array) => {
let mut array_meta = None::<(ty::Id, Nid)>;
let mut offset = 0;
for field in fields {
let (elem, mem) = match array_meta {
Some((ty, mem)) => {
(self.checked_expr(field, ty, "array element")?, mem)
}
None => {
let expr = self.expr(field)?;
let aty = self.tys.make_array(expr.ty, fields.len() as _);
let mem = self.new_stack(pos, aty);
array_meta = Some((expr.ty, mem));
(expr, mem)
}
};
let mem = self.offset(mem, offset);
self.store_mem(mem, elem.ty, elem.id);
offset += self.tys.size_of(elem.ty);
}
let Some((_, mem)) = array_meta else {
return self.error(pos, "can not infer the type of the array element, \
array is empty, has no explicit type, and type is not obvious from the context");
};
Some(Value::ptr(mem).ty(self.ci.nodes[mem].ty))
}
(Some(ty::Kind::Struct(s)), ListKind::Tuple) => {
let mem = self.new_stack(pos, s.into());
let mut offs = OffsetIter::new(s, self.tys);
for field in fields {
@ -1683,15 +1711,17 @@ impl<'a> Codegen<'a> {
}
Some(Value::ptr(mem).ty(s.into()))
}
Some(ty::Kind::Slice(s)) => {
let slice = &self.tys.ins.slices[s];
let len = slice.len().unwrap_or(fields.len());
let elem = slice.elem;
(Some(kty), ListKind::Array) => {
let (len, elem) = if ty.is_none()
&& let ty::Kind::Slice(a) = kty
{
let arr = &self.tys.ins.slices[a];
(arr.len().unwrap_or(fields.len()), arr.elem)
} else {
(fields.len(), kty.compress())
};
let elem_size = self.tys.size_of(elem);
let aty = slice.len().map_or_else(
|| self.tys.make_array(elem, len as ArrayLen),
|_| s.into(),
);
let aty = self.tys.make_array(elem, len as ArrayLen);
if len != fields.len() {
return self.error(
@ -1716,11 +1746,10 @@ impl<'a> Codegen<'a> {
Some(Value::ptr(mem).ty(aty))
}
Some(t) => self.error(
(Some(t), ListKind::Tuple) => self.error(
pos,
fa!(
"the {}type of the constructor is `{}`, \
but thats not a struct nor slice or array",
"the {}type of the constructor is `{}`, but thats not a struct",
if ty.is_some() { "" } else { "inferred " },
self.ty_display(t.compress()),
),