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
```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 {
return struct {
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 {
i := 69;
vec := Vec(int).{
data: &i,
len: 1,
cap: 1,
};
vec := new(int);
push(int, &vec, 69);
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
```hb
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> {
pub fn new(input: &'a str) -> Self {
Self::restore(input, 0)
}
pub fn restore(input: &'a str, pos: u32) -> Self {
Self {
pos: 0,
pos,
bytes: input.as_bytes(),
}
}
@ -317,13 +321,17 @@ impl LineMap {
let mut iter = self.lines.iter().copied();
while let Some(mut len) = iter.next() {
loop {
let mut acc = 0;
while len & 0x80 != 0 {
acc = (acc << 7) | (len & 0x7F) as u32;
len = iter.next().unwrap();
let mut idx = 0;
loop {
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 {
break;
@ -372,7 +380,7 @@ impl LineMap {
let idx = mask.trailing_zeros() as usize + i * 16 + start.len();
let mut len = idx - last_nl + 1;
while len >= 0x80 {
lines.push((0x80 | (len & 0x7F)) as u8);
lines.push(0x80 | (len & 0x7F) as u8);
len >>= 7;
}
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(inline_const_pat)]
#![feature(pattern)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
#![feature(if_let_guard)]
#![feature(slice_partition_dedup)]
#![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";
enum Chk<'a> {
Branch(&'a str),
Rev(&'a str),
Tag(&'a str),
}
enum ImportPath<'a> {
Root {
path: &'a str,
@ -228,11 +236,9 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
path: &'a str,
},
Git {
link: &'a str,
path: &'a str,
branch: Option<&'a str>,
tag: Option<&'a str>,
rev: Option<&'a str>,
link: &'a str,
path: &'a str,
chk: Option<Chk<'a>>,
},
}
@ -249,22 +255,16 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
let (link, path) =
path.split_once(':').ok_or(ParseImportError::ExpectedPath)?;
let (link, params) = link.split_once('?').unwrap_or((link, ""));
let [mut branch, mut tag, mut rev] = [None; 3];
for (key, value) in params.split('&').filter_map(|s| s.split_once('=')) {
match key {
"branch" => branch = Some(value),
"tag" => tag = Some(value),
"rev" => rev = Some(value),
_ => return Err(ParseImportError::UnexpectedParam),
}
}
Ok(Self::Git {
link,
path,
branch,
tag,
rev,
})
let chk = params
.split('&')
.filter_map(|s| s.split_once('='))
.find_map(|(key, value)| match key {
"branch" => Some(Chk::Branch(value)),
"rev" => Some(Chk::Rev(value)),
"tag" => Some(Chk::Tag(value)),
_ => None,
});
Ok(Self::Git { link, path, chk })
}
_ => Err(ParseImportError::InvalidPrefix),
}
@ -294,21 +294,15 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
enum ParseImportError {
ExpectedPath,
InvalidPrefix,
UnexpectedParam,
}
impl std::fmt::Display for ParseImportError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Self::ExpectedPath => write!(f, "expected path"),
Self::InvalidPrefix => write!(
f,
"invalid prefix, expected one of rel, \
Self::ExpectedPath => "expected path".fmt(f),
Self::InvalidPrefix => "invalid prefix, expected one of rel, \
git or none followed by colon"
),
Self::UnexpectedParam => {
write!(f, "unexpected git param, expected branch, tag or rev")
}
.fmt(f),
}
}
}
@ -389,14 +383,7 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
};
let command = if !physiscal_path.exists() {
let ImportPath::Git {
link,
branch,
rev,
tag,
..
} = path
else {
let ImportPath::Git { link, chk, .. } = path else {
return Err(io::Error::new(
io::ErrorKind::NotFound,
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 mut command = std::process::Command::new("git");
command
.args(["clone", "--depth", "1"])
.args(branch.map(|b| ["--branch", b]).into_iter().flatten())
.args(tag.map(|t| ["--tag", t]).into_iter().flatten())
.args(rev.map(|r| ["--rev", r]).into_iter().flatten())
.arg(link)
.arg(root);
command.args(["clone", "--depth", "1"]);
if let Some(chk) = chk {
command.args(match chk {
Chk::Branch(b) => ["--branch", b],
Chk::Tag(t) => ["--tag", t],
Chk::Rev(r) => ["--rev", r],
});
}
command.arg(link).arg(root);
Some(command)
} else {
None
@ -472,9 +461,7 @@ pub fn parse_all(threads: usize, root: &str) -> io::Result<Vec<Ast>> {
.collect::<io::Result<Vec<_>>>()
}
type HashMap<K, V> = std::collections::HashMap<K, V, FnvBuildHash>;
type FnvBuildHash = std::hash::BuildHasherDefault<FnvHasher>;
type HashMap<K, V> = std::collections::HashMap<K, V, std::hash::BuildHasherDefault<FnvHasher>>;
struct FnvHasher(u64);

View file

@ -3,7 +3,7 @@ fn main() -> std::io::Result<()> {
.nth(1)
.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();
codegen.files = parsed;

View file

@ -136,16 +136,36 @@ impl<'a, 'b> Parser<'a, 'b> {
break;
}
let checkpoint = self.token.start;
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.bin_expr(right, prec);
let right = self.arena.alloc(right);
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);
let right = Expr::BinOp { left, op, right };
let right = Expr::BinOp {
left: self.arena.alloc(clone),
op,
right,
};
fold = Expr::BinOp {
left,
op: TokenKind::Assign,
@ -163,7 +183,7 @@ impl<'a, 'b> Parser<'a, 'b> {
}
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());
if let Some(builtin) = codegen::ty::from_str(name) {
@ -270,7 +290,12 @@ impl<'a, 'b> Parser<'a, 'b> {
T::Ident | T::CtIdent => {
let (id, index) = self.resolve_ident(token, self.token.kind == T::Decl);
let name = self.move_str(token);
E::Ident { name, id, index }
E::Ident {
pos: token.start,
name,
id,
index,
}
}
T::If => E::If {
pos: token.start,
@ -526,7 +551,7 @@ macro_rules! generate_expr {
pub fn pos(&self) -> Pos {
#[allow(unused_variables)]
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>,
},
Ident {
pos: Pos,
id: Ident,
name: &'a str,
index: u16,
@ -637,21 +663,17 @@ generate_expr! {
}
trait Poser {
fn posi(self, expr: &Expr) -> Pos;
fn posi(self) -> Pos;
}
impl Poser for Pos {
fn posi(self, expr: &Expr) -> Pos {
if matches!(expr, Expr::Ident { .. }) {
ident::pos(self)
} else {
self
}
fn posi(self) -> Pos {
self
}
}
impl<'a> Poser for &Expr<'a> {
fn posi(self, _: &Expr) -> Pos {
fn posi(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
status: Ok(())