forked from AbleOS/holey-bytes
pekomaaaaa
This commit is contained in:
parent
66c3f7b0d4
commit
76b3f9ff4b
|
@ -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
|
@ -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 _));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
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
|
ret: 69
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
Loading…
Reference in a new issue