forked from AbleOS/holey-bytes
adding struct syntax
This commit is contained in:
parent
2aa315a863
commit
4bb5ec1953
9
hblang/examples/structs.hb
Normal file
9
hblang/examples/structs.hb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Ty := struct {
|
||||||
|
a: int
|
||||||
|
b: int
|
||||||
|
}
|
||||||
|
|
||||||
|
main := fn(): int {
|
||||||
|
inst := Ty.{ a: 1, b: 2 };
|
||||||
|
return inst.a + inst.b;
|
||||||
|
}
|
|
@ -915,5 +915,6 @@ mod tests {
|
||||||
loops => include_str!("../examples/loops.hb");
|
loops => include_str!("../examples/loops.hb");
|
||||||
fb_driver => include_str!("../examples/fb_driver.hb");
|
fb_driver => include_str!("../examples/fb_driver.hb");
|
||||||
pointers => include_str!("../examples/pointers.hb");
|
pointers => include_str!("../examples/pointers.hb");
|
||||||
|
structs => include_str!("../examples/structs.hb");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,14 +91,17 @@ gen_token_kind! {
|
||||||
Break = b"break",
|
Break = b"break",
|
||||||
Continue = b"continue",
|
Continue = b"continue",
|
||||||
Fn = b"fn",
|
Fn = b"fn",
|
||||||
|
Struct = b"struct",
|
||||||
#[punkt]
|
#[punkt]
|
||||||
LParen = b'(',
|
LParen = "(",
|
||||||
RParen = b')',
|
RParen = ")",
|
||||||
LBrace = b'{',
|
LBrace = "{",
|
||||||
RBrace = b'}',
|
RBrace = "}",
|
||||||
Semi = b';',
|
Semi = ";",
|
||||||
Colon = b':',
|
Colon = ":",
|
||||||
Comma = b',',
|
Comma = ",",
|
||||||
|
Dot = ".",
|
||||||
|
Ctor = ".{",
|
||||||
#[ops]
|
#[ops]
|
||||||
#[prec = 1]
|
#[prec = 1]
|
||||||
Decl = ":=",
|
Decl = ":=",
|
||||||
|
@ -202,6 +205,8 @@ impl<'a> Iterator for Lexer<'a> {
|
||||||
b':' if self.advance_if(b'=') => T::Decl,
|
b':' if self.advance_if(b'=') => T::Decl,
|
||||||
b':' => T::Colon,
|
b':' => T::Colon,
|
||||||
b',' => T::Comma,
|
b',' => T::Comma,
|
||||||
|
b'.' if self.advance_if(b'{') => T::Ctor,
|
||||||
|
b'.' => T::Dot,
|
||||||
b';' => T::Semi,
|
b';' => T::Semi,
|
||||||
b'=' if self.advance_if(b'=') => T::Eq,
|
b'=' if self.advance_if(b'=') => T::Eq,
|
||||||
b'=' => T::Assign,
|
b'=' => T::Assign,
|
||||||
|
|
|
@ -139,6 +139,18 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
let frame = self.idents.len();
|
let frame = self.idents.len();
|
||||||
let token = self.next();
|
let token = self.next();
|
||||||
let mut expr = match token.kind {
|
let mut expr = match token.kind {
|
||||||
|
T::Struct => E::Struct {
|
||||||
|
pos: token.start,
|
||||||
|
fields: {
|
||||||
|
self.expect_advance(T::LBrace);
|
||||||
|
self.collect_list(T::Comma, T::RBrace, |s| {
|
||||||
|
let name = s.expect_advance(T::Ident);
|
||||||
|
s.expect_advance(T::Colon);
|
||||||
|
let ty = s.expr();
|
||||||
|
(s.lexer.slice(name.range()), ty)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
T::Ident => {
|
T::Ident => {
|
||||||
let (id, last) = self.resolve_ident(token, self.token.kind == T::Decl);
|
let (id, last) = self.resolve_ident(token, self.token.kind == T::Decl);
|
||||||
let name = self.lexer.slice(token.range());
|
let name = self.lexer.slice(token.range());
|
||||||
|
@ -207,14 +219,32 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
expr = match self.token.kind {
|
let token = self.token.kind;
|
||||||
T::LParen => {
|
if matches!(token, T::LParen | T::Ctor | T::Dot) {
|
||||||
self.next();
|
self.next();
|
||||||
Expr::Call {
|
}
|
||||||
|
|
||||||
|
expr = match token {
|
||||||
|
T::LParen => Expr::Call {
|
||||||
func: self.arena.alloc(expr),
|
func: self.arena.alloc(expr),
|
||||||
args: self.collect_list(T::Comma, T::RParen, Self::expr),
|
args: self.collect_list(T::Comma, T::RParen, Self::expr),
|
||||||
}
|
},
|
||||||
}
|
T::Ctor => E::Ctor {
|
||||||
|
ty: self.arena.alloc(expr),
|
||||||
|
fields: self.collect_list(T::Comma, T::RBrace, |s| {
|
||||||
|
let name = s.expect_advance(T::Ident);
|
||||||
|
s.expect_advance(T::Colon);
|
||||||
|
let val = s.expr();
|
||||||
|
(s.lexer.slice(name.range()), val)
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
T::Dot => E::Field {
|
||||||
|
ty: self.arena.alloc(expr),
|
||||||
|
field: {
|
||||||
|
let token = self.expect_advance(T::Ident);
|
||||||
|
self.lexer.slice(token.range())
|
||||||
|
},
|
||||||
|
},
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,16 +343,16 @@ pub enum Expr<'a> {
|
||||||
Closure {
|
Closure {
|
||||||
pos: u32,
|
pos: u32,
|
||||||
args: &'a [Arg<'a>],
|
args: &'a [Arg<'a>],
|
||||||
ret: &'a Expr<'a>,
|
ret: &'a Self,
|
||||||
body: &'a Expr<'a>,
|
body: &'a Self,
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
func: &'a Expr<'a>,
|
func: &'a Self,
|
||||||
args: &'a [Expr<'a>],
|
args: &'a [Self],
|
||||||
},
|
},
|
||||||
Return {
|
Return {
|
||||||
pos: u32,
|
pos: u32,
|
||||||
val: Option<&'a Expr<'a>>,
|
val: Option<&'a Self>,
|
||||||
},
|
},
|
||||||
Ident {
|
Ident {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
|
@ -331,31 +361,43 @@ pub enum Expr<'a> {
|
||||||
},
|
},
|
||||||
Block {
|
Block {
|
||||||
pos: u32,
|
pos: u32,
|
||||||
stmts: &'a [Expr<'a>],
|
stmts: &'a [Self],
|
||||||
},
|
},
|
||||||
Number {
|
Number {
|
||||||
pos: u32,
|
pos: u32,
|
||||||
value: u64,
|
value: u64,
|
||||||
},
|
},
|
||||||
BinOp {
|
BinOp {
|
||||||
left: &'a Expr<'a>,
|
left: &'a Self,
|
||||||
op: TokenKind,
|
op: TokenKind,
|
||||||
right: &'a Expr<'a>,
|
right: &'a Self,
|
||||||
},
|
},
|
||||||
If {
|
If {
|
||||||
pos: u32,
|
pos: u32,
|
||||||
cond: &'a Expr<'a>,
|
cond: &'a Self,
|
||||||
then: &'a Expr<'a>,
|
then: &'a Self,
|
||||||
else_: Option<&'a Expr<'a>>,
|
else_: Option<&'a Self>,
|
||||||
},
|
},
|
||||||
Loop {
|
Loop {
|
||||||
pos: u32,
|
pos: u32,
|
||||||
body: &'a Expr<'a>,
|
body: &'a Self,
|
||||||
},
|
},
|
||||||
UnOp {
|
UnOp {
|
||||||
pos: u32,
|
pos: u32,
|
||||||
op: TokenKind,
|
op: TokenKind,
|
||||||
val: &'a Expr<'a>,
|
val: &'a Self,
|
||||||
|
},
|
||||||
|
Struct {
|
||||||
|
pos: u32,
|
||||||
|
fields: &'a [(&'a str, Self)],
|
||||||
|
},
|
||||||
|
Ctor {
|
||||||
|
ty: &'a Self,
|
||||||
|
fields: &'a [(&'a str, Self)],
|
||||||
|
},
|
||||||
|
Field {
|
||||||
|
ty: &'a Self,
|
||||||
|
field: &'a str,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,6 +408,29 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
|
Self::Field { ty, field } => write!(f, "{}.{}", ty, field),
|
||||||
|
Self::Struct { fields, .. } => {
|
||||||
|
write!(f, "struct {{")?;
|
||||||
|
let first = &mut true;
|
||||||
|
for (name, ty) in fields {
|
||||||
|
if !std::mem::take(first) {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
write!(f, "{}: {}", name, ty)?;
|
||||||
|
}
|
||||||
|
write!(f, "}}")
|
||||||
|
}
|
||||||
|
Self::Ctor { ty, fields } => {
|
||||||
|
write!(f, "{} {{", ty)?;
|
||||||
|
let first = &mut true;
|
||||||
|
for (name, val) in fields {
|
||||||
|
if !std::mem::take(first) {
|
||||||
|
write!(f, ", ")?;
|
||||||
|
}
|
||||||
|
write!(f, "{}: {}", name, val)?;
|
||||||
|
}
|
||||||
|
write!(f, "}}")
|
||||||
|
}
|
||||||
Self::UnOp { op, val, .. } => write!(f, "{}{}", op, val),
|
Self::UnOp { op, val, .. } => write!(f, "{}{}", op, val),
|
||||||
Self::Break { .. } => write!(f, "break;"),
|
Self::Break { .. } => write!(f, "break;"),
|
||||||
Self::Continue { .. } => write!(f, "continue;"),
|
Self::Continue { .. } => write!(f, "continue;"),
|
||||||
|
|
BIN
hblang/test.bin
BIN
hblang/test.bin
Binary file not shown.
Loading…
Reference in a new issue