pekomaaaaa

This commit is contained in:
mlokr 2024-06-24 17:26:00 +02:00
parent 66c3f7b0d4
commit 76b3f9ff4b
No known key found for this signature in database
GPG key ID: DEA147DDEE644993
9 changed files with 579 additions and 335 deletions

View file

@ -241,6 +241,15 @@ main := fn(): int {
#### generic_types #### generic_types
```hb ```hb
MALLOC_SYS_CALL := 69
FREE_SYS_CALL := 96
malloc := fn(size: uint, align: uint): ^void
return @eca(^void, MALLOC_SYS_CALL, size, align);
free := fn(ptr: ^void, size: uint, align: uint): void
return @eca(void, FREE_SYS_CALL, ptr, size, align);
Vec := fn($Elem: type): type { Vec := fn($Elem: type): type {
return struct { return struct {
data: ^Elem, data: ^Elem,
@ -249,17 +258,60 @@ Vec := fn($Elem: type): type {
}; };
} }
new := fn($Elem: type): Vec(Elem) return Vec(Elem).{ data: @bitcast(0), len: 0, cap: 0 };
deinit := fn($Elem: type, vec: ^Vec(Elem)): void {
free(@bitcast(vec.data), vec.len * @sizeof(Elem), @alignof(Elem));
*vec = new(Elem);
}
push := fn($Elem: type, vec: ^Vec(Elem), value: Elem): ^Elem {
if vec.len == vec.cap {
if vec.cap == 0 {
vec.cap = 1;
} else {
vec.cap *= 2;
}
new_alloc := @as(^Elem, @bitcast(malloc(vec.cap * @sizeof(Elem), @alignof(Elem))));
if @as(uint, @bitcast(new_alloc)) == 0 return @bitcast(0);
src_cursor := vec.data;
dst_cursor := new_alloc;
end := vec.data + vec.len;
loop if src_cursor == end break else {
*dst_cursor = *src_cursor;
src_cursor += 1;
dst_cursor += 1;
}
free(@bitcast(vec.data), vec.len * @sizeof(Elem), @alignof(Elem));
vec.data = new_alloc;
}
slot := vec.data + vec.len;
*slot = value;
vec.len += 1;
return slot;
}
main := fn(): int { main := fn(): int {
i := 69; vec := new(int);
vec := Vec(int).{ push(int, &vec, 69);
data: &i,
len: 1,
cap: 1,
};
return *vec.data; return *vec.data;
} }
``` ```
#### generic_functions
```hb
add := fn($T: type, a: T, b: T): T return a + b;
main := fn(): int {
return add(u32, 2, 2) - add(int, 1, 3);
}
```
#### fb_driver #### fb_driver
```hb ```hb
arm_fb_ptr := fn(): int return 100; arm_fb_ptr := fn(): int return 100;

File diff suppressed because it is too large Load diff

View file

@ -156,8 +156,12 @@ pub struct Lexer<'a> {
impl<'a> Lexer<'a> { impl<'a> Lexer<'a> {
pub fn new(input: &'a str) -> Self { pub fn new(input: &'a str) -> Self {
Self::restore(input, 0)
}
pub fn restore(input: &'a str, pos: u32) -> Self {
Self { Self {
pos: 0, pos,
bytes: input.as_bytes(), bytes: input.as_bytes(),
} }
} }
@ -317,13 +321,17 @@ impl LineMap {
let mut iter = self.lines.iter().copied(); let mut iter = self.lines.iter().copied();
while let Some(mut len) = iter.next() { loop {
let mut acc = 0; let mut acc = 0;
while len & 0x80 != 0 { let mut idx = 0;
acc = (acc << 7) | (len & 0x7F) as u32; loop {
len = iter.next().unwrap(); let len = iter.next().unwrap();
acc |= ((len & 0x7F) as u32) << (7 * idx);
idx += 1;
if len & 0x80 == 0 {
break;
}
} }
acc += len as u32;
if pos < acc { if pos < acc {
break; break;
@ -372,7 +380,7 @@ impl LineMap {
let idx = mask.trailing_zeros() as usize + i * 16 + start.len(); let idx = mask.trailing_zeros() as usize + i * 16 + start.len();
let mut len = idx - last_nl + 1; let mut len = idx - last_nl + 1;
while len >= 0x80 { while len >= 0x80 {
lines.push((0x80 | (len & 0x7F)) as u8); lines.push(0x80 | (len & 0x7F) as u8);
len >>= 7; len >>= 7;
} }
lines.push(len as u8); lines.push(len as u8);
@ -388,3 +396,30 @@ impl LineMap {
} }
} }
} }
#[cfg(test)]
mod test {
#[test]
fn test_smh() {
let example = include_str!("../README.md");
let nlines = super::LineMap::new(example);
fn slow_nline_search(str: &str, mut pos: usize) -> (usize, usize) {
(
str.lines()
.take_while(|l| match pos.checked_sub(l.len() + 1) {
Some(nl) => (pos = nl, true).1,
None => false,
})
.count()
+ 1,
pos + 1,
)
}
for i in 0..example.len() {
assert_eq!(slow_nline_search(example, i), nlines.line_col(i as _));
}
}
}

View file

@ -3,6 +3,8 @@
#![feature(anonymous_lifetime_in_impl_trait)] #![feature(anonymous_lifetime_in_impl_trait)]
#![feature(inline_const_pat)] #![feature(inline_const_pat)]
#![feature(pattern)] #![feature(pattern)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(if_let_guard)] #![feature(if_let_guard)]
#![feature(slice_partition_dedup)] #![feature(slice_partition_dedup)]
#![feature(noop_waker)] #![feature(noop_waker)]
@ -217,9 +219,15 @@ impl<T> TaskQueueInner<T> {
} }
} }
pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> { pub fn parse_from_fs(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
const GIT_DEPS_DIR: &str = "git-deps"; const GIT_DEPS_DIR: &str = "git-deps";
enum Chk<'a> {
Branch(&'a str),
Rev(&'a str),
Tag(&'a str),
}
enum ImportPath<'a> { enum ImportPath<'a> {
Root { Root {
path: &'a str, path: &'a str,
@ -230,9 +238,7 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
Git { Git {
link: &'a str, link: &'a str,
path: &'a str, path: &'a str,
branch: Option<&'a str>, chk: Option<Chk<'a>>,
tag: Option<&'a str>,
rev: Option<&'a str>,
}, },
} }
@ -249,22 +255,16 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
let (link, path) = let (link, path) =
path.split_once(':').ok_or(ParseImportError::ExpectedPath)?; path.split_once(':').ok_or(ParseImportError::ExpectedPath)?;
let (link, params) = link.split_once('?').unwrap_or((link, "")); let (link, params) = link.split_once('?').unwrap_or((link, ""));
let [mut branch, mut tag, mut rev] = [None; 3]; let chk = params
for (key, value) in params.split('&').filter_map(|s| s.split_once('=')) { .split('&')
match key { .filter_map(|s| s.split_once('='))
"branch" => branch = Some(value), .find_map(|(key, value)| match key {
"tag" => tag = Some(value), "branch" => Some(Chk::Branch(value)),
"rev" => rev = Some(value), "rev" => Some(Chk::Rev(value)),
_ => return Err(ParseImportError::UnexpectedParam), "tag" => Some(Chk::Tag(value)),
} _ => None,
} });
Ok(Self::Git { Ok(Self::Git { link, path, chk })
link,
path,
branch,
tag,
rev,
})
} }
_ => Err(ParseImportError::InvalidPrefix), _ => Err(ParseImportError::InvalidPrefix),
} }
@ -294,21 +294,15 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
enum ParseImportError { enum ParseImportError {
ExpectedPath, ExpectedPath,
InvalidPrefix, InvalidPrefix,
UnexpectedParam,
} }
impl std::fmt::Display for ParseImportError { impl std::fmt::Display for ParseImportError {
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 {
Self::ExpectedPath => write!(f, "expected path"), Self::ExpectedPath => "expected path".fmt(f),
Self::InvalidPrefix => write!( Self::InvalidPrefix => "invalid prefix, expected one of rel, \
f,
"invalid prefix, expected one of rel, \
git or none followed by colon" git or none followed by colon"
), .fmt(f),
Self::UnexpectedParam => {
write!(f, "unexpected git param, expected branch, tag or rev")
}
} }
} }
} }
@ -389,14 +383,7 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
}; };
let command = if !physiscal_path.exists() { let command = if !physiscal_path.exists() {
let ImportPath::Git { let ImportPath::Git { link, chk, .. } = path else {
link,
branch,
rev,
tag,
..
} = path
else {
return Err(io::Error::new( return Err(io::Error::new(
io::ErrorKind::NotFound, io::ErrorKind::NotFound,
format!("can't find file: {}", physiscal_path.display()), format!("can't find file: {}", physiscal_path.display()),
@ -406,13 +393,15 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
let root = PathBuf::from_iter([GIT_DEPS_DIR, preprocess_git(link)]); let root = PathBuf::from_iter([GIT_DEPS_DIR, preprocess_git(link)]);
let mut command = std::process::Command::new("git"); let mut command = std::process::Command::new("git");
command command.args(["clone", "--depth", "1"]);
.args(["clone", "--depth", "1"]) if let Some(chk) = chk {
.args(branch.map(|b| ["--branch", b]).into_iter().flatten()) command.args(match chk {
.args(tag.map(|t| ["--tag", t]).into_iter().flatten()) Chk::Branch(b) => ["--branch", b],
.args(rev.map(|r| ["--rev", r]).into_iter().flatten()) Chk::Tag(t) => ["--tag", t],
.arg(link) Chk::Rev(r) => ["--rev", r],
.arg(root); });
}
command.arg(link).arg(root);
Some(command) Some(command)
} else { } else {
None None
@ -472,9 +461,7 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
.collect::<io::Result<Vec<_>>>() .collect::<io::Result<Vec<_>>>()
} }
type HashMap<K, V> = std::collections::HashMap<K, V, FnvBuildHash>; type HashMap<K, V> = std::collections::HashMap<K, V, std::hash::BuildHasherDefault<FnvHasher>>;
type FnvBuildHash = std::hash::BuildHasherDefault<FnvHasher>;
struct FnvHasher(u64); struct FnvHasher(u64);

View file

@ -3,7 +3,7 @@ fn main() -> std::io::Result<()> {
.nth(1) .nth(1)
.unwrap_or_else(|| "main.hb".to_string()); .unwrap_or_else(|| "main.hb".to_string());
let parsed = hblang::parse_all(1, &root)?; let parsed = hblang::parse_from_fs(1, &root)?;
let mut codegen = hblang::codegen::Codegen::default(); let mut codegen = hblang::codegen::Codegen::default();
codegen.files = parsed; codegen.files = parsed;

View file

@ -136,16 +136,36 @@ impl<'a, 'b> Parser<'a, 'b> {
break; break;
} }
let checkpoint = self.token.start;
let op = self.next().kind; let op = self.next().kind;
let op_ass = op.assign_op().map(|op| {
// this abomination reparses the left side, so that the desubaring adheres to the
// parser invariants.
let source = self.lexer.slice(0..checkpoint as usize);
let prev_lexer =
std::mem::replace(&mut self.lexer, Lexer::restore(source, fold.pos()));
let prev_token = std::mem::replace(&mut self.token, self.lexer.next());
let clone = self.expr();
self.lexer = prev_lexer;
self.token = prev_token;
(op, clone)
});
let right = self.unit_expr(); let right = self.unit_expr();
let right = self.bin_expr(right, prec); let right = self.bin_expr(right, prec);
let right = self.arena.alloc(right); let right = self.arena.alloc(right);
let left = self.arena.alloc(fold); let left = self.arena.alloc(fold);
if let Some(op) = op.assign_op() { if let Some((op, clone)) = op_ass {
self.flag_idents(*left, idfl::MUTABLE); self.flag_idents(*left, idfl::MUTABLE);
let right = Expr::BinOp { left, op, right };
let right = Expr::BinOp {
left: self.arena.alloc(clone),
op,
right,
};
fold = Expr::BinOp { fold = Expr::BinOp {
left, left,
op: TokenKind::Assign, op: TokenKind::Assign,
@ -163,7 +183,7 @@ impl<'a, 'b> Parser<'a, 'b> {
} }
fn resolve_ident(&mut self, token: Token, decl: bool) -> (Ident, u16) { fn resolve_ident(&mut self, token: Token, decl: bool) -> (Ident, u16) {
let is_ct = self.token.kind == TokenKind::CtIdent; let is_ct = token.kind == TokenKind::CtIdent;
let name = self.lexer.slice(token.range()); let name = self.lexer.slice(token.range());
if let Some(builtin) = codegen::ty::from_str(name) { if let Some(builtin) = codegen::ty::from_str(name) {
@ -270,7 +290,12 @@ impl<'a, 'b> Parser<'a, 'b> {
T::Ident | T::CtIdent => { T::Ident | T::CtIdent => {
let (id, index) = self.resolve_ident(token, self.token.kind == T::Decl); let (id, index) = self.resolve_ident(token, self.token.kind == T::Decl);
let name = self.move_str(token); let name = self.move_str(token);
E::Ident { name, id, index } E::Ident {
pos: token.start,
name,
id,
index,
}
} }
T::If => E::If { T::If => E::If {
pos: token.start, pos: token.start,
@ -526,7 +551,7 @@ macro_rules! generate_expr {
pub fn pos(&self) -> Pos { pub fn pos(&self) -> Pos {
#[allow(unused_variables)] #[allow(unused_variables)]
match self { match self {
$(Self::$variant { $($field),* } => generate_expr!(@first $(($field),)*).posi(self),)* $(Self::$variant { $($field),* } => generate_expr!(@first $(($field),)*).posi(),)*
} }
} }
@ -573,6 +598,7 @@ generate_expr! {
val: Option<&'a Self>, val: Option<&'a Self>,
}, },
Ident { Ident {
pos: Pos,
id: Ident, id: Ident,
name: &'a str, name: &'a str,
index: u16, index: u16,
@ -637,21 +663,17 @@ generate_expr! {
} }
trait Poser { trait Poser {
fn posi(self, expr: &Expr) -> Pos; fn posi(self) -> Pos;
} }
impl Poser for Pos { impl Poser for Pos {
fn posi(self, expr: &Expr) -> Pos { fn posi(self) -> Pos {
if matches!(expr, Expr::Ident { .. }) {
ident::pos(self)
} else {
self self
} }
} }
}
impl<'a> Poser for &Expr<'a> { impl<'a> Poser for &Expr<'a> {
fn posi(self, _: &Expr) -> Pos { fn posi(self) -> Pos {
self.pos() self.pos()
} }
} }

View file

@ -0,0 +1,3 @@
code size: 296
ret: 0
status: Ok(())

View file

@ -1,3 +1,3 @@
code size: 318 code size: 1302
ret: 69 ret: 69
status: Ok(()) status: Ok(())