diff --git a/compiler/pipec-arena-structures/src/adynlist.rs b/compiler/pipec-arena-structures/src/adynlist.rs index f5c8005..2424398 100644 --- a/compiler/pipec-arena-structures/src/adynlist.rs +++ b/compiler/pipec-arena-structures/src/adynlist.rs @@ -1,13 +1,13 @@ use pipec_arena::{ASpan, Arena}; -#[derive(Debug, Clone, Copy, Default)] +#[derive(Debug, Clone, Copy, Default, Hash)] pub enum ListNode { #[default] Empty, Node(T, ASpan), } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub struct ADynList { first: ASpan>, mutate: ASpan>, @@ -24,10 +24,10 @@ where { type Item = T; fn next(&mut self) -> Option { - match self.arena.take(self.current.clone()) { + match self.arena.take(self.current) { ListNode::Empty => None, ListNode::Node(current, next) => { - self.current = next.clone(); + self.current = *next; Some(current.clone()) } } @@ -36,24 +36,24 @@ where impl ADynList { pub fn push(&mut self, input: T, arena: &mut Arena) { - let handle = arena.take(self.mutate.clone()); + let handle = arena.take(self.mutate); let empty = arena.alloc(ListNode::Empty); - *handle = ListNode::Node(input, empty.clone()); + *handle = ListNode::Node(input, empty); self.mutate = empty } pub fn new(arena: &mut Arena) -> Self { let out = arena.alloc(ListNode::Empty); ADynList { - first: out.clone(), + first: out, mutate: out, } } pub fn first(&self, arena: &mut Arena) -> &mut ListNode { - arena.take(self.first.clone()) + arena.take(self.first) } pub fn iter<'a>(&'a self, arena: &'a Arena) -> ADynListIter<'a, T> { ADynListIter { - current: self.first.clone(), + current: self.first, arena, } } diff --git a/compiler/pipec-arena-structures/src/astring.rs b/compiler/pipec-arena-structures/src/astring.rs index c0db60b..07e3d82 100644 --- a/compiler/pipec-arena-structures/src/astring.rs +++ b/compiler/pipec-arena-structures/src/astring.rs @@ -1,78 +1,47 @@ -use core::cmp::PartialEq; -use core::ops::Deref; -use std::fmt::Display; -use std::mem::MaybeUninit; +use pipec_arena::{ABytes, ASlice, Arena}; #[derive(Debug, Clone)] -pub struct AString { - buf: [u8; SIZE], +pub struct AString { + buf: ASlice, index: usize, + pub capacity: usize, } -impl AString { +impl AString { #[allow(clippy::new_without_default)] - pub fn new() -> Self { - #[allow(clippy::uninit_assumed_init)] + pub fn with_capacity(capacity: usize, arena: &mut Arena) -> Self { + let buf = unsafe { arena.alloc_empty(capacity) }; Self { - buf: unsafe { MaybeUninit::uninit().assume_init() }, + buf, index: 0, + capacity, } } - pub fn push(&mut self, input: char) -> Result<(), AStringError> { + pub fn push(&mut self, input: char, arena: &mut Arena) -> Result<(), AStringError> { let mut buf = [0u8; 4]; let char_len = input.encode_utf8(&mut buf).len(); - if self.index + char_len > SIZE { + if self.index + char_len > self.capacity { return Err(AStringError::BufFilled); } - self.buf[self.index..self.index + char_len].copy_from_slice(&buf[..char_len]); + let abuf = arena.take_slice(self.buf); + abuf[self.index..self.index + char_len].copy_from_slice(&buf[..char_len]); self.index += char_len; Ok(()) } - pub fn push_str(&mut self, input: &str) -> Result<(), AStringError> { + pub fn push_str(&mut self, input: &str, arena: &mut Arena) -> Result<(), AStringError> { let len = input.len(); - if self.index + input.len() > SIZE { + if self.index + input.len() > self.capacity { return Err(AStringError::BufFilled); } - self.buf[self.index..self.index + len].copy_from_slice(input.as_bytes()); + arena.take_slice(self.buf)[self.index..self.index + len].copy_from_slice(input.as_bytes()); self.index += len; Ok(()) } - pub fn as_str(&self) -> &str { - self - } -} - -impl Display for AString { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(self.deref()) - } -} - -impl PartialEq for AString { - fn eq(&self, other: &Self) -> bool { - self.deref() == other.deref() - } -} - -impl PartialEq> for str { - fn eq(&self, other: &AString) -> bool { - other.deref() == self - } -} - -impl PartialEq for AString { - fn eq(&self, other: &str) -> bool { - self.deref() == other - } -} - -impl Deref for AString { - type Target = str; - fn deref(&self) -> &Self::Target { - unsafe { str::from_utf8_unchecked(&self.buf[..self.index]) } + pub fn as_str(&self, arena: &mut Arena) -> &str { + unsafe { str::from_utf8_unchecked(&arena.take_slice(self.buf)[..self.index]) } } } @@ -84,26 +53,29 @@ pub enum AStringError { #[cfg(test)] mod tests { use super::*; + use pipec_arena::Size; #[test] fn test_str() -> Result<(), AStringError> { - let mut string = AString::<100>::new(); - string.push('h')?; - string.push('e')?; - string.push('l')?; - string.push('l')?; - string.push('o')?; - string.push_str(" world!")?; - println!("{}", &string); - assert_eq!("hello world!", &string); + let mut arena = Arena::new(Size::Megs(2)); + let mut string = AString::with_capacity(100, &mut arena); + string.push('h', &mut arena)?; + string.push('e', &mut arena)?; + string.push('l', &mut arena)?; + string.push('l', &mut arena)?; + string.push('o', &mut arena)?; + string.push_str(" world!", &mut arena)?; + let as_str = string.as_str(&mut arena); + assert_eq!("hello world!", as_str); Ok(()) } #[test] fn different_size_same_contents() -> Result<(), AStringError> { - let mut s1 = AString::<100>::new(); - let mut s2 = AString::<50>::new(); - s1.push_str("hello world!")?; - s2.push_str("hello world!")?; - assert_eq!(s1.as_str(), s2.as_str()); + let mut arena = Arena::new(Size::Megs(2)); + let mut s1 = AString::with_capacity(100, &mut arena); + let mut s2 = AString::with_capacity(50, &mut arena); + s1.push_str("hello world!", &mut arena)?; + s2.push_str("hello world!", &mut arena)?; + assert_eq!(s1.as_str(&mut arena), s2.as_str(&mut arena)); Ok(()) } } diff --git a/compiler/pipec-arena/src/lib.rs b/compiler/pipec-arena/src/lib.rs index ae014ac..ec21ef8 100644 --- a/compiler/pipec-arena/src/lib.rs +++ b/compiler/pipec-arena/src/lib.rs @@ -25,6 +25,13 @@ pub struct ASlice { pub(crate) end: usize, } +/// Compiler can't "know" the size of ASlice<[u8]>, so this is for api convenience. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ABytes; +/// Compiler can't "know" the size of ASlice, so this is for api convenience. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct AStr; + impl Clone for ASlice { fn clone(&self) -> Self { *self @@ -66,21 +73,34 @@ impl ASlice { /// An "owned pointer" the arena returns after you do an allocation with it. /// Lifetimes are a mess to deal with so returning a struct like this instead of say &'a mut T is easier -#[derive(Debug, Copy)] +#[derive(Debug)] pub struct ASpan { _marker: PhantomData, pub(crate) val: usize, } +impl std::hash::Hash for ASpan { + fn hash(&self, state: &mut H) { + state.write_usize(self.val); + } +} + +impl PartialEq for ASpan { + fn eq(&self, other: &Self) -> bool { + self.val == other.val + } +} + +impl Eq for ASpan {} + impl Clone for ASpan { fn clone(&self) -> Self { - Self { - _marker: PhantomData, - val: self.val, - } + *self } } +impl Copy for ASpan {} + impl ASpan { pub(crate) fn new(input: usize) -> Self { Self { @@ -130,6 +150,17 @@ impl Arena { } } + /// Allocates an empty memory region given a size. + /// # Safety + /// The returned data will be empty. Yeah + pub unsafe fn alloc_empty(&mut self, size: usize) -> ASlice { + unsafe { + let bump = self.bump; + self.bump += size; + ASlice::from_raw_parts(bump, self.bump) + } + } + /// Takes an ASpan and turns it into a &mut T. pub fn take<'b, T>(&self, input: ASpan) -> &'b mut T { unsafe { @@ -139,7 +170,7 @@ impl Arena { } /// Takes an ASlice<&[u8]> and turns it into a &mut [u8]. - pub fn take_slice<'b>(&self, input: ASlice<&[u8]>) -> &'b mut [u8] { + pub fn take_slice<'b>(&self, input: ASlice) -> &'b mut [u8] { unsafe { let ptr = self.data.as_ptr().add(input.start) as *mut u8; @@ -149,7 +180,7 @@ impl Arena { } /// Takes an ASlice and turns it into a &mut str. - pub fn take_str_slice<'b>(&self, input: ASlice) -> &'b str { + pub fn take_str_slice<'b>(&self, input: ASlice) -> &'b str { unsafe { let ptr = self.data.as_ptr().add(input.start) as *mut u8; diff --git a/compiler/pipec-ast/src/ast/asttree.rs b/compiler/pipec-ast/src/ast/asttree.rs index 9917e7f..6283b61 100644 --- a/compiler/pipec-ast/src/ast/asttree.rs +++ b/compiler/pipec-ast/src/ast/asttree.rs @@ -19,16 +19,16 @@ impl ASTTree { } } pub fn current_node(&mut self, arena: &mut Arena) -> Option<&ASTNode> { - let handle = arena.take(self.stream.clone()); + let handle = arena.take(self.stream); handle.get(self.pos) } pub fn next_node(&mut self, arena: &mut Arena) -> Option { - let handle = arena.take(self.stream.clone()); + let handle = arena.take(self.stream); self.pos += 1; handle.get(self.pos - 1).cloned() } pub fn peek(&mut self, arena: &mut Arena) -> Option<&ASTNode> { - let handle = arena.take(self.stream.clone()); + let handle = arena.take(self.stream); handle.get(self.pos) } // pub fn from_vec(vec: Vec) -> Self { diff --git a/compiler/pipec-ast/src/ast/mod.rs b/compiler/pipec-ast/src/ast/mod.rs index 971b041..f04b369 100644 --- a/compiler/pipec-ast/src/ast/mod.rs +++ b/compiler/pipec-ast/src/ast/mod.rs @@ -25,7 +25,7 @@ pub struct ASTGenerator<'this> { impl<'this> ASTGenerator<'this> { pub fn tree(mut self) -> ASTTree { let out = self.arena.alloc(AVec::new()); - let out_handle = self.arena.take(out.clone()); + let out_handle = self.arena.take(out); loop { let next = self.parse_value(); if matches!(next, ASTNode::EOF) { @@ -60,6 +60,7 @@ impl<'this> ASTGenerator<'this> { #[inline] pub(crate) fn advance_stream(&mut self) -> Option { + println!("{:#?}", self.peek_stream()); self.tokens.next_token() } #[inline] @@ -76,7 +77,9 @@ impl<'this> ASTGenerator<'this> { Token::ComponentKeyword => self.consume_component_keyword(), Token::ViewportKeyword => self.consume_viewport_keyword(), Token::FunctionKeyword => self.consume_function_keyword(), + Token::PublicKeyword => self.consume_public_keyword(), _v => { + println!("{_v:#?}"); todo!(); } }, @@ -84,6 +87,13 @@ impl<'this> ASTGenerator<'this> { } } + #[inline] + pub(crate) fn consume_public_keyword(&mut self) -> ASTNode { + self.advance_stream(); + let val = self.parse_value(); + ASTNode::Public(self.arena.alloc(val)) + } + #[inline] pub(crate) fn consume_function_keyword(&mut self) -> ASTNode { self.advance_stream(); @@ -93,7 +103,7 @@ impl<'this> ASTGenerator<'this> { let params = self.consume_function_parameters(); self.consume_whitespace(); let mut out_type = None; - if self.next_is(Token::ThinArrow) { + if self.next_is(Token::FatArrow) { self.advance_stream(); self.consume_whitespace(); out_type = Some(self.consume_a_path()); @@ -133,7 +143,7 @@ impl<'this> ASTGenerator<'this> { #[inline] pub(crate) fn consume_function_parameters(&mut self) -> FunctionDeclarationParameters { let vec = self.arena.alloc(AVec::new()); - let vec_handle = self.arena.take(vec.clone()); + let vec_handle = self.arena.take(vec); self.must(Token::LeftParenthesis); loop { self.consume_whitespace(); @@ -172,6 +182,7 @@ impl<'this> ASTGenerator<'this> { #[inline] pub(crate) fn must(&mut self, val: Token) { + println!("should have {:#?}", self.peek_stream()); if self.advance_stream() != Some(val) { // TODO : compiler error unreachable!() @@ -198,7 +209,7 @@ impl<'this> ASTGenerator<'this> { pub(crate) fn consume_mod_block(&mut self, mod_path: Span) -> ASTNode { self.advance_stream(); let nodes = self.arena.alloc(AVec::new()); - let nodes_handle = self.arena.take(nodes.clone()); + let nodes_handle = self.arena.take(nodes); loop { self.consume_whitespace(); if self.peek_stream() == &Some(Token::RightCurly) { @@ -328,8 +339,7 @@ impl<'this> ASTGenerator<'this> { ) -> ComponentDeclarationBlockStatements { match self.advance_stream() { Some(Token::FinalKeyword) => self.consume_final_variable_declaration(), - Some(Token::RenderKeyword) => self.consume_render_block(), - Some(Token::PublicKeyword) => self.consume_public_constructor(), + Some(Token::RenderKeyword) => self.consume_component_render_block(), _v => { //TODO : compiler error unreachable!(); @@ -338,23 +348,14 @@ impl<'this> ASTGenerator<'this> { } #[inline] - pub(crate) fn consume_public_constructor(&mut self) -> ComponentDeclarationBlockStatements { - self.consume_whitespace(); - let expression = self.consume_an_expression(); - self.consume_whitespace(); - self.consume_a_semicolon(); - ComponentDeclarationBlockStatements::PublicConstructor { expression } - } - - #[inline] - pub(crate) fn consume_render_block(&mut self) -> ComponentDeclarationBlockStatements { + pub(crate) fn consume_component_render_block(&mut self) -> ComponentDeclarationBlockStatements { self.consume_whitespace(); - let block = self.consume_render_block_inner(); + let block = self.consume_component_render_block_inner(); ComponentDeclarationBlockStatements::RenderBlockDeclaration { block } } #[inline] - pub(crate) fn consume_render_block_inner(&mut self) -> RenderBlock { + pub(crate) fn consume_component_render_block_inner(&mut self) -> RenderBlock { self.must(Token::LeftCurly); self.consume_whitespace(); let vertices_block = self.consume_vertices_block(); @@ -446,8 +447,10 @@ impl<'this> ASTGenerator<'this> { self.consume_whitespace(); match self.peek_stream() { Some(v) => match v { - Token::LetKeyword => self.consume_variable_declaration(), + Token::MutableKeyword => self.consume_mutable_variable_declaration(), + Token::ImmutableKeyword => self.consume_immutable_variable_declaration(), Token::ExportKeyword => self.consume_export_declaration(), + Token::RenderKeyword => self.consume_render_block(), _ => self.consume_expression_statement(), }, None => { @@ -456,13 +459,25 @@ impl<'this> ASTGenerator<'this> { } } } + #[inline] + pub(crate) fn consume_render_block(&mut self) -> FunctionBlockStatements { + self.advance_stream(); + self.consume_whitespace(); + FunctionBlockStatements::RenderBlock { + block: self.consume_function_block(), + } + } #[inline] pub(crate) fn consume_expression_statement(&mut self) -> FunctionBlockStatements { let expression = self.consume_an_expression(); self.consume_whitespace(); - self.consume_a_semicolon(); - FunctionBlockStatements::ExpressionStatement { expression } + let mut hidden = false; + if self.next_is(Token::Semicolon) { + hidden = true; + self.advance_stream(); + } + FunctionBlockStatements::ExpressionStatement { expression, hidden } } #[inline] @@ -533,34 +548,60 @@ impl<'this> ASTGenerator<'this> { } #[inline] - pub(crate) fn consume_variable_declaration(&mut self) -> FunctionBlockStatements { + pub(crate) fn consume_mutable_variable_declaration(&mut self) -> FunctionBlockStatements { self.advance_stream(); - // let x : u32 = 0; + // mutable x : u32 = 0; self.consume_whitespace(); - let varname: Span; + let varname = self.must_ident(); let vartype: Option; let declexpr: Option; - let mut is_mutable = false; + self.consume_whitespace(); match self.advance_stream() { - Some(Token::Ident(variable_name)) => { - varname = variable_name; - } - Some(Token::MutableKeyword) => { - is_mutable = true; + Some(Token::Colon) => { self.consume_whitespace(); - if let Some(Token::Ident(variable_name)) = self.advance_stream() { - varname = variable_name; - } else { - //TODO : compiler error - unreachable!() + vartype = Some(self.consume_a_path()); + self.consume_whitespace(); + match self.advance_stream() { + Some(Token::EqualSign) => { + declexpr = Some(self.consume_an_expression()); + } + _anything_else => { + //TODO : compiler error + unreachable!(); + } } } + + Some(Token::EqualSign) => { + self.consume_whitespace(); + declexpr = Some(self.consume_an_expression()); + vartype = None; + } + _ => { - //TODO: compiler error + //TODO : compiler error unreachable!() } } self.consume_whitespace(); + self.consume_a_semicolon(); + + FunctionBlockStatements::MutableVariableDeclaration { + variablename: varname, + variabletype: vartype, + declarationexpression: declexpr, + } + // TODO : update this function + } + #[inline] + pub(crate) fn consume_immutable_variable_declaration(&mut self) -> FunctionBlockStatements { + self.advance_stream(); + // mutable x : u32 = 0; + self.consume_whitespace(); + let varname = self.must_ident(); + let vartype: Option; + let declexpr: Option; + self.consume_whitespace(); match self.advance_stream() { Some(Token::Colon) => { self.consume_whitespace(); @@ -591,11 +632,10 @@ impl<'this> ASTGenerator<'this> { self.consume_whitespace(); self.consume_a_semicolon(); - FunctionBlockStatements::VariableDeclaration { + FunctionBlockStatements::ImmutableVariableDeclaration { variablename: varname, variabletype: vartype, declarationexpression: declexpr, - is_mutable, } // TODO : update this function } @@ -614,7 +654,7 @@ impl<'this> ASTGenerator<'this> { #[inline] pub(crate) fn consume_an_expression(&mut self) -> Expression { self.consume_whitespace(); - match self.peek_stream() { + let out = match self.peek_stream() { Some(Token::Digit { .. }) => self.consume_number_expression(), Some(Token::String(_)) => self.consume_string_expression(), Some(Token::LeftParenthesis) => self.consume_tuple_expression(), @@ -622,14 +662,90 @@ impl<'this> ASTGenerator<'this> { Some(Token::Tilde) => self.consume_tilde_expression(), Some(Token::Ident(_)) => self.consume_path_expression(), Some(Token::RequiredKeyword) => self.consume_required_expression(), + Some(Token::SwitchKeyword) => self.consume_switch_expression(), _v => { + println!("{_v:#?}"); //TODO : compiler error unreachable!(); } + }; + self.check_expression_rhs(out) + } + + #[inline] + pub(crate) fn check_expression_rhs(&mut self, input: Expression) -> Expression { + self.consume_whitespace(); + let exprtype = match self.peek_stream() { + Some(Token::Plus) => Some(BinaryOpType::Add), + Some(Token::Minus) => Some(BinaryOpType::Subtract), + Some(Token::Asterisk) => Some(BinaryOpType::Multiply), + Some(Token::Slash) => Some(BinaryOpType::Divide), + Some(Token::PlusEqual) => Some(BinaryOpType::AddEqual), + Some(Token::MinusEqual) => Some(BinaryOpType::SubtractEqual), + Some(Token::AsteriskEqual) => Some(BinaryOpType::MultiplyEqual), + Some(Token::SlashEqual) => Some(BinaryOpType::DivideEqual), + Some(Token::ModEqual) => Some(BinaryOpType::ModEqual), + _ => None, + }; + if let Some(v) = exprtype { + self.advance_stream(); + let rhs_expr = self.consume_an_expression(); + + return Expression::BinaryOpExpression { + optype: v, + lhs: self.arena.alloc(input), + rhs: self.arena.alloc(rhs_expr), + }; + } + input + } + + #[inline] + pub(crate) fn consume_switch_expression(&mut self) -> Expression { + self.advance_stream(); + self.consume_whitespace(); + let expression = self.consume_an_expression(); + let predicate = self.arena.alloc(expression); + Expression::SwitchExpression { + predicate, + block: self.consume_switch_block(), } } + #[inline] + pub(crate) fn consume_switch_block(&mut self) -> SwitchExpressionBlock { + self.consume_whitespace(); + self.must(Token::LeftCurly); + let mut out = ADynList::new(self.arena); + loop { + self.consume_whitespace(); + if self.next_is(Token::RightCurly) { + self.advance_stream(); + break; + } + out.push(self.consume_switch_arm(), self.arena); + if self.next_is(Token::Comma) { + self.advance_stream(); + continue; + } + } + SwitchExpressionBlock(out) + } + + #[inline] + pub(crate) fn consume_switch_arm(&mut self) -> SwitchArm { + let expr = self.consume_an_expression(); + println!("arm lhs = {expr:#?}"); + let lhs = self.arena.alloc(expr); + self.consume_whitespace(); + self.must(Token::ThinArrow); + self.consume_whitespace(); + let expr = self.consume_an_expression(); + let rhs = self.arena.alloc(expr); + SwitchArm { lhs, rhs } + } + #[inline] pub(crate) fn consume_required_expression(&mut self) -> Expression { self.advance_stream(); @@ -694,11 +810,9 @@ impl<'this> ASTGenerator<'this> { #[inline] pub(crate) fn consume_string_expression(&mut self) -> Expression { - if let Some(Token::Ident(v)) = self.advance_stream() { - return Expression::StringExpression { value: v }; + Expression::PathExpression { + value: self.consume_a_path(), } - //TODO : compiler error - unreachable!(); } #[inline] @@ -730,7 +844,7 @@ impl<'this> ASTGenerator<'this> { #[inline] pub(crate) fn consume_number_expression(&mut self) -> Expression { self.consume_whitespace(); - let first = match self.advance_stream() { + match self.advance_stream() { Some(Token::Digit { val: value, digittype, @@ -739,56 +853,6 @@ impl<'this> ASTGenerator<'this> { //TODO : compile error unreachable!() } - }; - self.consume_whitespace(); - match self.peek_stream() { - Some(Token::Plus) => { - self.advance_stream(); - let expr = self.consume_an_expression(); - Expression::UnaryOpExpression { - optype: UnaryOpType::Add, - lhs: self.arena.alloc(first), - rhs: self.arena.alloc(expr), - } - } - Some(Token::Minus) => { - self.advance_stream(); - let expr = self.consume_an_expression(); - Expression::UnaryOpExpression { - optype: UnaryOpType::Subtract, - lhs: self.arena.alloc(first), - rhs: self.arena.alloc(expr), - } - } - Some(Token::Asterisk) => { - self.advance_stream(); - let expr = self.consume_an_expression(); - Expression::UnaryOpExpression { - optype: UnaryOpType::Multiply, - lhs: self.arena.alloc(first), - rhs: self.arena.alloc(expr), - } - } - Some(Token::Slash) => { - self.advance_stream(); - let expr = self.consume_an_expression(); - Expression::UnaryOpExpression { - optype: UnaryOpType::Divide, - lhs: self.arena.alloc(first), - rhs: self.arena.alloc(expr), - } - } - Some(Token::Modulo) => { - self.advance_stream(); - let expr = self.consume_an_expression(); - Expression::UnaryOpExpression { - optype: UnaryOpType::Mod, - lhs: self.arena.alloc(first), - rhs: self.arena.alloc(expr), - } - } - - _v => first, } } @@ -812,13 +876,33 @@ impl<'this> ASTGenerator<'this> { let name = *v; self.advance_stream(); let param = self.consume_path_param(); - out.push(PathNode { name, param }, self.arena); + out.push(PathNode::Named { name, param }, self.arena); continue; } - Some(Token::DoubleColon) => { + Some(Token::Slash) => { self.advance_stream(); continue; } + Some(Token::LeftParenthesis) => { + self.advance_stream(); + let mut vals = ADynList::new(self.arena); + loop { + self.consume_whitespace(); + match self.advance_stream() { + Some(Token::Ident(v)) => { + vals.push(v, self.arena); + continue; + } + Some(Token::RightParenthesis) => { + break; + } + Some(Token::Comma) => { + continue; + } + _v => {} + } + } + } _ => { break; } @@ -841,6 +925,12 @@ impl<'this> ASTGenerator<'this> { _v => None, } } + #[inline] + pub(crate) fn consume_whitespace(&mut self) { + while self.tokens.peek() == &Some(Token::Whitespace) { + self.tokens.next_token(); + } + } #[inline] pub(crate) fn consume_angle_params(&mut self) -> ADynList { @@ -877,25 +967,22 @@ impl<'this> ASTGenerator<'this> { } out } - - #[inline] - pub(crate) fn consume_whitespace(&mut self) { - while self.tokens.peek() == &Some(Token::Whitespace) { - self.tokens.next_token(); - } - } } -#[derive(Clone, Debug)] + +#[derive(Clone, Debug, Hash)] #[allow(unused)] pub struct Path(pub ADynList); -#[derive(Debug, Clone)] -pub struct PathNode { - pub name: Span, - pub param: Option, +#[derive(Debug, Clone, Hash)] +pub enum PathNode { + Named { + name: Span, + param: Option, + }, + Tuple(ADynList), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Hash)] pub enum FunctionNodeParams { Tuple(ADynList), Angles(ADynList), @@ -930,6 +1017,7 @@ pub enum ASTNode { name: Span, tree: ASTTree, }, + Public(ASpan), EOF, } @@ -979,13 +1067,18 @@ pub struct FragmentsBlock { #[derive(Debug, Clone)] pub enum FunctionBlockStatements { - VariableDeclaration { + MutableVariableDeclaration { + variablename: Span, + variabletype: Option, + declarationexpression: Option, + }, + ImmutableVariableDeclaration { variablename: Span, variabletype: Option, declarationexpression: Option, - is_mutable: bool, }, ExpressionStatement { + hidden: bool, expression: Expression, }, ExportDeclaration { @@ -993,6 +1086,9 @@ pub enum FunctionBlockStatements { exporttype: Option, expression: Expression, }, + RenderBlock { + block: Block, + }, } #[derive(Debug, PartialEq, Clone)] @@ -1002,7 +1098,7 @@ pub enum Exported { Custom(Span), } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Hash)] pub enum Expression { NumberExpression { value: Span, @@ -1017,8 +1113,8 @@ pub enum Expression { ListExpression { values: ADynList, }, - UnaryOpExpression { - optype: UnaryOpType, + BinaryOpExpression { + optype: BinaryOpType, lhs: ASpan, rhs: ASpan, }, @@ -1028,18 +1124,35 @@ pub enum Expression { RequiredExpression { value: ASpan, }, - StringExpression { - value: Span, + SwitchExpression { + predicate: ASpan, + block: SwitchExpressionBlock, }, } +#[derive(Debug, Clone, Hash)] +#[allow(unused)] +pub struct SwitchExpressionBlock(ADynList); + +#[derive(Debug, Clone, Hash)] +#[allow(unused)] +pub struct SwitchArm { + lhs: ASpan, + rhs: ASpan, +} + #[derive(Debug, PartialEq, Clone, Eq, Hash)] -pub enum UnaryOpType { +pub enum BinaryOpType { Add, Subtract, Multiply, Divide, Mod, + AddEqual, + SubtractEqual, + MultiplyEqual, + DivideEqual, + ModEqual, } #[derive(Debug)] @@ -1052,11 +1165,11 @@ pub enum VariableType { #[allow(unused)] pub struct Block(ADynList); -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Hash)] #[allow(unused)] pub struct FunctionDeclarationParameters(pub ASpan>); -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Hash)] #[allow(unused)] pub struct FunctionDeclarationParameter { pub name: Span, diff --git a/compiler/pipec-ast/src/tokenizer/mod.rs b/compiler/pipec-ast/src/tokenizer/mod.rs index 9d86253..84fa42d 100644 --- a/compiler/pipec-ast/src/tokenizer/mod.rs +++ b/compiler/pipec-ast/src/tokenizer/mod.rs @@ -62,7 +62,10 @@ impl<'chars> Tokenizer<'chars> { '&' => self.consume_ampersand(), '+' => self.consume_plus(), '-' => self.consume_minus(), - '/' => self.consume_slash(), + '/' => match self.consume_slash() { + Some(v) => v, + None => self.consume_next_token(), + }, '*' => self.consume_asterisk(), '!' => self.consume_exclamation_mark(), '?' => self.consume_question_mark(), @@ -137,6 +140,10 @@ impl<'chars> Tokenizer<'chars> { #[inline] pub(crate) fn consume_plus(&mut self) -> Token { self.advance_stream(); + if self.peek_stream() == &Some('=') { + self.advance_stream(); + return Token::PlusEqual; + } Token::Plus } #[inline] @@ -146,11 +153,19 @@ impl<'chars> Tokenizer<'chars> { self.advance_stream(); return Token::ThinArrow; } + if self.peek_stream() == &Some('=') { + self.advance_stream(); + return Token::MinusEqual; + } Token::Minus } #[inline] pub(crate) fn consume_asterisk(&mut self) -> Token { self.advance_stream(); + if self.peek_stream() == &Some('=') { + self.advance_stream(); + return Token::AsteriskEqual; + } Token::Asterisk } #[inline] @@ -231,6 +246,10 @@ impl<'chars> Tokenizer<'chars> { self.advance_stream(); return Token::EqualTo; } + if self.peek_stream() == &Some('>') { + self.advance_stream(); + return Token::FatArrow; + } Token::EqualSign } #[inline] @@ -306,8 +325,14 @@ impl<'chars> Tokenizer<'chars> { continue; } if peek == &Some('.') { - self.advance_stream(); - digittype = DigitType::Float; + match digittype { + DigitType::Float => break, + DigitType::Int => { + self.advance_stream(); + digittype = DigitType::Float; + continue; + } + } } break; } @@ -319,9 +344,24 @@ impl<'chars> Tokenizer<'chars> { } #[inline] - pub(crate) fn consume_slash(&mut self) -> Token { + pub(crate) fn consume_slash(&mut self) -> Option { self.advance_stream(); - Token::Slash + match self.peek_stream() { + Some('/') => { + self.consume_single_line_comment(); + return None; + } + Some('*') => { + self.consume_multi_line_comment(); + return None; + } + Some('=') => { + self.advance_stream(); + return Some(Token::SlashEqual); + } + _ => {} + } + Some(Token::Slash) } #[inline] pub(crate) fn consume_hash(&mut self) -> Token { @@ -380,7 +420,6 @@ impl<'chars> Tokenizer<'chars> { use Token::*; match input.parse_str(self.src) { "using" => UsingKeyword, - "let" => LetKeyword, "viewport" => ViewportKeyword, "component" => ComponentKeyword, "final" => FinalKeyword, @@ -393,6 +432,8 @@ impl<'chars> Tokenizer<'chars> { "module" => ModuleKeyword, "mutable" => MutableKeyword, "function" => FunctionKeyword, + "immutable" => ImmutableKeyword, + "switch" => SwitchKeyword, _ => Token::Ident(input), } } @@ -420,6 +461,8 @@ pub enum Token { Or, /// -> ThinArrow, + /// => + FatArrow, /// @ AtSign, /// = @@ -446,6 +489,16 @@ pub enum Token { Ampersand, /// % Modulo, + /// += + PlusEqual, + /// -= + MinusEqual, + /// *= + AsteriskEqual, + /// /= + SlashEqual, + /// /= + ModEqual, /// ! ExclamationMark, /// ? @@ -478,8 +531,6 @@ pub enum Token { Whitespace, /// using UsingKeyword, - /// let - LetKeyword, /// viewport ViewportKeyword, /// component @@ -502,8 +553,12 @@ pub enum Token { ModuleKeyword, /// mutable MutableKeyword, + /// immutable + ImmutableKeyword, /// function FunctionKeyword, + /// switch + SwitchKeyword, /// 21213 Digit { val: Span, digittype: DigitType }, /// things_like_this or this_2 diff --git a/compiler/pipec-file-loader/src/lib.rs b/compiler/pipec-file-loader/src/lib.rs index 5522516..d07f2d5 100644 --- a/compiler/pipec-file-loader/src/lib.rs +++ b/compiler/pipec-file-loader/src/lib.rs @@ -1,10 +1,10 @@ -use pipec_arena::{ASlice, Arena}; +use pipec_arena::{ASlice, AStr, Arena}; use std::fs::File; use std::path::PathBuf; /// This struct is for loading files into the memory, ensuring every Span points to correct memory. pub struct FileLoader { - store: Vec>, + store: Vec>, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -19,7 +19,7 @@ impl FileLoader { Ok(FileId(id)) } - pub fn load(&mut self, input: FileId) -> ASlice { + pub fn load(&mut self, input: FileId) -> ASlice { self.store[input.0] } } diff --git a/compiler/pipec-gst/src/lib.rs b/compiler/pipec-gst/src/lib.rs index 33deeec..5eb9610 100644 --- a/compiler/pipec-gst/src/lib.rs +++ b/compiler/pipec-gst/src/lib.rs @@ -1,8 +1,10 @@ +use pipec_arena::AStr; use pipec_arena::{ASlice, Arena}; use pipec_arena_structures::ListNode; use pipec_ast::ast::ASTNode; use pipec_ast::ast::FunctionDeclarationParameters; use pipec_ast::ast::Path; +use pipec_ast::ast::PathNode; use pipec_ast::ast::asttree::ASTTree; use pipec_file_loader::FileLoader; use pipec_span::Span; @@ -12,27 +14,28 @@ pub struct GlobalSymbolTree<'this> { ast: ASTTree, loader: &'this mut FileLoader, arena: &'this mut Arena, - pub map: HashMap, - context: SymbolName, - src: ASlice, + src: ASlice, +} + +#[derive(Default, Debug)] +pub struct ModuleScope<'a> { + symbols: HashMap<&'a str, Symbol>, + submodules: HashMap<&'a str, Self>, } impl<'this> GlobalSymbolTree<'this> { pub fn new(arena: &'this mut Arena, loader: &'this mut FileLoader, ast: ASTTree) -> Self { - let map = HashMap::new(); let src = loader.load(ast.id); - let context = SymbolName::default(); Self { ast, arena, loader, - map, src, - context, } } - pub fn generate(&mut self) { + pub fn generate<'a>(&mut self) -> ModuleScope<'a> { + let mut out = ModuleScope::default(); loop { let next = self.ast.next_node(self.arena); match next { @@ -40,30 +43,31 @@ impl<'this> GlobalSymbolTree<'this> { ASTNode::EOF => { break; } - _ => self.check_node(v.clone()), + _ => self.check_node(v.clone(), &mut out), }, None => break, } } + out } - pub(crate) fn check_node(&mut self, input: ASTNode) { + pub(crate) fn check_node(&mut self, input: ASTNode, scope: &mut ModuleScope) { match input { ASTNode::FunctionDeclaration { name, params, block: _, out_type, - } => self.parse_function_declaration(name, params, out_type), + } => self.parse_function_declaration(name, params, out_type, scope), ASTNode::ViewportDeclaration { name, params, block: _, - } => self.parse_viewport_declaration(name, params), + } => self.parse_viewport_declaration(name, params, scope), ASTNode::ModStatement { name, tree } => { - self.parse_mod_statement(name, tree); + self.parse_mod_statement(name, tree, scope); } - _ => todo!(), + _ => {} } } @@ -72,55 +76,54 @@ impl<'this> GlobalSymbolTree<'this> { name: Span, params: FunctionDeclarationParameters, out_type: Option, + scope: &mut ModuleScope, ) { let return_type = match out_type { - None => Type::Void, + None => Type::Nothing, Some(v) => self.type_from_path(&v), }; - let params = self.ast_to_gst_params(params); let symbol = Symbol::Function { params, return_type, }; - let mut cloned = self.context.clone(); - let name = name.parse_arena(self.src, self.arena).to_string(); - cloned.path.push(name); - - self.map.insert(cloned, symbol); + let name = name.parse_arena(self.src, self.arena); + scope.symbols.insert(name, symbol); } pub(crate) fn parse_viewport_declaration( &mut self, name: Span, params: FunctionDeclarationParameters, + scope: &mut ModuleScope, ) { - let params = self.ast_to_gst_params(params); let symbol = Symbol::Viewport { params }; - let mut cloned = self.context.clone(); - let name = name.parse_arena(self.src, self.arena).to_string(); - cloned.path.push(name); - - self.map.insert(cloned, symbol); + let name = name.parse_arena(self.src, self.arena); + scope.symbols.insert(name, symbol); } - pub(crate) fn parse_mod_statement(&mut self, name: Span, mut tree: ASTTree) { - let name = name.parse_arena(self.src, self.arena).to_string(); - let old_src = self.src; - let old_context = self.context.clone(); - let mut mod_context = self.context.clone(); - mod_context.path.push(name); - self.context = mod_context; + pub(crate) fn parse_mod_statement( + &mut self, + name: Span, + mut tree: ASTTree, + parent: &mut ModuleScope, + ) { + let old = self.src; self.src = self.loader.load(tree.id); + let mod_name = name.parse_arena(old, self.arena); + let mut mod_scope = ModuleScope::default(); loop { let next = tree.next_node(self.arena); match next { - Some(v) => self.check_node(v.clone()), - _ => break, + None => break, + Some(v) => { + self.check_node(v, &mut mod_scope); + } } } - self.context = old_context; - self.src = old_src; + parent.submodules.insert(mod_name, mod_scope); + self.src = old; } + pub(crate) fn type_from_path(&mut self, input: &Path) -> Type { let vec = input.0.clone(); use Type::*; @@ -129,90 +132,87 @@ impl<'this> GlobalSymbolTree<'this> { let first = vec.first(self.arena); match first { ListNode::Empty => {} - ListNode::Node(val, _) => { - let name = val.name.parse_arena(self.src, self.arena); + ListNode::Node(PathNode::Named { name, param: _ }, _) => { + let name = name.parse_arena(self.src, self.arena); match name { - "i8" => return I8, - "u8" => return U8, - "f8" => return F8, - "i16" => return I16, - "u16" => return U16, - "f16" => return F16, - "i32" => return I32, - "u32" => return U32, - "f32" => return F32, - "i64" => return I64, - "u64" => return U64, - "f64" => return F64, - "fport" => return FPort, - "void" => return Void, + "integer8" => return Integer8, + "unsigned8" => return Unsigned8, + "float8" => return Float8, + "integer16" => return Integer16, + "unsigned16" => return Unsigned16, + "float16" => return Float16, + "integer32" => return Integer32, + "unsigned32" => return Unsigned32, + "float32" => return Float32, + "integer64" => return Integer64, + "unsigned64" => return Unsigned64, + "float64" => return Float64, + "floatport" => return FloatPort, + "nothing" => return Nothing, _ => {} } } + _ => {} } } Link(self.path_to_symbol_name(input)) } - pub(crate) fn ast_to_gst_params( - &mut self, - input: FunctionDeclarationParameters, - ) -> FunctionParameters { - let avec = self.arena.take(input.0); - let mut out = FunctionParameters(Vec::new()); - for i in avec.iter() { - let name = i.name.parse_arena(self.src, self.arena).to_string(); - let p_type = self.type_from_path(&i.arg_type); - out.0.push((name, p_type)); - } - out - } - pub(crate) fn path_to_symbol_name(&mut self, input: &Path) -> SymbolName { let vec = input.0.clone(); - let mut out = SymbolName::default(); - for i in vec.iter(self.arena) { - let name = i.name.parse_arena(self.src, self.arena).to_string(); - out.path.push(name); + let mut out = SymbolName::new(); + let mut iter = vec.iter(self.arena); + loop { + let next = iter.next(); + if next.is_none() { + break; + } + if let Some(PathNode::Named { name, param: _ }) = next { + let parsed = name.parse_arena(self.src, self.arena).to_string(); + out.path.push(parsed); + } } out } } -#[derive(Hash, Clone, PartialEq, Eq, Default, Debug)] +#[derive(Hash, Clone, PartialEq, Eq, Debug)] pub struct SymbolName { pub(crate) path: Vec, } -#[derive(Hash, Clone, PartialEq, Eq, Debug)] +impl SymbolName { + fn new() -> Self { + Self { path: vec![] } + } +} + +#[derive(Hash, Clone, Debug)] pub enum Symbol { Function { return_type: Type, - params: FunctionParameters, + params: FunctionDeclarationParameters, }, Viewport { - params: FunctionParameters, + params: FunctionDeclarationParameters, }, } #[derive(Hash, Clone, PartialEq, Eq, Debug)] pub enum Type { - I8, - U8, - F8, - I16, - U16, - F16, - I32, - U32, - F32, - I64, - U64, - F64, - FPort, - Void, + Integer8, + Unsigned8, + Float8, + Integer16, + Unsigned16, + Float16, + Integer32, + Unsigned32, + Float32, + Integer64, + Unsigned64, + Float64, + FloatPort, + Nothing, Link(SymbolName), } - -#[derive(Hash, Clone, PartialEq, Eq, Debug)] -pub struct FunctionParameters(Vec<(String, Type)>); diff --git a/compiler/pipec-prelude/src/lib.rs b/compiler/pipec-prelude/src/lib.rs index 2031d5b..41ea1bf 100644 --- a/compiler/pipec-prelude/src/lib.rs +++ b/compiler/pipec-prelude/src/lib.rs @@ -29,6 +29,7 @@ pub fn run_compiler() { let ast_tree = ast_generator.tree(); let mut gst = GlobalSymbolTree::new(&mut arena, &mut loader, ast_tree); - gst.generate(); - println!("{:#?}", gst.map); + let scope = gst.generate(); + println!("{:#?}", scope); + println!("{} bytes used for arena", &arena.index()); } diff --git a/compiler/pipec-span/src/lib.rs b/compiler/pipec-span/src/lib.rs index edb7a3c..f47daf3 100644 --- a/compiler/pipec-span/src/lib.rs +++ b/compiler/pipec-span/src/lib.rs @@ -1,18 +1,18 @@ #![allow(dead_code)] -use pipec_arena::{ASlice, Arena}; +use pipec_arena::{ASlice, AStr, Arena}; use putbackpeekmore::PutBackPeekMore; use std::str::Chars; /// A span in a source later used to be read from using the function parse(). /// The idea is to not store entire Strings inside tokens, but rather these less expensive structs for more performance. -#[derive(Default, Clone, Copy, PartialEq, Debug)] +#[derive(Default, Clone, Copy, PartialEq, Debug, Hash)] pub struct Span { pub begin: usize, pub end: usize, } impl Span { - pub fn parse_arena<'b>(&self, input: ASlice, arena: &Arena) -> &'b str { + pub fn parse_arena<'b>(&self, input: ASlice, arena: &Arena) -> &'b str { let parsed = arena.take_str_slice(input); &parsed[self.begin..self.end] } diff --git a/compiler/pipec-tests/src/ast/functiondeclaration/test.pipec b/compiler/pipec-tests/src/ast/functiondeclaration/test.pipec index 5fabbf3..df61824 100644 --- a/compiler/pipec-tests/src/ast/functiondeclaration/test.pipec +++ b/compiler/pipec-tests/src/ast/functiondeclaration/test.pipec @@ -1,2 +1,3 @@ function random_function_name(arg1 : this , arg2 : that) {} -function random_function_name(arg1 : this , arg2 : that) -> u32 {} +function random_function_name(arg1 : this , arg2 : that) => u32 {} + diff --git a/compiler/pipec-tests/src/ast/variablemutability/test.pipec b/compiler/pipec-tests/src/ast/variablemutability/test.pipec index 5731a4a..bb63369 100644 --- a/compiler/pipec-tests/src/ast/variablemutability/test.pipec +++ b/compiler/pipec-tests/src/ast/variablemutability/test.pipec @@ -1,4 +1,4 @@ function main() { - let x = 0; - let mutable x = 0; + immutable x = 0; + mutable x = 0; }