forked from AbleOS/holey-bytes
pekomaaaaa
This commit is contained in:
parent
66c3f7b0d4
commit
76b3f9ff4b
|
@ -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
|
@ -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 _));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
3
hblang/tests/codegen_tests_generic_functions.txt
Normal file
3
hblang/tests/codegen_tests_generic_functions.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
code size: 296
|
||||
ret: 0
|
||||
status: Ok(())
|
|
@ -1,3 +1,3 @@
|
|||
code size: 318
|
||||
code size: 1302
|
||||
ret: 69
|
||||
status: Ok(())
|
||||
|
|
Loading…
Reference in a new issue