5828 lines
202 KiB
Rust
5828 lines
202 KiB
Rust
#![allow(dead_code)]
|
|
|
|
use std::{
|
|
collections::BTreeMap,
|
|
fmt::{Debug, Display},
|
|
};
|
|
|
|
use intern::{InternPool, PointerFlags, StructFlags, AMD64_POINTER_TYPE_INFO};
|
|
use num_bigint::BigInt;
|
|
|
|
use crate::{
|
|
ast::FloatingType, comptime::ComptimeNumber, lexer::SourceLocation, tokens::Token,
|
|
writeln_indented,
|
|
};
|
|
|
|
pub mod intern;
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub enum Tag {
|
|
/// pseudo tag, contains a range from a..b into extra of all files.
|
|
Root,
|
|
/// `data` is a range from a..b into extra of all global nodes.
|
|
File,
|
|
/// `data` is an intern to a name, and an index into extra of [index: return_type, index: ParameterList]
|
|
FunctionProto,
|
|
/// `data` is an index to a FunctionProto and an index to a Block
|
|
FunctionDecl,
|
|
/// `data` is a range from a..b into extra of indices to parameters
|
|
ParameterList,
|
|
/// `data` is an index to a type, and an intern to a name
|
|
Parameter,
|
|
/// `data` is range from a..b into `extra` of indices to statements
|
|
Block,
|
|
/// `data` is range from a..b into `extra` of indices to statements, where the last one is an expression
|
|
BlockTrailingExpr,
|
|
/// `data` is an index to a type, and an intern to a value
|
|
Constant,
|
|
/// `data` is an index to an expression
|
|
ExprStmt,
|
|
/// `data` is none
|
|
ReturnStmt,
|
|
/// `data` is an index to an expr
|
|
ReturnExprStmt,
|
|
/// `data` is a range from a..b into `extra` of `[name: intern, type: index]`
|
|
VarDecl,
|
|
/// `data` is a range from a..b into `extra` of `[name: intern, type: index]`
|
|
MutVarDecl,
|
|
/// `data` is a range from a..b into `extra` of `[name: intern, expr: index, type?: index]`
|
|
VarDeclAssignment,
|
|
/// `data` is a range from a..b into `extra` of `[name: intern, expr: index, type?: index]`
|
|
MutVarDeclAssignment,
|
|
/// `data` is an intern to a name, and an offset into `extra` of `[type: index, expr: index]`
|
|
GlobalDecl,
|
|
/// `data` is an intern to a name, and an offset into extra of `[flags, type0 ,..., typeN ,name0 ,..., nameN]`
|
|
StructDecl,
|
|
/// `data` is an index to a type, and an intern to a name
|
|
FieldDecl,
|
|
/// `data` is an index to a VarDecl, GlobalDecl or FunctionDecl
|
|
DeclRef,
|
|
/// `data` is an inlined key into the symbol table (scope: index, name: intern)
|
|
DeclRefUnresolved,
|
|
/// `data` is an intern of a type
|
|
InternedType,
|
|
/// `data` is an index to a StructDecl
|
|
TypeDeclRef,
|
|
/// `data` is an inlined key into the symbol table (scope: index, name: intern)
|
|
TypeDeclRefUnresolved,
|
|
/// `data` is an index to a Type and u32 PointerFlags (extra offset)
|
|
PointerType,
|
|
/// `data` is an index to a length expression, and an underlying pointer type
|
|
ArrayType,
|
|
/// `data` is an index to an expr and an index to an ArgumentList
|
|
CallExpr,
|
|
/// `data` is an index to an expr and an intern to a field name
|
|
FieldAccess,
|
|
/// `data` is a range from a..b into extra of indices to arguments
|
|
ArgumentList,
|
|
/// `data` is an index to an expression
|
|
Argument,
|
|
/// `data` is an index to an expression, and an intern to a name
|
|
NamedArgument,
|
|
/// `data` is an index to lhs, and an index to the type
|
|
ExplicitCast,
|
|
/// `data` is a single index to an expr
|
|
Deref,
|
|
AddressOf,
|
|
Not,
|
|
Negate,
|
|
PlaceToValueConversion,
|
|
ValueToPlaceConversion,
|
|
/// data is two indices for `lhs` and `rhs`
|
|
Or,
|
|
And,
|
|
BitOr,
|
|
BitXOr,
|
|
BitAnd,
|
|
Eq,
|
|
NEq,
|
|
Lt,
|
|
Gt,
|
|
Le,
|
|
Ge,
|
|
Shl,
|
|
Shr,
|
|
Add,
|
|
Sub,
|
|
Mul,
|
|
Div,
|
|
Rem,
|
|
Assign,
|
|
SubscriptExpr,
|
|
IfExpr,
|
|
/// `data` is an index to an expression and an index into extra for [if, else]
|
|
IfElseExpr,
|
|
// TODO:
|
|
/// `data` is a ParseError
|
|
Error,
|
|
/// placeholder tag for reserved indices/nodes, `data` is none
|
|
Undefined,
|
|
}
|
|
|
|
impl Tag {
|
|
fn is_type(&self) -> bool {
|
|
match self {
|
|
Tag::TypeDeclRef
|
|
| Tag::TypeDeclRefUnresolved
|
|
| Tag::PointerType
|
|
| Tag::InternedType
|
|
| Tag::ArrayType
|
|
| Tag::StructDecl => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
fn is_expr(&self) -> bool {
|
|
match self {
|
|
Tag::Constant
|
|
| Tag::DeclRef
|
|
| Tag::Deref
|
|
| Tag::CallExpr
|
|
| Tag::AddressOf
|
|
| Tag::Not
|
|
| Tag::Negate
|
|
| Tag::Or
|
|
| Tag::And
|
|
| Tag::BitOr
|
|
| Tag::BitXOr
|
|
| Tag::BitAnd
|
|
| Tag::Eq
|
|
| Tag::NEq
|
|
| Tag::Lt
|
|
| Tag::Gt
|
|
| Tag::Le
|
|
| Tag::Ge
|
|
| Tag::Shl
|
|
| Tag::Shr
|
|
| Tag::Add
|
|
| Tag::Sub
|
|
| Tag::Mul
|
|
| Tag::Div
|
|
| Tag::Rem
|
|
| Tag::SubscriptExpr
|
|
| Tag::IfExpr
|
|
| Tag::IfElseExpr
|
|
| Tag::Block
|
|
| &Tag::BlockTrailingExpr => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, thiserror::Error, PartialEq, Eq)]
|
|
enum ParseError {
|
|
#[error("Unexpected end of token iter.")]
|
|
UnexpectedEndOfTokens,
|
|
#[error("Expected Token {0}.")]
|
|
ExpectedToken(Token),
|
|
#[error("Expected Token {0}, but other token was found.")]
|
|
ExpectedTokenNotFound(Token),
|
|
#[error("Expected either a function declaration or a global variable.")]
|
|
UnexpectedTokenAtFileScope,
|
|
#[error("Expected Ident.")]
|
|
ExpectedIdent,
|
|
#[error("Integral types may not be wider than 65535 bits.")]
|
|
IntegralTypeTooWide,
|
|
#[error("Expected typename.")]
|
|
ExpectedTypeName,
|
|
#[error("Dummy Message.")]
|
|
ExpectedFunctionPrototype,
|
|
#[error("Dummy Message.")]
|
|
ExpectedPrimaryExpression,
|
|
#[error("Dummy Message.")]
|
|
ExpectedConstantLiteral,
|
|
#[error("Dummy Message.")]
|
|
ExpectedExpression,
|
|
#[error("Dummy Message.")]
|
|
ExpectedPostfixExpression,
|
|
#[error("Dummy Message.")]
|
|
ExpectedPrefixExpression,
|
|
#[error("Dummy Message.")]
|
|
ExpectedArgumentList,
|
|
#[error("Dummy Message.")]
|
|
ExpectedStatement,
|
|
#[error("Dummy Message.")]
|
|
UnmatchedParens(u32),
|
|
#[error("Dummy Message.")]
|
|
ExpectedTypeDeclaration,
|
|
#[error("Dummy Message.")]
|
|
UnexpectedTypeAttributes,
|
|
#[error("Dummy Message.")]
|
|
UnmatchedSquareBracket(u32),
|
|
#[error("Dummy Message.")]
|
|
ExpectedEndOfBlock,
|
|
#[error("Dummy Message.")]
|
|
UnmatchedBrace(u32),
|
|
#[error("Dummy Message.")]
|
|
UnmatchedDelimiter(u32),
|
|
#[error("Error in child node {0:?}.")]
|
|
ErrorNode(Index),
|
|
}
|
|
|
|
#[repr(packed)]
|
|
#[derive(Clone, Copy)]
|
|
struct Node {
|
|
/// defines the type of the node in the tree
|
|
tag: Tag,
|
|
data: Data,
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
pub union Data {
|
|
none: (),
|
|
error: ParseError,
|
|
index: Index,
|
|
two_indices: (Index, Index),
|
|
range: (Index, Index),
|
|
extra_range: (u32, u32),
|
|
intern: intern::Index,
|
|
index_intern: (Index, intern::Index),
|
|
two_interns: (intern::Index, intern::Index),
|
|
intern_and_extra_offset: (intern::Index, u32),
|
|
index_and_extra_offset: (Index, u32),
|
|
index_and_opaque: (Index, u32),
|
|
}
|
|
|
|
impl Default for Tag {
|
|
fn default() -> Self {
|
|
Tag::Undefined
|
|
}
|
|
}
|
|
impl Default for SourceLocation {
|
|
fn default() -> Self {
|
|
Self::invalid()
|
|
}
|
|
}
|
|
|
|
impl Default for Data {
|
|
fn default() -> Self {
|
|
Self::none()
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
#[allow(dead_code)]
|
|
enum ExpandedData {
|
|
None,
|
|
Error(ParseError),
|
|
Index(Index),
|
|
TwoIndices(Index, Index),
|
|
Range(Index, Index),
|
|
ExtraRange(usize, usize),
|
|
Intern(intern::Index),
|
|
IndexIntern(Index, intern::Index),
|
|
TwoInterns(intern::Index, intern::Index),
|
|
InternAndExtraOffset(intern::Index, usize),
|
|
IndexAndExtraOffset(Index, usize),
|
|
IndexAndOpaque(Index, u32),
|
|
}
|
|
|
|
impl ExpandedData {
|
|
fn from_none() -> Self {
|
|
Self::None
|
|
}
|
|
fn from_error(data: Data) -> Self {
|
|
Self::Error(data.as_error())
|
|
}
|
|
fn from_index(data: Data) -> Self {
|
|
Self::Index(data.as_index())
|
|
}
|
|
|
|
fn from_two_indices(data: Data) -> Self {
|
|
let data = data.as_two_indices();
|
|
Self::TwoIndices(data.0, data.1)
|
|
}
|
|
fn from_range(data: Data) -> Self {
|
|
let data = data.as_index_range();
|
|
Self::Range(data.0, data.1)
|
|
}
|
|
fn from_extra_range(data: Data) -> Self {
|
|
let data = data.as_extra_range();
|
|
Self::ExtraRange(data.0, data.1)
|
|
}
|
|
fn from_intern(data: Data) -> Self {
|
|
let data = data.as_intern();
|
|
Self::Intern(data)
|
|
}
|
|
fn from_index_intern(data: Data) -> Self {
|
|
let data = data.as_index_intern();
|
|
Self::IndexIntern(data.0, data.1)
|
|
}
|
|
fn from_two_interns(data: Data) -> Self {
|
|
let data = data.as_two_interns();
|
|
Self::TwoInterns(data.0, data.1)
|
|
}
|
|
fn from_intern_and_extra_offset(data: Data) -> Self {
|
|
let data = data.as_intern_and_extra_offset();
|
|
Self::InternAndExtraOffset(data.0, data.1)
|
|
}
|
|
fn from_index_and_extra_offset(data: Data) -> Self {
|
|
let data = data.as_index_and_extra_offset();
|
|
Self::IndexAndExtraOffset(data.0, data.1)
|
|
}
|
|
fn from_index_and_opaque(data: Data) -> Self {
|
|
let data = data.as_index_and_opaque();
|
|
Self::IndexAndExtraOffset(data.0, data.1)
|
|
}
|
|
}
|
|
|
|
impl From<(Tag, Data)> for ExpandedData {
|
|
fn from((tag, data): (Tag, Data)) -> Self {
|
|
match tag {
|
|
Tag::FunctionProto => Self::from_index_and_extra_offset(data),
|
|
Tag::ParameterList => Self::from_extra_range(data),
|
|
Tag::Root => Self::from_extra_range(data),
|
|
Tag::File => Self::from_extra_range(data),
|
|
Tag::ArgumentList
|
|
| Tag::VarDecl
|
|
| Tag::MutVarDecl
|
|
| Tag::VarDeclAssignment
|
|
| Tag::MutVarDeclAssignment
|
|
| Tag::BlockTrailingExpr
|
|
| Tag::Block => Self::from_extra_range(data),
|
|
Tag::FieldDecl | Tag::Constant | Tag::Parameter => Self::from_index_intern(data),
|
|
Tag::Or
|
|
| Tag::And
|
|
| Tag::BitOr
|
|
| Tag::BitXOr
|
|
| Tag::BitAnd
|
|
| Tag::Eq
|
|
| Tag::NEq
|
|
| Tag::Lt
|
|
| Tag::Gt
|
|
| Tag::Le
|
|
| Tag::Ge
|
|
| Tag::Shl
|
|
| Tag::Shr
|
|
| Tag::Add
|
|
| Tag::Sub
|
|
| Tag::Mul
|
|
| Tag::Div
|
|
| Tag::Rem
|
|
| Tag::Assign
|
|
| Tag::IfExpr
|
|
| Tag::SubscriptExpr
|
|
| Tag::CallExpr
|
|
| Tag::ArrayType
|
|
| Tag::FunctionDecl => Self::from_two_indices(data),
|
|
Tag::ReturnExprStmt
|
|
| Tag::DeclRef
|
|
| Tag::TypeDeclRef
|
|
| Tag::Argument
|
|
| Tag::Deref
|
|
| Tag::AddressOf
|
|
| Tag::Not
|
|
| Tag::Negate
|
|
| Tag::PlaceToValueConversion
|
|
| Tag::ValueToPlaceConversion
|
|
| Tag::ExprStmt => Self::from_index(data),
|
|
Tag::FieldAccess
|
|
| Tag::DeclRefUnresolved
|
|
| Tag::TypeDeclRefUnresolved
|
|
| Tag::NamedArgument
|
|
| Tag::ExplicitCast => Self::from_index_intern(data),
|
|
Tag::GlobalDecl => Self::from_intern_and_extra_offset(data),
|
|
Tag::InternedType | Tag::StructDecl => Self::from_intern(data),
|
|
Tag::PointerType | Tag::IfElseExpr => Self::from_index_and_extra_offset(data),
|
|
Tag::Error => Self::from_error(data),
|
|
Tag::ReturnStmt | Tag::Undefined => Self::from_none(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Data {
|
|
fn as_error(self) -> ParseError {
|
|
unsafe { self.error }
|
|
}
|
|
fn as_index(self) -> Index {
|
|
unsafe { self.index }
|
|
}
|
|
fn as_two_indices(self) -> (Index, Index) {
|
|
unsafe { self.two_indices }
|
|
}
|
|
fn as_index_range(self) -> (Index, Index) {
|
|
unsafe { self.range }
|
|
}
|
|
fn as_extra_range(self) -> (usize, usize) {
|
|
let (a, b) = unsafe { self.extra_range };
|
|
(a as usize, b as usize)
|
|
}
|
|
fn as_intern(self) -> intern::Index {
|
|
unsafe { self.intern }
|
|
}
|
|
|
|
fn as_two_interns(self) -> (intern::Index, intern::Index) {
|
|
unsafe { self.two_interns }
|
|
}
|
|
|
|
fn as_index_intern(self) -> (Index, intern::Index) {
|
|
unsafe { self.index_intern }
|
|
}
|
|
fn as_index_and_extra_offset(self) -> (Index, usize) {
|
|
let (i, e) = unsafe { self.index_and_extra_offset };
|
|
(i, e as usize)
|
|
}
|
|
fn as_intern_and_extra_offset(self) -> (intern::Index, usize) {
|
|
let (i, e) = unsafe { self.intern_and_extra_offset };
|
|
(i, e as usize)
|
|
}
|
|
fn as_index_and_opaque(self) -> (Index, usize) {
|
|
let (i, e) = unsafe { self.index_and_opaque };
|
|
(i, e as usize)
|
|
}
|
|
}
|
|
|
|
impl Data {
|
|
fn none() -> Self {
|
|
Self { none: () }
|
|
}
|
|
fn error(error: ParseError) -> Self {
|
|
Self { error }
|
|
}
|
|
fn index(index: Index) -> Self {
|
|
Self { index }
|
|
}
|
|
fn two_indices(a: Index, b: Index) -> Self {
|
|
Self {
|
|
two_indices: (a, b),
|
|
}
|
|
}
|
|
fn two_interns(a: intern::Index, b: intern::Index) -> Self {
|
|
Self {
|
|
two_interns: (a, b),
|
|
}
|
|
}
|
|
fn range_of_indices(a: Index, b: Index) -> Self {
|
|
Self { range: (a, b) }
|
|
}
|
|
fn extra_range(a: u32, b: u32) -> Self {
|
|
Self {
|
|
extra_range: (a, b),
|
|
}
|
|
}
|
|
fn intern(intern: intern::Index) -> Self {
|
|
Self { intern }
|
|
}
|
|
fn index_and_intern(index: Index, intern: intern::Index) -> Self {
|
|
Self {
|
|
index_intern: (index, intern),
|
|
}
|
|
}
|
|
fn intern_and_extra_offset(intern: intern::Index, offset: u32) -> Self {
|
|
Self {
|
|
intern_and_extra_offset: (intern, offset),
|
|
}
|
|
}
|
|
fn index_and_extra_offset(index: Index, offset: u32) -> Self {
|
|
Self {
|
|
index_and_extra_offset: (index, offset),
|
|
}
|
|
}
|
|
fn index_and_opaque(index: Index, value: u32) -> Self {
|
|
Self {
|
|
index_and_opaque: (index, value),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
enum PlaceOrValue {
|
|
Value(index::Index),
|
|
Place(index::Index),
|
|
}
|
|
|
|
impl PlaceOrValue {
|
|
fn into_index(self) -> index::Index {
|
|
match self {
|
|
PlaceOrValue::Value(index) => index,
|
|
PlaceOrValue::Place(index) => index,
|
|
}
|
|
}
|
|
fn is_value(&self) -> bool {
|
|
matches!(self, &Self::Value(_))
|
|
}
|
|
fn is_place(&self) -> bool {
|
|
!self.is_value()
|
|
}
|
|
fn into_value(self) -> PlaceOrValue {
|
|
Self::Value(self.into_index())
|
|
}
|
|
fn into_place(self) -> PlaceOrValue {
|
|
Self::Place(self.into_index())
|
|
}
|
|
fn eq_discriminant(&self, other: &Self) -> bool {
|
|
core::mem::discriminant(self).eq(&core::mem::discriminant(other))
|
|
}
|
|
fn with_index(self, index: Index) -> PlaceOrValue {
|
|
match self {
|
|
PlaceOrValue::Value(_) => Self::Value(index),
|
|
PlaceOrValue::Place(_) => Self::Place(index),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<index::Index> for PlaceOrValue {
|
|
fn from(value: index::Index) -> Self {
|
|
Self::Value(value)
|
|
}
|
|
}
|
|
|
|
mod index {
|
|
use std::num::NonZero;
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
#[repr(u8)]
|
|
pub enum Kind {
|
|
Other = 0,
|
|
Function,
|
|
GlobalDecl,
|
|
Error,
|
|
File,
|
|
}
|
|
|
|
impl TryFrom<u8> for Kind {
|
|
type Error = ();
|
|
|
|
fn try_from(value: u8) -> Result<Self, ()> {
|
|
match value {
|
|
0 => Ok(Self::Other),
|
|
1 => Ok(Self::Function),
|
|
2 => Ok(Self::GlobalDecl),
|
|
3 => Ok(Self::Error),
|
|
4 => Ok(Self::File),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Index type that has 28 bits of index and 4 bits of kind.
|
|
#[repr(transparent)]
|
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct Index(NonZero<u32>);
|
|
|
|
impl core::fmt::Debug for Index {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("Index")
|
|
.field("kind", &self.kind())
|
|
.field("index", &self.index_u32())
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl core::fmt::Display for Index {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
let label = match self.kind() {
|
|
Kind::Other => "",
|
|
Kind::Function => "funcs.",
|
|
Kind::GlobalDecl => "gdecls.",
|
|
Kind::Error => "errors.",
|
|
Kind::File => "files.",
|
|
};
|
|
|
|
write!(f, "%{label}{}", self.index_u32())
|
|
}
|
|
}
|
|
|
|
impl Index {
|
|
pub fn new(kind: Kind, idx: u32) -> Option<Self> {
|
|
let inner = NonZero::new((kind as u32) << 28 | idx & ((1 << 28) - 1));
|
|
|
|
inner.map(Self)
|
|
}
|
|
pub fn kind(&self) -> Kind {
|
|
Kind::try_from(((self.0.get() >> 28) & 0b1111) as u8).unwrap()
|
|
}
|
|
pub fn index_u32(&self) -> u32 {
|
|
self.0.get() & ((1 << 28) - 1)
|
|
}
|
|
pub fn index_usize(&self) -> usize {
|
|
self.index_u32() as usize
|
|
}
|
|
pub fn from_u32(inner: u32) -> Option<Self> {
|
|
NonZero::new(inner).map(Self)
|
|
}
|
|
pub unsafe fn from_u32_unchecked(inner: u32) -> Self {
|
|
Self(NonZero::new_unchecked(inner))
|
|
}
|
|
pub fn as_u32(self) -> u32 {
|
|
self.0.get()
|
|
}
|
|
pub fn into_u32(self) -> u32 {
|
|
self.0.get()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub use index::{Index, Kind};
|
|
|
|
#[derive(Debug, Clone)]
|
|
struct AstTables<T> {
|
|
functions: Vec<T>,
|
|
global_decls: Vec<T>,
|
|
errors: Vec<T>,
|
|
files: Vec<T>,
|
|
other: Vec<T>,
|
|
}
|
|
|
|
impl<T> core::ops::Index<index::Index> for AstTables<T> {
|
|
type Output = T;
|
|
|
|
fn index(&self, index: index::Index) -> &Self::Output {
|
|
&self.table_ref(index.kind())[index.index_usize()]
|
|
}
|
|
}
|
|
|
|
impl<T> core::ops::IndexMut<index::Index> for AstTables<T> {
|
|
fn index_mut(&mut self, index: index::Index) -> &mut Self::Output {
|
|
&mut self.table_mut(index.kind())[index.index_usize()]
|
|
}
|
|
}
|
|
|
|
impl<T> AstTables<T> {
|
|
fn new() -> Self {
|
|
Self {
|
|
functions: Vec::new(),
|
|
global_decls: Vec::new(),
|
|
errors: Vec::new(),
|
|
files: Vec::new(),
|
|
other: Vec::new(),
|
|
}
|
|
}
|
|
|
|
fn get(&self, index: index::Index) -> Option<&T> {
|
|
self.table_ref(index.kind()).get(index.index_usize())
|
|
}
|
|
unsafe fn get_unchecked(&self, index: index::Index) -> &T {
|
|
self.table_ref(index.kind())
|
|
.get_unchecked(index.index_usize())
|
|
}
|
|
|
|
fn init() -> Self
|
|
where
|
|
T: Default,
|
|
{
|
|
Self {
|
|
functions: Vec::new(),
|
|
global_decls: Vec::new(),
|
|
errors: Vec::new(),
|
|
files: Vec::new(),
|
|
other: vec![T::default()],
|
|
}
|
|
}
|
|
|
|
fn push(&mut self, kind: index::Kind, t: T) -> index::Index {
|
|
let table = self.table_mut(kind);
|
|
let i = table.len();
|
|
table.push(t);
|
|
|
|
index::Index::new(kind, i as u32).unwrap()
|
|
}
|
|
|
|
fn reserve(&mut self, kind: index::Kind) -> index::Index
|
|
where
|
|
T: Default,
|
|
{
|
|
self.push(kind, T::default())
|
|
}
|
|
|
|
fn table_mut(&mut self, kind: index::Kind) -> &mut Vec<T> {
|
|
match kind {
|
|
index::Kind::Other => &mut self.other,
|
|
index::Kind::Function => &mut self.functions,
|
|
index::Kind::GlobalDecl => &mut self.global_decls,
|
|
index::Kind::Error => &mut self.errors,
|
|
index::Kind::File => &mut self.files,
|
|
}
|
|
}
|
|
|
|
fn table_ref(&self, kind: index::Kind) -> &Vec<T> {
|
|
match kind {
|
|
index::Kind::Other => &self.other,
|
|
index::Kind::Function => &self.functions,
|
|
index::Kind::GlobalDecl => &self.global_decls,
|
|
index::Kind::Error => &self.errors,
|
|
index::Kind::File => &self.files,
|
|
}
|
|
}
|
|
|
|
fn table_len(&self, kind: index::Kind) -> usize {
|
|
self.table_ref(kind).len()
|
|
}
|
|
|
|
fn iter(&self) -> impl Iterator<Item = &T> {
|
|
self.errors
|
|
.iter()
|
|
.chain(self.files.iter())
|
|
.chain(self.functions.iter())
|
|
.chain(self.global_decls.iter())
|
|
.chain(self.other.iter())
|
|
}
|
|
}
|
|
|
|
pub struct Ast {
|
|
tags: AstTables<Tag>,
|
|
datas: AstTables<Data>,
|
|
source_locs: AstTables<SourceLocation>,
|
|
extra: Vec<u32>,
|
|
}
|
|
|
|
impl Debug for Ast {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.debug_struct("Ast")
|
|
.field_with("nodes", |f| {
|
|
let mut list = f.debug_list();
|
|
struct LocDisplay(SourceLocation);
|
|
impl Debug for LocDisplay {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "({})", self.0)
|
|
}
|
|
}
|
|
let entries = self
|
|
.tags
|
|
.iter()
|
|
.cloned()
|
|
.zip(self.datas.iter().cloned())
|
|
.zip(self.source_locs.iter().cloned())
|
|
.enumerate()
|
|
.map(|(i, ((tag, data), loc))| {
|
|
(i, tag, ExpandedData::from((tag, data)), LocDisplay(loc))
|
|
});
|
|
list.entries(entries).finish()
|
|
})
|
|
.field("extra", &self.extra)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl Ast {
|
|
fn new() -> Ast {
|
|
let mut tags = AstTables::new();
|
|
let mut datas = AstTables::new();
|
|
let mut source_locs = AstTables::new();
|
|
|
|
tags.other.push(Tag::Root);
|
|
datas.other.push(Data::extra_range(0, 0));
|
|
source_locs.other.push(SourceLocation::new(0, 0));
|
|
|
|
Self {
|
|
tags,
|
|
datas,
|
|
extra: vec![],
|
|
source_locs,
|
|
}
|
|
}
|
|
|
|
fn reserve_node_other(&mut self) -> Index {
|
|
self.reserve_node(Kind::Other)
|
|
}
|
|
|
|
fn reserve_node(&mut self, kind: index::Kind) -> Index {
|
|
let i = self.tags.reserve(kind);
|
|
self.datas.reserve(kind);
|
|
self.source_locs.reserve(kind);
|
|
|
|
i
|
|
}
|
|
|
|
fn get_loc(&self, index: Index) -> SourceLocation {
|
|
self.source_locs[index]
|
|
}
|
|
|
|
fn push_error(&mut self, error: ParseError, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node(Kind::Error);
|
|
self.set_tag_data_source_loc(i, Tag::Error, Data::error(error), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn set_file<I: IntoIterator<Item = Index>>(&mut self, i: Index, decls: I, loc: SourceLocation) {
|
|
let (extra_start, extra_end) = self.extend_extra_by_indices(decls);
|
|
self.set_tag_data_source_loc(i, Tag::File, Data::extra_range(extra_start, extra_end), loc);
|
|
}
|
|
|
|
fn push_file<I: IntoIterator<Item = Index>>(&mut self, decls: I, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node(Kind::File);
|
|
self.set_file(i, decls, loc);
|
|
i
|
|
}
|
|
|
|
fn set_root<I: IntoIterator<Item = Index>>(&mut self, decls: I) {
|
|
let (extra_start, extra_end) = self.extend_extra_by_indices(decls);
|
|
self.tags.other[0] = Tag::Root;
|
|
self.datas.other[0] = Data::extra_range(extra_start, extra_end);
|
|
}
|
|
|
|
fn get_root_file_indices<'a>(&'a self) -> impl Iterator<Item = Index> + 'a {
|
|
let (a, b) = self.datas.other[0].as_extra_range();
|
|
self.extra[a..b]
|
|
.iter()
|
|
.cloned()
|
|
.map(|i| Index::from_u32(i).unwrap())
|
|
}
|
|
|
|
fn push_global_decl(
|
|
&mut self,
|
|
ident: intern::Index,
|
|
ty: Index,
|
|
expr: Index,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node(Kind::GlobalDecl);
|
|
let (extra_start, _) = self.extend_extra([ty.into_u32(), expr.into_u32()]);
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::GlobalDecl,
|
|
Data::intern_and_extra_offset(ident, extra_start),
|
|
loc,
|
|
);
|
|
|
|
i
|
|
}
|
|
|
|
fn set_fn_decl(&mut self, i: Index, proto: Index, body: Index, loc: SourceLocation) {
|
|
self.set_tag_data_source_loc(i, Tag::FunctionDecl, Data::two_indices(proto, body), loc);
|
|
}
|
|
|
|
fn push_fn_decl(&mut self, proto: Index, body: Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node(Kind::Function);
|
|
self.set_fn_decl(i, proto, body, loc);
|
|
i
|
|
}
|
|
|
|
fn push_ret(&mut self, expr: Option<Index>, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node(Kind::Other);
|
|
match expr {
|
|
Some(expr) => {
|
|
self.set_tag_data_source_loc(i, Tag::ReturnExprStmt, Data::index(expr), loc)
|
|
}
|
|
None => self.set_tag_data_source_loc(i, Tag::ReturnStmt, Data::none(), loc),
|
|
}
|
|
|
|
i
|
|
}
|
|
|
|
fn push_var_decl(
|
|
&mut self,
|
|
is_let: bool,
|
|
name: intern::Index,
|
|
ty: Option<Index>,
|
|
assignment: Option<Index>,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node_other();
|
|
|
|
let start = self.extra.len() as u32;
|
|
self.extra.push(name.into_u32());
|
|
_ = self.extend_extra(assignment.map(|i| i.into_u32()));
|
|
_ = self.extend_extra(ty.map(|i| i.into_u32()));
|
|
let end = self.extra.len() as u32;
|
|
|
|
let tag = match (is_let, assignment.is_some()) {
|
|
(true, false) => Tag::VarDecl,
|
|
(true, true) => Tag::VarDeclAssignment,
|
|
(false, false) => Tag::MutVarDecl,
|
|
(false, true) => Tag::MutVarDeclAssignment,
|
|
};
|
|
|
|
self.set_tag_data_source_loc(i, tag, Data::extra_range(start, end), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_fn_proto(
|
|
&mut self,
|
|
ident: intern::Index,
|
|
return_type: Index,
|
|
parameter_list: Index,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node_other();
|
|
let (extra_start, _) =
|
|
self.extend_extra([return_type.into_u32(), parameter_list.into_u32()]);
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::FunctionProto,
|
|
Data::intern_and_extra_offset(ident, extra_start),
|
|
loc,
|
|
);
|
|
|
|
i
|
|
}
|
|
|
|
fn set_block<I: IntoIterator<Item = Index>>(
|
|
&mut self,
|
|
i: Index,
|
|
statements: I,
|
|
trailing: Option<Index>,
|
|
loc: SourceLocation,
|
|
) {
|
|
let (extra_start, extra_end) =
|
|
self.extend_extra_by_indices(statements.into_iter().chain(trailing.into_iter()));
|
|
if trailing.is_some() {
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::BlockTrailingExpr,
|
|
Data::extra_range(extra_start, extra_end),
|
|
loc,
|
|
);
|
|
} else {
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::Block,
|
|
Data::extra_range(extra_start, extra_end),
|
|
loc,
|
|
);
|
|
}
|
|
}
|
|
|
|
fn push_block<I: IntoIterator<Item = Index>>(
|
|
&mut self,
|
|
statements: I,
|
|
trailing: Option<Index>,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_block(i, statements, trailing, loc);
|
|
i
|
|
}
|
|
|
|
fn push_parameter_list<I: IntoIterator<Item = Index>>(
|
|
&mut self,
|
|
parameters: I,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node_other();
|
|
let (extra_start, extra_end) = self.extend_extra_by_indices(parameters);
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::ParameterList,
|
|
Data::extra_range(extra_start, extra_end),
|
|
loc,
|
|
);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_argument(&mut self, expr: Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, Tag::Argument, Data::index(expr), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_named_argument(
|
|
&mut self,
|
|
name: intern::Index,
|
|
expr: Index,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::NamedArgument,
|
|
Data::index_and_intern(expr, name),
|
|
loc,
|
|
);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_parameter(&mut self, name: intern::Index, ty: Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, Tag::Parameter, Data::index_and_intern(ty, name), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_argument_list<I: IntoIterator<Item = Index>>(
|
|
&mut self,
|
|
args: I,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node_other();
|
|
let (extra_start, extra_end) = self.extend_extra_by_indices(args);
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::ArgumentList,
|
|
Data::extra_range(extra_start, extra_end),
|
|
loc,
|
|
);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_unary(&mut self, tag: Tag, lhs: Index, loc: SourceLocation) -> PlaceOrValue {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, tag, Data::index(lhs), loc);
|
|
|
|
match tag {
|
|
Tag::Deref => PlaceOrValue::Place(i),
|
|
_ => PlaceOrValue::Value(i),
|
|
}
|
|
}
|
|
|
|
/// converts from a place expression to a value expression.
|
|
fn push_place_to_value_conversion(&mut self, index: Index) -> Index {
|
|
let loc = self.get_loc(index);
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(index, Tag::PlaceToValueConversion, Data::index(index), loc);
|
|
|
|
i
|
|
}
|
|
|
|
/// converts from a value expression to a place expression.
|
|
fn push_value_to_place_conversion(&mut self, index: Index) -> Index {
|
|
let loc = self.get_loc(index);
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(index, Tag::ValueToPlaceConversion, Data::index(index), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_binary(&mut self, tag: Tag, lhs: Index, rhs: Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, tag, Data::two_indices(lhs, rhs), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_assign(&mut self, lhs: Index, rhs: Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, Tag::Assign, Data::two_indices(lhs, rhs), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_cast(&mut self, lhs: Index, ty: Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, Tag::ExplicitCast, Data::two_indices(lhs, ty), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_if(&mut self, cond: Index, body: Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, Tag::IfExpr, Data::two_indices(cond, body), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_if_else(
|
|
&mut self,
|
|
cond: Index,
|
|
body: Index,
|
|
other: Index,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node_other();
|
|
let (extra_start, _) = self.extend_extra_by_indices([body, other]);
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::IfElseExpr,
|
|
Data::index_and_extra_offset(cond, extra_start),
|
|
loc,
|
|
);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_call_expr(&mut self, lhs: Index, args: Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, Tag::CallExpr, Data::two_indices(lhs, args), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_decl_ref_unresolved(
|
|
&mut self,
|
|
scope: Index,
|
|
ident: intern::Index,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::DeclRefUnresolved,
|
|
Data::index_and_intern(scope, ident),
|
|
loc,
|
|
);
|
|
|
|
i
|
|
}
|
|
|
|
fn resolve_decl_ref(&mut self, i: Index, decl: Index) {
|
|
self.tags[i] = Tag::DeclRef;
|
|
self.datas[i] = Data::index(decl);
|
|
}
|
|
|
|
fn push_struct_decl<I: IntoIterator<Item = (intern::Index, Index)>>(
|
|
&mut self,
|
|
name: intern::Index,
|
|
flags: StructFlags,
|
|
fields: I,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node(Kind::GlobalDecl);
|
|
self.set_struct_decl(i, name, flags, fields, loc)
|
|
}
|
|
|
|
fn set_struct_decl<I: IntoIterator<Item = (intern::Index, Index)>>(
|
|
&mut self,
|
|
i: Index,
|
|
name: intern::Index,
|
|
flags: StructFlags,
|
|
fields: I,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let (offset, _) = self.extend_extra([flags.pack()]);
|
|
let (names, types) = fields
|
|
.into_iter()
|
|
.map(|(name, ty)| (name.into_u32(), ty.into_u32()))
|
|
.unzip::<_, _, Vec<_>, Vec<_>>();
|
|
self.extend_extra(types);
|
|
self.extend_extra(names);
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::StructDecl,
|
|
Data::intern_and_extra_offset(name, offset),
|
|
loc,
|
|
);
|
|
i
|
|
}
|
|
|
|
fn push_field_decl(&mut self, name: intern::Index, ty: Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, Tag::FieldDecl, Data::index_and_intern(ty, name), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_field_access(
|
|
&mut self,
|
|
expr: Index,
|
|
name: intern::Index,
|
|
loc: SourceLocation,
|
|
) -> PlaceOrValue {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, Tag::FieldAccess, Data::index_and_intern(expr, name), loc);
|
|
|
|
PlaceOrValue::Place(i)
|
|
}
|
|
|
|
fn push_interend_type(&mut self, ty: intern::Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, Tag::InternedType, Data::intern(ty), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_array_type(
|
|
&mut self,
|
|
length_expr: Index,
|
|
pointer_ty: Index,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::ArrayType,
|
|
Data::two_indices(length_expr, pointer_ty),
|
|
loc,
|
|
);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_pointer_type(&mut self, ty: Index, flags: PointerFlags, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::PointerType,
|
|
Data::index_and_extra_offset(ty, flags.pack() as u32),
|
|
loc,
|
|
);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_type_ref_unresolved(
|
|
&mut self,
|
|
scope: Index,
|
|
ident: intern::Index,
|
|
loc: SourceLocation,
|
|
) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(
|
|
i,
|
|
Tag::TypeDeclRefUnresolved,
|
|
Data::index_and_intern(scope, ident),
|
|
loc,
|
|
);
|
|
|
|
i
|
|
}
|
|
|
|
fn resolve_type_ref(&mut self, i: Index, decl: Index) {
|
|
self.tags[i] = Tag::TypeDeclRef;
|
|
self.datas[i] = Data::index(decl);
|
|
}
|
|
|
|
fn push_expr_stmt(&mut self, expr: Index) -> Index {
|
|
let i = self.reserve_node_other();
|
|
let loc = self.get_loc(expr);
|
|
self.set_tag_data_source_loc(i, Tag::ExprStmt, Data::index(expr), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn push_constant(&mut self, value: intern::Index, ty: Index, loc: SourceLocation) -> Index {
|
|
let i = self.reserve_node_other();
|
|
self.set_tag_data_source_loc(i, Tag::Constant, Data::index_and_intern(ty, value), loc);
|
|
|
|
i
|
|
}
|
|
|
|
fn extend_extra_by_indices<I: IntoIterator<Item = Index>>(&mut self, indices: I) -> (u32, u32) {
|
|
self.extend_extra(indices.into_iter().map(|i| i.as_u32()))
|
|
}
|
|
fn extend_extra<I: IntoIterator<Item = u32>>(&mut self, words: I) -> (u32, u32) {
|
|
let i = self.extra.len() as u32;
|
|
self.extra.extend(words);
|
|
|
|
(i, self.extra.len() as u32)
|
|
}
|
|
fn set_tag_data_source_loc(&mut self, index: Index, tag: Tag, data: Data, loc: SourceLocation) {
|
|
self.tags[index] = tag;
|
|
self.datas[index] = data;
|
|
self.source_locs[index] = loc;
|
|
}
|
|
}
|
|
|
|
struct Children(Vec<Index>);
|
|
|
|
impl Display for Children {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "[")?;
|
|
if let Some((last, rest)) = self.0.split_last() {
|
|
for i in rest {
|
|
write!(f, "{i}, ")?;
|
|
}
|
|
write!(f, "{last}")?;
|
|
}
|
|
write!(f, "]")
|
|
}
|
|
}
|
|
|
|
type TypeCache = BTreeMap<Index, intern::Index>;
|
|
// type ComptimeCache = BTreeMap<Index, bool>;
|
|
|
|
#[derive(Debug, Default)]
|
|
struct ComptimeCache {
|
|
inner: BTreeMap<Index, bool>,
|
|
// this is (a,b) where b dominates a
|
|
// meaning:
|
|
// when a is marked as runtime, b can be updated to be runtime as well.
|
|
dependencies: BTreeMap<Index, Index>,
|
|
}
|
|
|
|
impl ComptimeCache {
|
|
fn get(&self, key: &Index) -> Option<bool> {
|
|
self.inner.get(key).cloned()
|
|
}
|
|
fn insert(&mut self, key: Index, value: bool) {
|
|
self.inner.insert(key, value);
|
|
if !value {
|
|
self.set_runtime(key);
|
|
}
|
|
}
|
|
fn mark_as_dominated_by(&mut self, a: Index, b: Index) {
|
|
self.dependencies.insert(a, b);
|
|
}
|
|
fn set_runtime(&mut self, key: Index) {
|
|
self.inner.insert(key, false);
|
|
if let Some(&dom) = self.dependencies.get(&key) {
|
|
self.set_runtime(dom);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Ast {
|
|
fn get_type_of_node(
|
|
&self,
|
|
ip: &InternPool,
|
|
cache: &mut TypeCache,
|
|
index: Index,
|
|
) -> intern::Index {
|
|
if let Some(ty) = cache.get(&index) {
|
|
return *ty;
|
|
}
|
|
|
|
let void = ip.get_void_type();
|
|
let tag = self.tags[index];
|
|
let data = self.datas[index];
|
|
|
|
let ty = match tag {
|
|
Tag::ArgumentList
|
|
| Tag::ExprStmt
|
|
| Tag::ReturnExprStmt
|
|
| Tag::Block
|
|
| Tag::ParameterList
|
|
| Tag::File => void,
|
|
// these all evaluate to pointers
|
|
Tag::VarDecl | Tag::MutVarDecl | Tag::VarDeclAssignment | Tag::MutVarDeclAssignment => {
|
|
let (_, b) = data.as_extra_range();
|
|
let pointee =
|
|
self.get_type_of_node(ip, cache, Index::from_u32(self.extra[b - 1]).unwrap());
|
|
|
|
ip.try_get_pointer_type(
|
|
pointee,
|
|
Some(PointerFlags::new(tag == Tag::VarDecl, false, false)),
|
|
)
|
|
.unwrap()
|
|
}
|
|
// these all evaluate to pointers
|
|
Tag::GlobalDecl => {
|
|
let (_, a) = data.as_intern_and_extra_offset();
|
|
let pointee =
|
|
self.get_type_of_node(ip, cache, Index::from_u32(self.extra[a]).unwrap());
|
|
|
|
ip.try_get_pointer_type(pointee, Some(PointerFlags::new(true, false, true)))
|
|
.unwrap()
|
|
}
|
|
Tag::FunctionDecl => self.get_type_of_node(ip, cache, data.as_two_indices().0),
|
|
Tag::FunctionProto => {
|
|
let (_, i) = data.as_intern_and_extra_offset();
|
|
let (return_type, parameter_list) = (
|
|
Index::from_u32(self.extra[i]).unwrap(),
|
|
Index::from_u32(self.extra[i + 1]).unwrap(),
|
|
);
|
|
let return_type = self.datas[return_type].as_intern();
|
|
let parameters = {
|
|
let (a, b) = self.datas[parameter_list].as_extra_range();
|
|
self.extra[a..b]
|
|
.iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.map(|i| {
|
|
// i is index to a parameter, a parameter is (index, intern)
|
|
let ty = self.datas[i].as_index_intern().0;
|
|
self.datas[ty].as_intern()
|
|
})
|
|
};
|
|
|
|
ip.try_get_function_type(return_type, parameters).unwrap()
|
|
}
|
|
Tag::BlockTrailingExpr => {
|
|
let (_a, b) = data.as_extra_range();
|
|
self.get_type_of_node(ip, cache, Index::from_u32(self.extra[b - 1]).unwrap())
|
|
}
|
|
Tag::CallExpr => {
|
|
let (expr, _args) = data.as_two_indices();
|
|
let fn_ty = self.get_type_of_node(ip, cache, expr);
|
|
if let intern::Key::FunctionType { return_type, .. } = ip.get_key(fn_ty) {
|
|
return_type
|
|
} else {
|
|
eprintln!(
|
|
"lhs of call expr is not a function: {fn_ty}: {:?}",
|
|
ip.get_key(fn_ty)
|
|
);
|
|
void
|
|
}
|
|
}
|
|
Tag::Argument => self.get_type_of_node(ip, cache, data.as_index()),
|
|
Tag::NamedArgument => {
|
|
let (a, _) = data.as_index_intern();
|
|
self.get_type_of_node(ip, cache, a)
|
|
}
|
|
Tag::ExplicitCast => {
|
|
let (_, a) = data.as_two_indices();
|
|
self.get_type_of_node(ip, cache, a)
|
|
}
|
|
// this evaluates to a pointer
|
|
Tag::FieldAccess => {
|
|
let (ty_expr, name) = data.as_index_intern();
|
|
let ty = self.get_type_of_node(ip, cache, ty_expr);
|
|
let pointee = match ip.get_key(ty) {
|
|
intern::Key::PointerType { pointee, .. }
|
|
if let intern::Key::StructType { fields, .. } = ip.get_key(pointee) =>
|
|
{
|
|
fields
|
|
.iter()
|
|
.cloned()
|
|
.find(|(n, _)| n == &name)
|
|
.map(|(_, t)| t)
|
|
.unwrap_or(void)
|
|
}
|
|
intern::Key::StructType { fields, .. } => fields
|
|
.iter()
|
|
.cloned()
|
|
.find(|(n, _)| n == &name)
|
|
.map(|(_, t)| t)
|
|
.unwrap_or(void),
|
|
_ => {
|
|
unimplemented!()
|
|
}
|
|
};
|
|
|
|
ip.try_get_pointer_type(pointee, None).unwrap()
|
|
}
|
|
// this evaluates to a pointer
|
|
Tag::SubscriptExpr => {
|
|
let ty = self.get_type_of_node(ip, cache, data.as_two_indices().0);
|
|
match ip.get_key(ty) {
|
|
intern::Key::PointerType { .. } | intern::Key::ArrayType { .. } => {
|
|
// note: because of value-to-place and place-to-value,
|
|
// this is actually a pointer.
|
|
// pointee
|
|
ty
|
|
}
|
|
_ => {
|
|
eprintln!("lhs of subscript is not an array or pointer!");
|
|
void
|
|
}
|
|
}
|
|
}
|
|
// this evaluates to a pointer
|
|
Tag::AddressOf => {
|
|
let ty = self.get_type_of_node(ip, cache, data.as_index());
|
|
// TODO: find out of the expression is const, volatile for flags
|
|
|
|
// ip.try_get_pointer_type(ty, None).unwrap()
|
|
// note: because of value-to-place and place-to-value,
|
|
// this is actually the same type.
|
|
ty
|
|
}
|
|
Tag::Deref => {
|
|
let ty = self.get_type_of_node(ip, cache, data.as_index());
|
|
if let intern::Key::PointerType { pointee, .. } = ip.get_key(ty) {
|
|
pointee
|
|
} else {
|
|
eprintln!("lhs of deref is not a pointer!");
|
|
void
|
|
}
|
|
}
|
|
Tag::ValueToPlaceConversion => {
|
|
let ty = self.get_type_of_node(ip, cache, data.as_index());
|
|
ip.try_get_pointer_type(ty, None).unwrap()
|
|
}
|
|
Tag::PlaceToValueConversion => {
|
|
let ty = self.get_type_of_node(ip, cache, data.as_index());
|
|
ip.try_get_pointee_type(ty).unwrap()
|
|
}
|
|
Tag::Not | Tag::Negate => self.get_type_of_node(ip, cache, data.as_index()),
|
|
Tag::Or
|
|
| Tag::And
|
|
| Tag::BitOr
|
|
| Tag::BitXOr
|
|
| Tag::BitAnd
|
|
| Tag::Eq
|
|
| Tag::NEq
|
|
| Tag::Lt
|
|
| Tag::Gt
|
|
| Tag::Le
|
|
| Tag::Ge
|
|
| Tag::Shl
|
|
| Tag::Shr
|
|
| Tag::Add
|
|
| Tag::Sub
|
|
| Tag::Mul
|
|
| Tag::Div
|
|
| Tag::Rem => self.get_type_of_node(ip, cache, data.as_two_indices().0),
|
|
Tag::IfExpr => ip.get_bool_type(), // really?
|
|
Tag::IfElseExpr => {
|
|
let (_, b) = data.as_index_and_extra_offset();
|
|
let if_ = Index::from_u32(self.extra[b]).unwrap();
|
|
self.get_type_of_node(ip, cache, if_)
|
|
}
|
|
Tag::Constant | Tag::Parameter => {
|
|
self.get_type_of_node(ip, cache, data.as_index_intern().0)
|
|
}
|
|
Tag::DeclRef => self.get_type_of_node(ip, cache, data.as_index()),
|
|
Tag::StructDecl => {
|
|
let (name, _) = data.as_intern_and_extra_offset();
|
|
ip.try_get_struct_type(name, index).unwrap()
|
|
}
|
|
Tag::Assign
|
|
| Tag::Root
|
|
| Tag::DeclRefUnresolved
|
|
| Tag::Error
|
|
| Tag::Undefined
|
|
| Tag::ReturnStmt => void,
|
|
Tag::FieldDecl => self.get_type_of_node(ip, cache, data.as_index_intern().0),
|
|
Tag::InternedType => data.as_intern(),
|
|
Tag::TypeDeclRef | Tag::TypeDeclRefUnresolved | Tag::PointerType | Tag::ArrayType => {
|
|
ip.get_void_type()
|
|
}
|
|
};
|
|
|
|
cache.insert(index, ty);
|
|
ty
|
|
}
|
|
|
|
fn get_node_children(&self, index: Index) -> Vec<Index> {
|
|
let tag = self.tags[index];
|
|
let data = self.datas[index];
|
|
|
|
match tag {
|
|
Tag::File => {
|
|
let (a, b) = data.as_extra_range();
|
|
self.extra[a..b]
|
|
.iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.collect()
|
|
}
|
|
Tag::FunctionProto => {
|
|
let (_, i) = data.as_intern_and_extra_offset();
|
|
self.extra[i..=i + 1]
|
|
.iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.collect()
|
|
}
|
|
Tag::FunctionDecl => {
|
|
let (a, b) = data.as_two_indices();
|
|
vec![a, b]
|
|
}
|
|
Tag::ParameterList => {
|
|
let (a, b) = data.as_extra_range();
|
|
self.extra[a..b]
|
|
.iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.collect()
|
|
}
|
|
Tag::Block | Tag::BlockTrailingExpr => {
|
|
let (a, b) = data.as_extra_range();
|
|
self.extra[a..b]
|
|
.iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.collect()
|
|
}
|
|
Tag::ExprStmt | Tag::ReturnExprStmt => {
|
|
let a = data.as_index();
|
|
vec![a]
|
|
}
|
|
Tag::VarDeclAssignment | Tag::MutVarDeclAssignment => {
|
|
let (a, b) = data.as_extra_range();
|
|
self.extra[a + 1..b]
|
|
.iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.collect()
|
|
}
|
|
Tag::GlobalDecl => {
|
|
let (_, offset) = data.as_intern_and_extra_offset();
|
|
self.extra[offset..=offset + 1]
|
|
.iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.collect()
|
|
}
|
|
Tag::CallExpr | Tag::ExplicitCast => {
|
|
let (a, b) = data.as_two_indices();
|
|
vec![a, b]
|
|
}
|
|
Tag::ArgumentList => {
|
|
let (a, b) = data.as_extra_range();
|
|
self.extra[a..b]
|
|
.iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.collect()
|
|
}
|
|
Tag::Argument => {
|
|
let a = data.as_index();
|
|
vec![a]
|
|
}
|
|
Tag::FieldDecl | Tag::FieldAccess | Tag::NamedArgument => {
|
|
let (a, _) = data.as_index_intern();
|
|
vec![a]
|
|
}
|
|
Tag::ValueToPlaceConversion
|
|
| Tag::PlaceToValueConversion
|
|
| Tag::Deref
|
|
| Tag::AddressOf
|
|
| Tag::Not
|
|
| Tag::Negate => {
|
|
let a = data.as_index();
|
|
vec![a]
|
|
}
|
|
Tag::Or
|
|
| Tag::And
|
|
| Tag::BitOr
|
|
| Tag::BitXOr
|
|
| Tag::BitAnd
|
|
| Tag::Eq
|
|
| Tag::NEq
|
|
| Tag::Lt
|
|
| Tag::Gt
|
|
| Tag::Le
|
|
| Tag::Ge
|
|
| Tag::Shl
|
|
| Tag::Shr
|
|
| Tag::Add
|
|
| Tag::Sub
|
|
| Tag::Mul
|
|
| Tag::Div
|
|
| Tag::Rem
|
|
| Tag::Assign
|
|
| Tag::SubscriptExpr
|
|
| Tag::ArrayType
|
|
| Tag::IfExpr => {
|
|
let (a, b) = data.as_two_indices();
|
|
vec![a, b]
|
|
}
|
|
Tag::IfElseExpr => {
|
|
let (a, b) = data.as_index_and_extra_offset();
|
|
let if_ = Index::from_u32(self.extra[b]).unwrap();
|
|
let else_ = Index::from_u32(self.extra[b + 1]).unwrap();
|
|
vec![a, if_, else_]
|
|
}
|
|
Tag::PointerType => {
|
|
let (a, _) = data.as_index_and_extra_offset();
|
|
vec![a]
|
|
}
|
|
Tag::StructDecl => {
|
|
let (_a, offset) = data.as_intern_and_extra_offset();
|
|
let flags = StructFlags::unpack(self.extra[offset]);
|
|
self.extra[offset + 1..(offset + 1 + flags.num_fields as usize)]
|
|
.iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.collect()
|
|
}
|
|
Tag::InternedType
|
|
| Tag::Root
|
|
| Tag::TypeDeclRefUnresolved
|
|
| Tag::DeclRefUnresolved
|
|
| Tag::Error
|
|
| Tag::Undefined
|
|
| Tag::TypeDeclRef
|
|
| Tag::DeclRef
|
|
| Tag::ReturnStmt => vec![],
|
|
Tag::Parameter | Tag::Constant => {
|
|
let (a, _) = data.as_index_intern();
|
|
vec![a]
|
|
}
|
|
Tag::VarDecl | Tag::MutVarDecl => {
|
|
let (a, _) = data.as_extra_range();
|
|
|
|
vec![Index::from_u32(self.extra[a + 1]).unwrap()]
|
|
}
|
|
}
|
|
}
|
|
|
|
fn is_node_comptime_evaluable(&self, cache: &mut ComptimeCache, index: Index) -> bool {
|
|
if let Some(a) = cache.get(&index) {
|
|
a
|
|
} else {
|
|
let tag = self.tags[index];
|
|
let data = self.datas[index];
|
|
|
|
let children = self.get_node_children(index);
|
|
|
|
let are_children_comptime = |this: &Self, cache: &mut ComptimeCache| {
|
|
children
|
|
.iter()
|
|
.all(|&i| this.is_node_comptime_evaluable(cache, i))
|
|
};
|
|
|
|
let is_comptime = match tag {
|
|
Tag::Parameter => false,
|
|
// TODO: figure out if there are function protos that arent const
|
|
// Tag::FunctionProto | Tag::FunctionDecl | Tag::Block | Tag::BlockTrailingExpr => {
|
|
// are_children_comptime(self, cache)
|
|
// }
|
|
Tag::Constant => true,
|
|
Tag::ReturnStmt => true,
|
|
Tag::ReturnExprStmt => are_children_comptime(self, cache),
|
|
Tag::MutVarDecl | Tag::MutVarDeclAssignment => false,
|
|
// Tag::VarDecl => true,
|
|
// Tag::ValueToPlaceConversion => false,
|
|
Tag::PlaceToValueConversion | Tag::VarDeclAssignment => {
|
|
are_children_comptime(self, cache)
|
|
}
|
|
Tag::GlobalDecl => true,
|
|
Tag::StructDecl => true,
|
|
Tag::FieldDecl => true,
|
|
Tag::DeclRef => self.tags[data.as_index()] == Tag::GlobalDecl,
|
|
Tag::InternedType | Tag::PointerType | Tag::ArrayType | Tag::TypeDeclRef => true,
|
|
// Tag::CallExpr => are_children_comptime(self, cache),
|
|
// Tag::FieldAccess => {
|
|
// let parent = data.as_index_intern().0;
|
|
// cache.mark_as_dominated_by(index, parent);
|
|
// self.is_node_comptime_evaluable(cache, parent)
|
|
// }
|
|
Tag::ArgumentList => are_children_comptime(self, cache),
|
|
Tag::Argument => self.is_node_comptime_evaluable(cache, data.as_index()),
|
|
Tag::NamedArgument => {
|
|
self.is_node_comptime_evaluable(cache, data.as_index_intern().0)
|
|
}
|
|
Tag::ExplicitCast => {
|
|
self.is_node_comptime_evaluable(cache, data.as_two_indices().0)
|
|
}
|
|
Tag::Deref | Tag::AddressOf => false,
|
|
Tag::Not
|
|
| Tag::Negate
|
|
| Tag::Or
|
|
| Tag::And
|
|
| Tag::BitOr
|
|
| Tag::BitXOr
|
|
| Tag::BitAnd
|
|
| Tag::Eq
|
|
| Tag::NEq
|
|
| Tag::Lt
|
|
| Tag::Gt
|
|
| Tag::Le
|
|
| Tag::Ge
|
|
| Tag::Shl
|
|
| Tag::Shr
|
|
| Tag::Add
|
|
| Tag::Sub
|
|
| Tag::Mul
|
|
| Tag::Div
|
|
| Tag::SubscriptExpr // TODO: add array decl expression
|
|
| Tag::Rem => are_children_comptime(self, cache),
|
|
Tag::Assign => {
|
|
let (left, _) = data.as_two_indices();
|
|
cache.mark_as_dominated_by(index, left);
|
|
are_children_comptime(self, cache)
|
|
}
|
|
// Tag::IfExpr | Tag::IfElseExpr => are_children_comptime(self, cache),
|
|
Tag::Root
|
|
| Tag::File
|
|
| Tag::ParameterList
|
|
| Tag::ExprStmt
|
|
| Tag::DeclRefUnresolved
|
|
| Tag::TypeDeclRefUnresolved
|
|
| Tag::Error
|
|
| Tag::Undefined => false,
|
|
_ => false,
|
|
};
|
|
|
|
cache.insert(index, is_comptime);
|
|
|
|
is_comptime
|
|
}
|
|
}
|
|
|
|
fn comptime_value_of_node(
|
|
&self,
|
|
ip: &InternPool,
|
|
pointer_bits: u16,
|
|
cache: &mut TypeCache,
|
|
index: Index,
|
|
) -> Option<crate::comptime::ComptimeNumber> {
|
|
let tag = self.tags[index];
|
|
let data = self.datas[index];
|
|
|
|
match tag {
|
|
Tag::Constant => {
|
|
let (ty, value) = data.as_index_intern();
|
|
let ty = self.get_type_of_node(ip, cache, ty);
|
|
Some(interned_type_and_value_to_comptime_number(
|
|
ip,
|
|
pointer_bits,
|
|
ty,
|
|
value,
|
|
))
|
|
}
|
|
Tag::GlobalDecl => {
|
|
let (_, offset) = data.as_intern_and_extra_offset();
|
|
self.comptime_value_of_node(
|
|
ip,
|
|
pointer_bits,
|
|
cache,
|
|
Index::from_u32(self.extra[offset + 1]).unwrap(),
|
|
)
|
|
}
|
|
Tag::VarDeclAssignment => {
|
|
let (a, _) = data.as_extra_range();
|
|
self.comptime_value_of_node(
|
|
ip,
|
|
pointer_bits,
|
|
cache,
|
|
Index::from_u32(self.extra[a + 1]).unwrap(),
|
|
)
|
|
}
|
|
Tag::SubscriptExpr => {
|
|
todo!()
|
|
}
|
|
Tag::PlaceToValueConversion | Tag::DeclRef => {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, data.as_index())
|
|
}
|
|
Tag::ExplicitCast => {
|
|
let (expr, ty) = data.as_two_indices();
|
|
let ty = ip.as_ast1_type(intern::AMD64_POINTER_BITS, self.datas[ty].as_intern());
|
|
let val = self.comptime_value_of_node(ip, pointer_bits, cache, expr);
|
|
val.and_then(|i| i.explicit_cast(ty).ok())
|
|
}
|
|
Tag::Add => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.add(b).ok())
|
|
})
|
|
}
|
|
Tag::Sub => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.sub(b).ok())
|
|
})
|
|
}
|
|
Tag::Mul => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.mul(b).ok())
|
|
})
|
|
}
|
|
Tag::Div => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.div(b).ok())
|
|
})
|
|
}
|
|
Tag::Rem => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.rem(b).ok())
|
|
})
|
|
}
|
|
Tag::Shl => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.shl(b).ok())
|
|
})
|
|
}
|
|
Tag::Shr => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.shr(b).ok())
|
|
})
|
|
}
|
|
Tag::BitAnd => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.bitand(b).ok())
|
|
})
|
|
}
|
|
Tag::BitOr => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.bitor(b).ok())
|
|
})
|
|
}
|
|
Tag::BitXOr => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.bitxor(b).ok())
|
|
})
|
|
}
|
|
Tag::And => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.and(b).ok())
|
|
})
|
|
}
|
|
Tag::Or => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.or(b).ok())
|
|
})
|
|
}
|
|
Tag::Eq => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.eq(b).ok())
|
|
})
|
|
}
|
|
Tag::NEq => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.eq(b).and_then(|i| i.not()).ok())
|
|
})
|
|
}
|
|
Tag::Gt => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.gt(b).ok())
|
|
})
|
|
}
|
|
Tag::Lt => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.lt(b).ok())
|
|
})
|
|
}
|
|
Tag::Le => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.le(b).ok())
|
|
})
|
|
}
|
|
Tag::Ge => {
|
|
let (a, b) = data.as_two_indices();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| {
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, b)
|
|
.and_then(|b| a.ge(b).ok())
|
|
})
|
|
}
|
|
Tag::Not => {
|
|
let a = data.as_index();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| a.not().ok())
|
|
}
|
|
Tag::Negate => {
|
|
let a = data.as_index();
|
|
self.comptime_value_of_node(ip, pointer_bits, cache, a)
|
|
.and_then(|a| a.neg().ok())
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn comptime_number_to_interned_type_and_value(
|
|
ip: &mut InternPool,
|
|
pointer_bits: u16,
|
|
comptime: ComptimeNumber,
|
|
) -> (intern::Index, intern::Index) {
|
|
use crate::ast::IntegralType;
|
|
|
|
let (value, ty) = comptime.into_bytes_and_type();
|
|
let value = match ty {
|
|
crate::ast::Type::Bool => {
|
|
if value.get(0) != Some(&1) {
|
|
ip.get_false_value()
|
|
} else {
|
|
ip.get_true_value()
|
|
}
|
|
}
|
|
crate::ast::Type::Integer(IntegralType { bits: 65.., .. })
|
|
| crate::ast::Type::ComptimeNumber => {
|
|
let bigint = BigInt::from_signed_bytes_le(&value);
|
|
if bigint.sign() == num_bigint::Sign::Minus {
|
|
ip.get_or_insert(intern::Key::NegativeInt { bigint })
|
|
} else {
|
|
ip.get_or_insert(intern::Key::PositiveInt { bigint })
|
|
}
|
|
}
|
|
crate::ast::Type::Integer(i) => match i.bits {
|
|
..=32 => {
|
|
let mut buf = [0u8; 4];
|
|
buf[..value.len()].copy_from_slice(&value[..]);
|
|
if i.signed {
|
|
ip.get_or_insert(intern::Key::SIntSmall {
|
|
bits: i32::from_le_bytes(buf),
|
|
})
|
|
} else {
|
|
ip.get_or_insert(intern::Key::UIntSmall {
|
|
bits: u32::from_le_bytes(buf),
|
|
})
|
|
}
|
|
}
|
|
..=64 => {
|
|
let mut buf = [0u8; 8];
|
|
buf[..value.len()].copy_from_slice(&value[..]);
|
|
if i.signed {
|
|
ip.get_or_insert(intern::Key::SInt64 {
|
|
bits: i64::from_le_bytes(buf),
|
|
})
|
|
} else {
|
|
ip.get_or_insert(intern::Key::UInt64 {
|
|
bits: u64::from_le_bytes(buf),
|
|
})
|
|
}
|
|
}
|
|
_ => unreachable!(),
|
|
},
|
|
crate::ast::Type::Floating(FloatingType::Binary32) => {
|
|
let mut buf = [0u8; 4];
|
|
buf[..value.len()].copy_from_slice(&value[..]);
|
|
ip.get_or_insert(intern::Key::F32 {
|
|
bits: f32::from_le_bytes(buf),
|
|
})
|
|
}
|
|
crate::ast::Type::Floating(FloatingType::Binary64) => {
|
|
let mut buf = [0u8; 8];
|
|
buf[..value.len()].copy_from_slice(&value[..]);
|
|
|
|
ip.get_or_insert(intern::Key::F64 {
|
|
bits: f64::from_le_bytes(buf),
|
|
})
|
|
}
|
|
_ => unimplemented!(),
|
|
};
|
|
let ty = ip.from_ast1_type(pointer_bits, &ty);
|
|
|
|
(value, ty)
|
|
}
|
|
|
|
pub fn interned_type_and_value_to_comptime_number(
|
|
ip: &InternPool,
|
|
pointer_bits: u16,
|
|
ty: intern::Index,
|
|
val: intern::Index,
|
|
) -> crate::comptime::ComptimeNumber {
|
|
use crate::ast::IntegralType;
|
|
use crate::comptime::*;
|
|
|
|
let ty_key = ip.get_key(ty);
|
|
let signed = ip.is_type_signed(ty, AMD64_POINTER_TYPE_INFO);
|
|
match ty_key {
|
|
intern::Key::SIntType { bit_width: bits } | intern::Key::UIntType { bit_width: bits } => {
|
|
let ty = IntegralType::new(signed, bits);
|
|
match ip.get_key(val) {
|
|
intern::Key::SIntSmall { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
|
|
bits: bits as _,
|
|
ty,
|
|
}),
|
|
intern::Key::UIntSmall { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
|
|
bits: bits as _,
|
|
ty,
|
|
}),
|
|
intern::Key::SInt64 { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
|
|
bits: bits as _,
|
|
ty,
|
|
}),
|
|
intern::Key::UInt64 { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
|
|
bits: bits as _,
|
|
ty,
|
|
}),
|
|
intern::Key::PositiveInt { bigint } => {
|
|
ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty })
|
|
}
|
|
intern::Key::NegativeInt { bigint } => {
|
|
ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty })
|
|
}
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
intern::Key::SimpleType { ty } => match ty {
|
|
intern::SimpleType::F32 => match ip.get_key(val) {
|
|
intern::Key::F32 { bits } => {
|
|
ComptimeNumber::Floating(ComptimeFloat::Binary32(bits))
|
|
}
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
},
|
|
intern::SimpleType::F64 => match ip.get_key(val) {
|
|
intern::Key::F64 { bits } => {
|
|
ComptimeNumber::Floating(ComptimeFloat::Binary64(bits))
|
|
}
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
},
|
|
intern::SimpleType::Bool => match ip.get_key(val) {
|
|
intern::Key::TrueValue => ComptimeNumber::Bool(true),
|
|
intern::Key::FalseValue => ComptimeNumber::Bool(false),
|
|
_ => unreachable!(),
|
|
},
|
|
intern::SimpleType::Void => todo!(),
|
|
intern::SimpleType::USize | intern::SimpleType::ISize => {
|
|
let ty = IntegralType::new(
|
|
matches!(
|
|
ty_key,
|
|
intern::Key::SimpleType {
|
|
ty: intern::SimpleType::ISize
|
|
}
|
|
),
|
|
pointer_bits,
|
|
);
|
|
|
|
match ip.get_key(val) {
|
|
intern::Key::SIntSmall { bits } => {
|
|
ComptimeNumber::Integral(ComptimeInt::Native {
|
|
bits: bits as _,
|
|
ty,
|
|
})
|
|
}
|
|
intern::Key::UIntSmall { bits } => {
|
|
ComptimeNumber::Integral(ComptimeInt::Native {
|
|
bits: bits as _,
|
|
ty,
|
|
})
|
|
}
|
|
intern::Key::SInt64 { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
|
|
bits: bits as _,
|
|
ty,
|
|
}),
|
|
intern::Key::UInt64 { bits } => ComptimeNumber::Integral(ComptimeInt::Native {
|
|
bits: bits as _,
|
|
ty,
|
|
}),
|
|
intern::Key::PositiveInt { bigint } => {
|
|
ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty })
|
|
}
|
|
intern::Key::NegativeInt { bigint } => {
|
|
ComptimeNumber::Integral(ComptimeInt::BigInt { bits: bigint, ty })
|
|
}
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
intern::SimpleType::ComptimeInt => {
|
|
let bigint = match ip.get_key(val) {
|
|
intern::Key::SIntSmall { bits } => {
|
|
BigInt::from_signed_bytes_le(&bits.to_le_bytes())
|
|
}
|
|
intern::Key::UIntSmall { bits } => {
|
|
BigInt::from_signed_bytes_le(&bits.to_le_bytes())
|
|
}
|
|
intern::Key::SInt64 { bits } => {
|
|
BigInt::from_signed_bytes_le(&bits.to_le_bytes())
|
|
}
|
|
intern::Key::UInt64 { bits } => {
|
|
BigInt::from_signed_bytes_le(&bits.to_le_bytes())
|
|
}
|
|
intern::Key::PositiveInt { bigint } | intern::Key::NegativeInt { bigint } => {
|
|
bigint
|
|
}
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
};
|
|
ComptimeNumber::Integral(ComptimeInt::Comptime(bigint))
|
|
}
|
|
},
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
|
|
use visitor::AstVisitor;
|
|
|
|
impl Ast {
|
|
pub fn visitor_mut(&mut self) -> AstVisitor<&mut Self> {
|
|
AstVisitor {
|
|
scopes: vec![],
|
|
nodes: self
|
|
.get_root_file_indices()
|
|
.map(|i| visitor::A::PushChildren(i))
|
|
.collect(),
|
|
ast: self,
|
|
rev: false,
|
|
}
|
|
}
|
|
pub fn visitor_rev_mut(&mut self) -> AstVisitor<&mut Self> {
|
|
AstVisitor {
|
|
scopes: vec![],
|
|
nodes: self
|
|
.get_root_file_indices()
|
|
.map(|i| visitor::A::PushChildren(i))
|
|
.collect(),
|
|
ast: self,
|
|
rev: true,
|
|
}
|
|
}
|
|
|
|
pub fn visitor(&self) -> AstVisitor<&Self> {
|
|
AstVisitor {
|
|
scopes: vec![],
|
|
nodes: self
|
|
.get_root_file_indices()
|
|
.map(|i| visitor::A::PushChildren(i))
|
|
.collect(),
|
|
ast: self,
|
|
rev: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub mod visitor {
|
|
use super::*;
|
|
pub trait AstExt {
|
|
fn get_node_children(&self, node: Index) -> Vec<Index>;
|
|
fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data);
|
|
}
|
|
|
|
impl AstExt for &Ast {
|
|
fn get_node_children(&self, node: Index) -> Vec<Index> {
|
|
Ast::get_node_children(self, node)
|
|
}
|
|
|
|
fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data) {
|
|
(self.tags[node], self.datas[node])
|
|
}
|
|
}
|
|
impl AstExt for &mut Ast {
|
|
fn get_node_children(&self, node: Index) -> Vec<Index> {
|
|
Ast::get_node_children(self, node)
|
|
}
|
|
|
|
fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data) {
|
|
(self.tags[node], self.datas[node])
|
|
}
|
|
}
|
|
|
|
pub struct AstVisitor<AstT> {
|
|
pub(super) ast: AstT,
|
|
pub(super) scopes: Vec<Index>,
|
|
pub(super) nodes: Vec<A>,
|
|
pub(super) rev: bool,
|
|
}
|
|
|
|
impl<AstT> AstVisitor<AstT>
|
|
where
|
|
AstT: AstExt,
|
|
{
|
|
pub fn visit<
|
|
F: FnMut(&mut AstT, &[Index], Index, Tag, Data),
|
|
G: FnMut(&mut AstT, &[Index], Index, Tag, Data),
|
|
>(
|
|
&mut self,
|
|
mut pre: F,
|
|
mut post: G,
|
|
) {
|
|
while let Some(node) = self.nodes.pop() {
|
|
match node {
|
|
A::PushChildren(i) => {
|
|
self.nodes.push(A::PopSelf(i));
|
|
let children_iter = self
|
|
.ast
|
|
.get_node_children(i)
|
|
.into_iter()
|
|
.map(|i| A::PushChildren(i));
|
|
// inverse because we are popping from the end
|
|
if !self.rev {
|
|
self.nodes.extend(children_iter.rev())
|
|
} else {
|
|
self.nodes.extend(children_iter)
|
|
};
|
|
|
|
let (tag, data) = self.ast.get_node_tag_and_data(i);
|
|
|
|
let _ = pre(&mut self.ast, &self.scopes, i, tag, data);
|
|
|
|
match tag {
|
|
Tag::File
|
|
| Tag::FunctionDecl
|
|
| Tag::GlobalDecl
|
|
| Tag::Block
|
|
| Tag::BlockTrailingExpr => {
|
|
self.scopes.push(i);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
A::PopSelf(i) => {
|
|
// already popped.
|
|
let (tag, data) = self.ast.get_node_tag_and_data(i);
|
|
|
|
let _ = post(&mut self.ast, &self.scopes, i, tag, data);
|
|
|
|
match tag {
|
|
Tag::File
|
|
| Tag::FunctionDecl
|
|
| Tag::GlobalDecl
|
|
| Tag::Block
|
|
| Tag::BlockTrailingExpr => {
|
|
self.scopes.pop();
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pub fn visit_pre<F: FnMut(&mut AstT, &[Index], Index, Tag, Data)>(&mut self, mut cb: F) {
|
|
while let Some(node) = self.nodes.pop() {
|
|
match node {
|
|
A::PushChildren(i) => {
|
|
self.nodes.push(A::PopSelf(i));
|
|
let children_iter = self
|
|
.ast
|
|
.get_node_children(i)
|
|
.into_iter()
|
|
.map(|i| A::PushChildren(i));
|
|
// inverse because we are popping from the end
|
|
if !self.rev {
|
|
self.nodes.extend(children_iter.rev())
|
|
} else {
|
|
self.nodes.extend(children_iter)
|
|
};
|
|
|
|
let (tag, data) = self.ast.get_node_tag_and_data(i);
|
|
|
|
let _ = cb(&mut self.ast, &self.scopes, i, tag, data);
|
|
|
|
match tag {
|
|
Tag::File
|
|
| Tag::FunctionDecl
|
|
| Tag::GlobalDecl
|
|
| Tag::Block
|
|
| Tag::BlockTrailingExpr => {
|
|
self.scopes.push(i);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
A::PopSelf(i) => {
|
|
// already popped.
|
|
let (tag, _data) = self.ast.get_node_tag_and_data(i);
|
|
|
|
match tag {
|
|
Tag::File
|
|
| Tag::FunctionDecl
|
|
| Tag::GlobalDecl
|
|
| Tag::Block
|
|
| Tag::BlockTrailingExpr => {
|
|
self.scopes.pop();
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pub fn visit_post<F: FnMut(&mut AstT, &[Index], Index, Tag, Data)>(&mut self, mut cb: F) {
|
|
while let Some(node) = self.nodes.pop() {
|
|
match node {
|
|
A::PushChildren(i) => {
|
|
self.nodes.push(A::PopSelf(i));
|
|
let children_iter = self
|
|
.ast
|
|
.get_node_children(i)
|
|
.into_iter()
|
|
.map(|i| A::PushChildren(i));
|
|
if self.rev {
|
|
self.nodes.extend(children_iter.rev())
|
|
} else {
|
|
self.nodes.extend(children_iter)
|
|
};
|
|
|
|
let (tag, _data) = self.ast.get_node_tag_and_data(i);
|
|
|
|
match tag {
|
|
Tag::File
|
|
| Tag::FunctionDecl
|
|
| Tag::GlobalDecl
|
|
| Tag::Block
|
|
| Tag::BlockTrailingExpr => {
|
|
self.scopes.push(i);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
A::PopSelf(i) => {
|
|
// already popped.
|
|
let (tag, data) = self.ast.get_node_tag_and_data(i);
|
|
|
|
let _ = cb(&mut self.ast, &self.scopes, i, tag, data);
|
|
|
|
match tag {
|
|
Tag::File
|
|
| Tag::FunctionDecl
|
|
| Tag::GlobalDecl
|
|
| Tag::Block
|
|
| Tag::BlockTrailingExpr => {
|
|
self.scopes.pop();
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub enum A {
|
|
PushChildren(Index),
|
|
PopSelf(Index),
|
|
}
|
|
}
|
|
|
|
pub struct AstRenderer<'a> {
|
|
ast: &'a Ast,
|
|
#[allow(dead_code)]
|
|
syms: &'a crate::symbol_table::syms2::Symbols,
|
|
ip: &'a InternPool,
|
|
cache: TypeCache,
|
|
comptime_cache: ComptimeCache,
|
|
}
|
|
|
|
pub struct NodeDisplay<'a> {
|
|
node: Index,
|
|
ast: &'a Ast,
|
|
ip: &'a InternPool,
|
|
}
|
|
impl<'a> Display for NodeDisplay<'a> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
let node = self.node;
|
|
let tag = self.ast.tags[node];
|
|
let loc = self.ast.source_locs[node];
|
|
|
|
let children = Children(self.ast.get_node_children(node));
|
|
let ty = self
|
|
.ast
|
|
.get_type_of_node(self.ip, &mut TypeCache::new(), node);
|
|
|
|
let is_comptime = self
|
|
.ast
|
|
.is_node_comptime_evaluable(&mut ComptimeCache::default(), node);
|
|
writeln!(
|
|
f,
|
|
"{node} {}({ty}) = ({loc}) {tag:?} {children}",
|
|
if is_comptime { "CONST " } else { "" }
|
|
)?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<'a> AstRenderer<'a> {
|
|
pub fn new(
|
|
ast: &'a Ast,
|
|
ip: &'a InternPool,
|
|
syms: &'a crate::symbol_table::syms2::Symbols,
|
|
) -> Self {
|
|
Self {
|
|
ast,
|
|
syms,
|
|
ip,
|
|
cache: TypeCache::new(),
|
|
comptime_cache: ComptimeCache::default(),
|
|
}
|
|
}
|
|
|
|
fn render<W: core::fmt::Write>(&mut self, w: &mut W) -> core::fmt::Result {
|
|
self.ast.visitor().visit_pre(|ast, scopes, node, tag, _| {
|
|
let loc = ast.source_locs[node];
|
|
|
|
let children = Children(ast.get_node_children(node));
|
|
let ty = self.ast.get_type_of_node(self.ip, &mut self.cache, node);
|
|
let is_comptime = ast.is_node_comptime_evaluable(&mut self.comptime_cache, node);
|
|
_ = writeln_indented!(
|
|
scopes.len() as u32 * 2,
|
|
w,
|
|
"{node} {}({ty}) = ({loc}) {tag:?} {children}",
|
|
if is_comptime { "CONST " } else { "" }
|
|
);
|
|
});
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub mod ast_gen {
|
|
|
|
use intern::{PointerFlags, SimpleType};
|
|
use itertools::Itertools;
|
|
use num_bigint::{BigInt, BigUint};
|
|
|
|
use crate::{
|
|
common::from_lo_hi_dwords,
|
|
comptime,
|
|
lexer::{Radix, TokenItem, TokenIterator},
|
|
symbol_table::syms2::SymbolKind,
|
|
tokens::PRECEDENCE_MAP,
|
|
variant,
|
|
};
|
|
|
|
use super::*;
|
|
|
|
#[derive(Debug)]
|
|
pub struct ErrorInfo {
|
|
error: ParseError,
|
|
loc: SourceLocation,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Parser {
|
|
pub ast: Ast,
|
|
pub intern: intern::InternPool,
|
|
pub syms: crate::symbol_table::syms2::Symbols,
|
|
scopes: Vec<Index>,
|
|
pub errors: Vec<ErrorInfo>,
|
|
}
|
|
|
|
type ParseResult<T> = core::result::Result<T, ErrorInfo>;
|
|
|
|
impl Display for Parser {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
self.display().render(f)
|
|
}
|
|
}
|
|
|
|
impl Parser {
|
|
pub fn new() -> Parser {
|
|
Self {
|
|
ast: Ast::new(),
|
|
intern: intern::InternPool::new(),
|
|
syms: crate::symbol_table::syms2::Symbols::new(),
|
|
scopes: Vec::new(),
|
|
errors: Vec::new(),
|
|
}
|
|
}
|
|
|
|
pub fn display(&self) -> AstRenderer<'_> {
|
|
AstRenderer::new(&self.ast, &self.intern, &self.syms)
|
|
}
|
|
|
|
pub fn node_display(&self, node: Index) -> NodeDisplay<'_> {
|
|
NodeDisplay {
|
|
node,
|
|
ast: &self.ast,
|
|
ip: &self.intern,
|
|
}
|
|
}
|
|
|
|
pub fn create_comptime_folding_graph(&mut self, pointer_bits: u16) {
|
|
let mut type_cache = TypeCache::new();
|
|
let mut cache = ComptimeCache::default();
|
|
let mut nodes = self.ast.get_root_file_indices().collect::<Vec<_>>();
|
|
while let Some(node) = nodes.pop() {
|
|
if !self.ast.is_node_comptime_evaluable(&mut cache, node) {
|
|
nodes.extend(self.ast.get_node_children(node));
|
|
}
|
|
}
|
|
|
|
let mut node_map = Vec::<Index>::new();
|
|
let edges = cache
|
|
.inner
|
|
.iter()
|
|
.filter(|(_, b)| **b)
|
|
.map(|(e, _)| self.ast.get_node_children(*e).into_iter().map(|d| (*e, d)))
|
|
.flatten()
|
|
// .map(|(a, b)| (a.into_u32(), b.into_u32()))
|
|
.map(|(a, b)| {
|
|
(
|
|
node_map.iter().position(|&i| i == a).unwrap_or_else(|| {
|
|
node_map.push(a);
|
|
node_map.len() - 1
|
|
}) as u32,
|
|
node_map.iter().position(|&i| i == b).unwrap_or_else(|| {
|
|
node_map.push(b);
|
|
node_map.len() - 1
|
|
}) as u32,
|
|
)
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
let extra_nodes = cache
|
|
.inner
|
|
.iter()
|
|
.filter(|(_, b)| **b)
|
|
.filter_map(|(i, _)| (!node_map.contains(i)).then(|| node_map.push(*i)))
|
|
.count();
|
|
|
|
eprintln!("cache: {cache:?}");
|
|
eprintln!("node_map: {node_map:?}");
|
|
eprintln!("edges: {edges:?}");
|
|
|
|
let mut graph = petgraph::stable_graph::StableDiGraph::<(), ()>::from_edges(edges);
|
|
for _ in 0..extra_nodes {
|
|
graph.add_node(());
|
|
}
|
|
std::fs::write(
|
|
"comptime_graph.dot",
|
|
&format!(
|
|
"{:?}",
|
|
petgraph::dot::Dot::with_attr_getters(
|
|
&graph,
|
|
&[],
|
|
&|_graph, _edgeref| { "".to_string() },
|
|
&|_graph, noderef| {
|
|
format!("label = \"{}\"", node_map[noderef.0.index()])
|
|
}
|
|
)
|
|
),
|
|
)
|
|
.expect("writing comptime graph repr");
|
|
|
|
while let Some(external) = graph.externals(petgraph::Direction::Outgoing).next() {
|
|
let node = node_map[external.index()];
|
|
if !(self.ast.tags[node] == Tag::Constant || self.ast.tags[node].is_type())
|
|
&& self.ast.tags[node].is_expr()
|
|
{
|
|
eprintln!("folding {node}:\n{}", self.node_display(node));
|
|
let value = self
|
|
.ast
|
|
.comptime_value_of_node(&self.intern, pointer_bits, &mut type_cache, node)
|
|
.expect(&format!("{node} has value of None?"));
|
|
let (value, ty) = comptime_number_to_interned_type_and_value(
|
|
&mut self.intern,
|
|
pointer_bits,
|
|
value,
|
|
);
|
|
let ty = self.ast.push_interend_type(ty, self.ast.get_loc(node));
|
|
self.ast.set_tag_data_source_loc(
|
|
node,
|
|
Tag::Constant,
|
|
Data::index_and_intern(ty, value),
|
|
self.ast.get_loc(node),
|
|
);
|
|
} else {
|
|
eprintln!("rejecting {node}:\n{}", self.node_display(node));
|
|
}
|
|
// comptime fold node
|
|
graph.remove_node(external);
|
|
}
|
|
}
|
|
|
|
/// folds more AST-patterns into structures that are easier to build the IR with
|
|
pub fn fold_more_patterns(&mut self) {
|
|
use visitor::AstExt;
|
|
self.ast.visitor_mut().visit_post(|ast, _, _i, tag, data| {
|
|
match tag {
|
|
// normalise functions with block-with-trailing-expr into block
|
|
Tag::FunctionDecl => {
|
|
let (_, block) = data.as_two_indices();
|
|
|
|
let (block_tag, block_data) = ast.get_node_tag_and_data(block);
|
|
if block_tag == Tag::BlockTrailingExpr {
|
|
let (_, end) = block_data.as_extra_range();
|
|
let end = end - 1;
|
|
let expr = Index::from_u32(ast.extra[end]).unwrap();
|
|
let loc = ast.get_loc(expr);
|
|
let ret = ast.push_ret(Some(expr), loc);
|
|
// modify last element in place to be a return instruction
|
|
ast.extra[end] = ret.as_u32();
|
|
ast.tags[block] = Tag::Block;
|
|
eprintln!("folding ({block}): {block_tag:?} into Tag::Block");
|
|
eprintln!("expr: {expr:?}");
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
});
|
|
}
|
|
|
|
pub fn intern_types(&mut self) {
|
|
self.ast.visitor_mut().visit_post(|ast, _, i, tag, data| {
|
|
match tag {
|
|
Tag::ArrayType => {
|
|
let (length, pointee) = data.as_two_indices();
|
|
let pointee =
|
|
ast.datas[pointee].as_intern();
|
|
variant!( self.intern.get_key(pointee) => intern::Key::PointerType { pointee, flags });
|
|
|
|
// get interened value from constant node
|
|
let length = {
|
|
let value = ast.datas[length]
|
|
.as_index_intern()
|
|
.1;
|
|
|
|
match self.intern.get_key(value) {
|
|
intern::Key::SIntSmall { bits } => {
|
|
bits as u32
|
|
}
|
|
intern::Key::UIntSmall { bits } => {
|
|
bits as u32
|
|
}
|
|
intern::Key::SInt64 { bits } => {
|
|
bits as u32
|
|
}
|
|
intern::Key::UInt64 { bits } => {
|
|
bits as u32
|
|
}
|
|
intern::Key::NegativeInt { bigint }
|
|
| intern::Key::PositiveInt { bigint } => {
|
|
bigint
|
|
.iter_u32_digits()
|
|
.next()
|
|
.unwrap_or(0)
|
|
}
|
|
_ => 0,
|
|
}
|
|
};
|
|
|
|
let ty = self.intern.get_array_type(
|
|
pointee,
|
|
Some(flags),
|
|
length,
|
|
);
|
|
ast.tags[i] = Tag::InternedType;
|
|
ast.datas[i] = Data::intern(ty);
|
|
}
|
|
Tag::PointerType => {
|
|
let (pointee, flags) =
|
|
data.as_index_and_extra_offset();
|
|
let pointee =
|
|
ast.datas[pointee].as_intern();
|
|
let ty = self.intern.get_pointer_type(
|
|
pointee,
|
|
Some(PointerFlags::unpack(flags as u8)),
|
|
);
|
|
ast.tags[i] = Tag::InternedType;
|
|
ast.datas[i] = Data::intern(ty);
|
|
}
|
|
Tag::TypeDeclRef => {
|
|
let decl = data.as_index();
|
|
let (name, _) = ast.datas[decl]
|
|
.as_intern_and_extra_offset();
|
|
|
|
let ty =
|
|
self.intern.get_struct_type(name, decl);
|
|
ast.tags[i] = Tag::InternedType;
|
|
ast.datas[i] = Data::intern(ty);
|
|
}
|
|
Tag::FunctionProto => {
|
|
let (_, i) = data.as_intern_and_extra_offset();
|
|
let (return_type, parameter_list) = (
|
|
Index::from_u32(ast.extra[i]).unwrap(),
|
|
Index::from_u32(ast.extra[i + 1]).unwrap(),
|
|
);
|
|
let return_type = ast.get_type_of_node(
|
|
&self.intern,
|
|
&mut TypeCache::new(),
|
|
return_type
|
|
);
|
|
let parameters = {
|
|
let (a, b) = ast.datas
|
|
[parameter_list]
|
|
.as_extra_range();
|
|
ast.extra[a..b].iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.map(|i| {
|
|
// i is index to a parameter, a parameter is (index, intern)
|
|
let ty = ast.datas[i]
|
|
.as_index_intern()
|
|
.0;
|
|
ast.datas[ty].as_intern()
|
|
})
|
|
};
|
|
|
|
self.intern
|
|
.get_function_type(return_type, parameters);
|
|
}
|
|
Tag::StructDecl => {
|
|
let (name, offset) =
|
|
data.as_intern_and_extra_offset();
|
|
let flags =
|
|
StructFlags::unpack(ast.extra[offset]);
|
|
|
|
let types = (offset + 1)
|
|
..(offset + 1 + flags.num_fields as usize);
|
|
let names =
|
|
(offset + 1 + flags.num_fields as usize)
|
|
..(offset
|
|
+ 1
|
|
+ flags.num_fields as usize * 2);
|
|
|
|
let types = ast.extra[types]
|
|
.iter()
|
|
.map(|&i| Index::from_u32(i).unwrap())
|
|
.map(|i| {
|
|
ast.datas[i].as_intern()
|
|
});
|
|
let names = ast.extra[names]
|
|
.iter()
|
|
.map(|&i| intern::Index::from_u32(i));
|
|
|
|
self.intern.insert_or_replace_struct_type(
|
|
name,
|
|
i,
|
|
flags.packed,
|
|
flags.c_like,
|
|
names.zip(types),
|
|
);
|
|
}
|
|
_ => {}
|
|
}
|
|
});
|
|
}
|
|
|
|
pub fn resolve_decl_refs(&mut self) {
|
|
self.ast
|
|
.visitor_rev_mut()
|
|
.visit_post(|ast, _, node, tag, _| {
|
|
match tag {
|
|
Tag::TypeDeclRefUnresolved => {
|
|
let (scope, name) = ast.datas[node].as_index_intern();
|
|
// look in my_scope
|
|
if let Some(decl) =
|
|
self.syms
|
|
.find_type_symbol(scope, name, ast.source_locs[node])
|
|
{
|
|
ast.resolve_type_ref(node, decl)
|
|
};
|
|
}
|
|
Tag::DeclRefUnresolved => {
|
|
let (scope, name) = ast.datas[node].as_index_intern();
|
|
|
|
// look in my_scope
|
|
if let Some(decl) =
|
|
self.syms.find_symbol(scope, name, ast.source_locs[node])
|
|
{
|
|
ast.resolve_decl_ref(node, decl)
|
|
};
|
|
}
|
|
_ => {}
|
|
}
|
|
});
|
|
}
|
|
|
|
fn current_scope(&self) -> Index {
|
|
self.scopes.last().cloned().unwrap()
|
|
}
|
|
|
|
fn parse_ident(&mut self, tokens: &mut TokenIterator) -> Result<intern::Index, ErrorInfo> {
|
|
let ident = tokens.expect_token(Token::Ident).map_err(|_| ErrorInfo {
|
|
error: ParseError::ExpectedIdent,
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
|
|
let name = self.intern.get_or_insert(intern::Key::String {
|
|
str: ident.lexeme(),
|
|
});
|
|
|
|
Ok(name)
|
|
}
|
|
|
|
fn parse_pointer(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
let loc = tokens.current_source_location();
|
|
tokens.eat_token(Token::Star).ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Star),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
|
|
let &[cnst, vol, noalias] =
|
|
&tokens.eat_all_zero_or_once(&[Token::Const, Token::Volatile, Token::Noalias])[..3]
|
|
else {
|
|
unreachable!()
|
|
};
|
|
let pointee = self.parse_type(tokens)?;
|
|
|
|
Ok(self
|
|
.ast
|
|
.push_pointer_type(pointee, PointerFlags::new(cnst, vol, noalias), loc))
|
|
}
|
|
|
|
/// [LENGTH]const? volatile? noalias? TYPE
|
|
fn parse_array_type(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
let loc = tokens.current_source_location();
|
|
let length_expr = self.parse_bracketed(tokens, |this, tokens| {
|
|
this.parse_value_expr(tokens)
|
|
// let next = tokens.peek_token().ok_or(ErrorInfo {
|
|
// error: ParseError::UnexpectedEndOfTokens,
|
|
// loc: tokens.current_source_location(),
|
|
// })?;
|
|
// match next.token() {
|
|
// Token::IntegerBinConstant
|
|
// | Token::IntegerHexConstant
|
|
// | Token::IntegerOctConstant
|
|
// | Token::IntegerConstant => {
|
|
// _ = tokens.next();
|
|
// Ok(this.parse_integral_constant(&next, next.source_location()))
|
|
// }
|
|
// _ => Err(ErrorInfo {
|
|
// error: ParseError::ExpectedConstantLiteral,
|
|
// loc: tokens.current_source_location(),
|
|
// }),
|
|
// }
|
|
})?;
|
|
|
|
let &[cnst, vol, noalias] =
|
|
&tokens.eat_all_zero_or_once(&[Token::Const, Token::Volatile, Token::Noalias])[..3]
|
|
else {
|
|
unreachable!()
|
|
};
|
|
|
|
let pointee = self.parse_type(tokens)?;
|
|
let pointer =
|
|
self.ast
|
|
.push_pointer_type(pointee, PointerFlags::new(cnst, vol, noalias), loc);
|
|
|
|
Ok(self.ast.push_array_type(length_expr, pointer, loc))
|
|
}
|
|
|
|
fn parse_simple_type(&mut self, token: Token) -> Option<intern::Index> {
|
|
match token {
|
|
Token::Void => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
|
|
ty: SimpleType::Void,
|
|
})),
|
|
Token::Bool => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
|
|
ty: SimpleType::Bool,
|
|
})),
|
|
Token::F32 => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
|
|
ty: SimpleType::F32,
|
|
})),
|
|
Token::F64 => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
|
|
ty: SimpleType::F64,
|
|
})),
|
|
Token::USize => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
|
|
ty: SimpleType::USize,
|
|
})),
|
|
Token::ISize => Some(self.intern.get_assume_present(&intern::Key::SimpleType {
|
|
ty: SimpleType::ISize,
|
|
})),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn try_parse_integral_type(
|
|
&mut self,
|
|
typename: &str,
|
|
) -> Result<Option<intern::Index>, ParseError> {
|
|
let mut iter = typename.chars().peekable();
|
|
let signed = match iter.next() {
|
|
Some('u') => false,
|
|
Some('i') => true,
|
|
_ => {
|
|
return Ok(None);
|
|
}
|
|
};
|
|
|
|
// need 1 digit for an integral type
|
|
if iter.peek().map(|&c| crate::common::is_digit(c)) != Some(true) {
|
|
return Ok(None);
|
|
}
|
|
|
|
// need no nondigits after digits
|
|
if iter
|
|
.clone()
|
|
.skip_while(|&c| crate::common::is_digit(c))
|
|
.next()
|
|
.is_some()
|
|
{
|
|
return Ok(None);
|
|
}
|
|
|
|
let mut bits = 0u16;
|
|
loop {
|
|
let Some(digit) = iter.next().map(|c| c as u8 - b'0') else {
|
|
break;
|
|
};
|
|
|
|
match bits
|
|
.checked_mul(10)
|
|
.and_then(|bits| bits.checked_add(digit as u16))
|
|
{
|
|
Some(val) => {
|
|
bits = val;
|
|
}
|
|
None => {
|
|
// this IS an integral type, but it is bigger than u/i65535
|
|
return Err(ParseError::IntegralTypeTooWide);
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(Some(self.intern.get_int_type(signed, bits)))
|
|
}
|
|
|
|
fn parse_integral_constant_inner(
|
|
&mut self,
|
|
item: &TokenItem,
|
|
) -> (intern::Index, intern::Index) {
|
|
let radix = Radix::from_token(item.token()).unwrap();
|
|
|
|
let mut chars = item.lexeme().char_indices();
|
|
match radix {
|
|
Radix::Dec => {}
|
|
_ => {
|
|
_ = chars.advance_by(2);
|
|
}
|
|
}
|
|
|
|
let digits = chars
|
|
.take_while_ref(|&(_, c)| radix.is_digit()(c) || c == '_')
|
|
.filter(|&(_, c)| c != '_')
|
|
.map(|(_, c)| c)
|
|
.collect::<Vec<_>>();
|
|
|
|
let value = comptime::bigint::parse_bigint(digits.into_iter(), radix);
|
|
|
|
let ty = match chars.clone().next() {
|
|
Some((i, 'u')) | Some((i, 'i')) => self
|
|
.try_parse_integral_type(&item.lexeme()[i..])
|
|
.expect("invalid integral type??"),
|
|
_ => None,
|
|
};
|
|
|
|
let interned = match value.len() {
|
|
..1 => {
|
|
let bits = value.get(0).cloned().unwrap_or(0);
|
|
self.intern.get_or_insert(intern::Key::UIntSmall { bits })
|
|
}
|
|
..2 => {
|
|
let lo = value.get(0).cloned().unwrap_or(0);
|
|
let hi = value.get(1).cloned().unwrap_or(0);
|
|
let bits = from_lo_hi_dwords(lo, hi);
|
|
self.intern.get_or_insert(intern::Key::UInt64 { bits })
|
|
}
|
|
_ => {
|
|
let bigint = BigInt::from_biguint(num_bigint::Sign::Plus, BigUint::new(value));
|
|
self.intern
|
|
.get_or_insert(intern::Key::PositiveInt { bigint })
|
|
}
|
|
};
|
|
|
|
let ty = ty.unwrap_or(self.intern.get_comptime_int_type());
|
|
(interned, ty)
|
|
}
|
|
|
|
fn parse_integral_constant(&mut self, item: &TokenItem, loc: SourceLocation) -> Index {
|
|
let (interned, ty) = self.parse_integral_constant_inner(item);
|
|
let ty = self.ast.push_interend_type(ty, loc);
|
|
return self.ast.push_constant(interned, ty, loc);
|
|
}
|
|
|
|
fn parse_floating_constant(&mut self, item: &TokenItem, loc: SourceLocation) -> Index {
|
|
let lexeme = item.lexeme();
|
|
let lexeme = lexeme
|
|
.strip_suffix("f32")
|
|
.map(|l| (l, self.intern.get_f32_type()))
|
|
.unwrap_or(
|
|
lexeme
|
|
.strip_suffix("f64")
|
|
.map(|l| (l, self.intern.get_f64_type()))
|
|
.unwrap_or((lexeme, self.intern.get_f64_type())),
|
|
);
|
|
|
|
let bits = if lexeme.1 == self.intern.get_f32_type() {
|
|
self.intern.get_or_insert(intern::Key::F32 {
|
|
bits: lexeme.0.parse::<f32>().unwrap(),
|
|
})
|
|
} else {
|
|
self.intern.get_or_insert(intern::Key::F64 {
|
|
bits: lexeme.0.parse::<f64>().unwrap(),
|
|
})
|
|
};
|
|
|
|
let ty = self.ast.push_interend_type(lexeme.1, loc);
|
|
return self.ast.push_constant(bits, ty, loc);
|
|
}
|
|
|
|
/// TYPE <-
|
|
/// * TYPE
|
|
/// IDENTIFIER
|
|
/// SIMPLE_TYPE
|
|
/// [ TYPE ; CONSTANT_EXPR ]
|
|
/// INTEGRAL_TYPE // u[0..65535] | i[0..65535]
|
|
fn parse_type(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
let loc = tokens.current_source_location();
|
|
match tokens
|
|
.peek_token()
|
|
.ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedTypeName,
|
|
loc: tokens.current_source_location(),
|
|
})?
|
|
.token()
|
|
{
|
|
Token::Star => self.parse_pointer(tokens),
|
|
Token::OpenSquareBracket => self.parse_array_type(tokens),
|
|
Token::Ident => {
|
|
let token = tokens.next().unwrap();
|
|
match self
|
|
.try_parse_integral_type(token.lexeme())
|
|
.map_err(|error| ErrorInfo {
|
|
error,
|
|
loc: token.source_location(),
|
|
})? {
|
|
Some(int) => Ok(self.ast.push_interend_type(int, loc)),
|
|
None => {
|
|
let name = self.intern.get_or_insert(intern::Key::String {
|
|
str: token.lexeme(),
|
|
});
|
|
// TODO: this will cause issues with redefinitions of types with the same name
|
|
// and actually, make type into a proper node of the ast
|
|
Ok(self
|
|
.ast
|
|
.push_type_ref_unresolved(self.current_scope(), name, loc))
|
|
}
|
|
}
|
|
}
|
|
token => {
|
|
let ty = self.parse_simple_type(token).ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedTypeName,
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
_ = tokens.next();
|
|
|
|
Ok(self.ast.push_interend_type(ty, loc))
|
|
}
|
|
}
|
|
}
|
|
|
|
/// GLOBAL_DECL <-
|
|
/// const IDENTIFIER: TYPENAME = EXPR;
|
|
fn parse_const_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
let err = 'blk: {
|
|
let loc = tokens.current_source_location();
|
|
let Some(_) = tokens.eat_token(Token::Const) else {
|
|
break 'blk ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Const),
|
|
loc,
|
|
};
|
|
};
|
|
|
|
let ident = match self.parse_ident(tokens) {
|
|
Ok(i) => i,
|
|
Err(err) => {
|
|
break 'blk err;
|
|
}
|
|
};
|
|
|
|
let Some(_) = tokens.eat_token(Token::Colon) else {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Colon),
|
|
loc,
|
|
});
|
|
};
|
|
|
|
let typename = match self.parse_type(tokens) {
|
|
Ok(i) => i,
|
|
Err(err) => {
|
|
break 'blk err;
|
|
}
|
|
};
|
|
|
|
let Some(_) = tokens.eat_token(Token::Equal) else {
|
|
break 'blk ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Equal),
|
|
loc: tokens.current_source_location(),
|
|
};
|
|
};
|
|
|
|
let expr = match self.parse_value_expr(tokens) {
|
|
Ok(i) => i,
|
|
Err(err) => {
|
|
break 'blk err;
|
|
}
|
|
};
|
|
|
|
let Some(_) = tokens.eat_token(Token::Semi) else {
|
|
break 'blk ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Semi),
|
|
loc: tokens.current_source_location(),
|
|
};
|
|
};
|
|
|
|
let decl = self.ast.push_global_decl(ident, typename, expr, loc);
|
|
self.syms
|
|
.insert_symbol(self.current_scope(), ident, SymbolKind::Const, decl);
|
|
|
|
return Ok(decl);
|
|
};
|
|
|
|
tokens.advance_past_semi().ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Semi),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
|
|
Ok(self.ast.push_error(err.error, err.loc))
|
|
}
|
|
|
|
/// FUNCTION_PROTO <-
|
|
/// fn IDENTIFIER ()
|
|
/// fn IDENTIFIER () -> TYPENAME
|
|
/// fn IDENTIFIER ( PARAMETER_LIST ,? )
|
|
/// fn IDENTIFIER ( PARAMETER_LIST ,? ) -> TYPENAME
|
|
fn parse_fn_proto(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
) -> ParseResult<(Index, intern::Index)> {
|
|
let loc = tokens.current_source_location();
|
|
let _ = tokens.eat_token(Token::Fn).ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Fn),
|
|
loc,
|
|
})?;
|
|
|
|
let ident = self.parse_ident(tokens)?;
|
|
|
|
let parameters = self.parse_parenthesised(tokens, |this, tokens| {
|
|
if tokens.is_next_token(Token::CloseParens) {
|
|
Ok(this.ast.push_parameter_list([], loc))
|
|
} else {
|
|
this.parse_parameter_list(tokens)
|
|
}
|
|
})?;
|
|
|
|
let return_type = if let Some(_) = tokens.eat_token(Token::MinusGreater) {
|
|
self.parse_type(tokens)?
|
|
} else {
|
|
self.ast.push_interend_type(
|
|
self.intern.get_void_type(),
|
|
tokens.current_source_location(),
|
|
)
|
|
};
|
|
|
|
let decl = self.ast.push_fn_proto(ident, return_type, parameters, loc);
|
|
|
|
Ok((decl, ident))
|
|
}
|
|
|
|
fn parse_fn_inner(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
let loc = tokens.current_source_location();
|
|
let func = self.ast.reserve_node(Kind::Function);
|
|
|
|
self.push_scope(func, intern::Index::invalid());
|
|
|
|
let (proto, ident) = self.parse_fn_proto(tokens).map_err(|e| {
|
|
self.pop_scope();
|
|
e
|
|
})?;
|
|
let body = self
|
|
.parse_block(tokens)
|
|
.map(|pv| self.convert_to_value_expr(pv))
|
|
.map_err(|e| {
|
|
self.pop_scope();
|
|
e
|
|
})?;
|
|
|
|
self.pop_scope();
|
|
|
|
self.ast.set_fn_decl(func, proto, body, loc);
|
|
|
|
self.syms
|
|
.insert_symbol(self.current_scope(), ident, SymbolKind::Function, func);
|
|
|
|
Ok(func)
|
|
}
|
|
|
|
/// FUNCTION_DECL <-
|
|
/// FUNCTION_PROTO BLOCK
|
|
fn parse_fn_decl(&mut self, tokens: &mut TokenIterator) -> Index {
|
|
match self.parse_fn_inner(tokens) {
|
|
Ok(i) => i,
|
|
Err(err) => {
|
|
self.find_next_fn_or_const(tokens);
|
|
self.push_error(err.error, err.loc)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// RETURN_STATEMENT <-
|
|
/// return EXPRESSION? ;
|
|
fn parse_return_stmt(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
// SAFETY: function invariance
|
|
let ret = tokens.next().unwrap();
|
|
let loc = ret.source_location();
|
|
|
|
let expr = if tokens.eat_token(Token::Semi).is_some() {
|
|
self.ast.push_ret(None, loc)
|
|
} else {
|
|
match self.parse_value_expr(tokens) {
|
|
Ok(i) => {
|
|
tokens.eat_token(Token::Semi).ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Semi),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
self.ast.push_ret(Some(i), loc)
|
|
}
|
|
Err(err) => {
|
|
tokens.advance_past_semi().ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Semi),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
self.push_error(err.error, err.loc)
|
|
}
|
|
}
|
|
};
|
|
|
|
Ok(expr)
|
|
}
|
|
|
|
/// VAR_DECL <-
|
|
/// (let | var) IDENTIFIER (: TYPENAME)? ;
|
|
/// (let | var) IDENTIFIER (: TYPENAME)? = EXPRESSION ;
|
|
fn parse_var_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
match self.parse_var_decl_inner(tokens) {
|
|
Ok(i) => {
|
|
_ = tokens.eat_token(Token::Semi).ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Semi),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
Ok(i)
|
|
}
|
|
Err(err) => {
|
|
tokens.advance_past_semi().ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Semi),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
Ok(self.push_error(err.error, err.loc))
|
|
}
|
|
}
|
|
}
|
|
|
|
fn parse_var_decl_inner(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
// SAFETY: function invariance
|
|
let let_or_var = tokens.next().unwrap();
|
|
let loc = let_or_var.source_location();
|
|
|
|
let is_let = let_or_var.token() == Token::Let;
|
|
|
|
let name = self.parse_ident(tokens)?;
|
|
|
|
let ty = if tokens.eat_token(Token::Colon).is_some() {
|
|
Some(self.parse_type(tokens)?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let assignment = if tokens.eat_token(Token::Equal).is_some() {
|
|
Some(self.parse_value_expr(tokens)?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
let decl = self.ast.push_var_decl(is_let, name, ty, assignment, loc);
|
|
self.syms.insert_symbol(
|
|
self.current_scope(),
|
|
name,
|
|
SymbolKind::Local(tokens.current_source_location()),
|
|
decl,
|
|
);
|
|
|
|
Ok(decl)
|
|
}
|
|
|
|
fn parse_block_inner(
|
|
&mut self,
|
|
block: Index,
|
|
tokens: &mut TokenIterator,
|
|
) -> ParseResult<PlaceOrValue> {
|
|
let loc = tokens.current_source_location();
|
|
let mut statements = Vec::new();
|
|
|
|
let trailing = loop {
|
|
if tokens.is_next_token(Token::CloseBrace) {
|
|
break None;
|
|
}
|
|
let next = tokens.peek_token().ok_or(ErrorInfo {
|
|
error: ParseError::UnexpectedEndOfTokens,
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
|
|
if let Some(decl) = self.parse_constant_decls(tokens)? {
|
|
statements.push(decl);
|
|
} else {
|
|
match next.token() {
|
|
Token::Return => {
|
|
statements.push(self.parse_return_stmt(tokens)?);
|
|
}
|
|
Token::Var | Token::Let => {
|
|
statements.push(self.parse_var_decl(tokens)?);
|
|
}
|
|
_ => {
|
|
if self.is_statement(tokens) {
|
|
// expr -> statements
|
|
let expr = self
|
|
.parse_with_trailing_semi(tokens, |this, tokens| {
|
|
Ok(this.parse_expr(tokens)?.into_index())
|
|
})?;
|
|
|
|
statements.push(expr);
|
|
} else {
|
|
// expr -> trailing
|
|
let expr = self.parse_expr(tokens)?;
|
|
if !tokens.is_next_token(Token::CloseBrace) {
|
|
statements.push(self.push_error(
|
|
ParseError::ExpectedEndOfBlock,
|
|
tokens.current_source_location(),
|
|
));
|
|
} else {
|
|
break Some(expr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
self.ast.set_block(
|
|
block,
|
|
statements,
|
|
trailing.map(PlaceOrValue::into_index),
|
|
loc,
|
|
);
|
|
|
|
let block = trailing
|
|
.map(|pv| pv.with_index(block))
|
|
.unwrap_or(PlaceOrValue::Value(block));
|
|
Ok(block)
|
|
}
|
|
|
|
/// BLOCK <-
|
|
/// { STATEMENT* EXPRESSION? }
|
|
fn parse_block(&mut self, tokens: &mut TokenIterator) -> ParseResult<PlaceOrValue> {
|
|
let block = self.parse_braced(tokens, |this, tokens| {
|
|
let block = this.ast.reserve_node_other();
|
|
this.push_scope(block, intern::Index::invalid());
|
|
let block_result = this.parse_block_inner(block, tokens);
|
|
this.pop_scope();
|
|
|
|
block_result
|
|
})?;
|
|
|
|
Ok(block)
|
|
}
|
|
|
|
/// PARAMETER_LIST <-
|
|
/// PARAMETER
|
|
/// PARAMETER_LIST , ARGUMENT
|
|
fn parse_parameter_list(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
let loc = tokens.current_source_location();
|
|
|
|
let mut params = Vec::new();
|
|
loop {
|
|
params.push(self.parse_parameter(tokens)?);
|
|
|
|
if !tokens.is_next_token(Token::Comma) {
|
|
break;
|
|
}
|
|
if tokens.is_next_token2(Token::CloseParens) {
|
|
break;
|
|
}
|
|
// skip comma
|
|
_ = tokens.next();
|
|
}
|
|
|
|
return Ok(self.ast.push_parameter_list(params, loc));
|
|
}
|
|
|
|
/// PARAMETER <-
|
|
/// IDENT : TYPENAME
|
|
fn parse_parameter(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
let loc = tokens.current_source_location();
|
|
let name = self.parse_ident(tokens)?;
|
|
let Some(_) = tokens.eat_token(Token::Colon) else {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Colon),
|
|
loc,
|
|
});
|
|
};
|
|
let ty = self.parse_type(tokens)?;
|
|
|
|
let param = self.ast.push_parameter(name, ty, loc);
|
|
self.syms
|
|
.insert_symbol(self.current_scope(), name, SymbolKind::Local(loc), param);
|
|
|
|
return Ok(param);
|
|
}
|
|
|
|
/// ARGUMENT <-
|
|
/// IDENT : EXPR
|
|
/// EXPR
|
|
fn parse_argument(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
let loc = tokens.current_source_location();
|
|
let name = if tokens.is_next_token2(Token::Colon) && tokens.is_next_token(Token::Ident)
|
|
{
|
|
let name = self.parse_ident(tokens)?;
|
|
// we checked `is_next_token2`
|
|
_ = tokens.eat_token(Token::Colon).unwrap();
|
|
Some(name)
|
|
} else {
|
|
None
|
|
};
|
|
let expr = self.parse_value_expr(tokens)?;
|
|
|
|
let i = match name {
|
|
Some(name) => self.ast.push_named_argument(name, expr, loc),
|
|
None => self.ast.push_argument(expr, loc),
|
|
};
|
|
|
|
Ok(i)
|
|
}
|
|
|
|
/// ARGUMENT_LIST <-
|
|
/// ARGUMENT
|
|
/// ARGUMENT_LIST , ARGUMENT
|
|
fn parse_argument_list(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
let loc = tokens.current_source_location();
|
|
let mut args = Vec::new();
|
|
loop {
|
|
args.push(self.parse_argument(tokens)?);
|
|
|
|
if !tokens.is_next_token(Token::Comma) {
|
|
break;
|
|
}
|
|
if tokens.is_next_token2(Token::CloseParens) {
|
|
break;
|
|
}
|
|
// skip comma
|
|
_ = tokens.next();
|
|
}
|
|
return Ok(self.ast.push_argument_list(args, loc));
|
|
}
|
|
|
|
/// PRIMARY_EXPR <-
|
|
/// IDENTIFIER
|
|
/// INTEGER_CONSTANT
|
|
/// FLOATING_CONSTANT
|
|
/// ( EXPRESSION )
|
|
/// BLOCK
|
|
fn parse_primary_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<PlaceOrValue> {
|
|
let loc = tokens.current_source_location();
|
|
|
|
let Some(next) = tokens.peek_token() else {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::ExpectedPrimaryExpression,
|
|
loc,
|
|
});
|
|
};
|
|
|
|
match next.token() {
|
|
Token::IntegerBinConstant
|
|
| Token::IntegerHexConstant
|
|
| Token::IntegerOctConstant
|
|
| Token::IntegerConstant => {
|
|
_ = tokens.next();
|
|
return Ok(PlaceOrValue::Value(
|
|
self.parse_integral_constant(&next, next.source_location()),
|
|
));
|
|
}
|
|
Token::FloatingConstant
|
|
| Token::FloatingExpConstant
|
|
| Token::DotFloatingConstant
|
|
| Token::DotFloatingExpConstant => {
|
|
_ = tokens.next();
|
|
return Ok(PlaceOrValue::Value(
|
|
self.parse_floating_constant(&next, next.source_location()),
|
|
));
|
|
}
|
|
|
|
Token::OpenParens => {
|
|
let expr =
|
|
self.parse_parenthesised(tokens, |this, tokens| this.parse_expr(tokens))?;
|
|
|
|
return Ok(expr);
|
|
}
|
|
Token::OpenBrace => {
|
|
return Ok(self.parse_block(tokens)?);
|
|
}
|
|
Token::Ident => {
|
|
_ = tokens.next();
|
|
let ident = next.lexeme();
|
|
let ident = self
|
|
.intern
|
|
.get_or_insert(intern::Key::String { str: ident });
|
|
|
|
return Ok(PlaceOrValue::Place(self.ast.push_decl_ref_unresolved(
|
|
self.current_scope(),
|
|
ident,
|
|
loc,
|
|
)));
|
|
}
|
|
// TODO: eventually handle paths
|
|
_ => {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::ExpectedPrimaryExpression,
|
|
loc,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
/// POSTFIX_EXPR <-
|
|
/// PRIMARY_EXPR
|
|
/// PRIMARY_EXPR ( )
|
|
/// PRIMARY_EXPR ( ARGUMENT_LIST )
|
|
/// PRIMARY_EXPR [ EXPR ]
|
|
/// POSTFIX_EXPR . IDENTIFIER
|
|
fn parse_postfix_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<PlaceOrValue> {
|
|
let mut lhs = self.parse_primary_expr(tokens)?;
|
|
while let Some(postfix) = self.try_parse_postfix_expr_inner(tokens, lhs)? {
|
|
lhs = postfix;
|
|
}
|
|
|
|
Ok(lhs)
|
|
}
|
|
|
|
fn try_parse_postfix_expr_inner(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
lhs: PlaceOrValue,
|
|
) -> ParseResult<Option<PlaceOrValue>> {
|
|
let lhs = if let Some(next) = tokens.peek_token() {
|
|
let loc = next.source_location();
|
|
match next.token() {
|
|
Token::OpenParens => {
|
|
let arguments = self.parse_parenthesised(tokens, |this, tokens| {
|
|
if tokens.is_next_token(Token::CloseParens) {
|
|
Ok(this.ast.push_argument_list([], loc))
|
|
} else {
|
|
this.parse_argument_list(tokens)
|
|
}
|
|
})?;
|
|
let lhs = self.convert_to_value_expr(lhs);
|
|
|
|
Some(PlaceOrValue::Value(
|
|
self.ast.push_call_expr(lhs, arguments, loc),
|
|
))
|
|
}
|
|
Token::OpenSquareBracket => {
|
|
let subscript = self.parse_bracketed(tokens, |this, tokens| {
|
|
this.parse_value_expr(tokens)
|
|
})?;
|
|
|
|
let lhs = self.convert_to_value_expr(lhs);
|
|
|
|
Some(PlaceOrValue::Place(self.ast.push_binary(
|
|
Tag::SubscriptExpr,
|
|
lhs,
|
|
subscript,
|
|
loc,
|
|
)))
|
|
}
|
|
Token::Dot if tokens.is_next_token2(Token::Ident) => {
|
|
_ = tokens.next();
|
|
let loc = tokens.current_source_location();
|
|
let lhs = self.convert_to_place_expr(lhs);
|
|
let name = self.parse_ident(tokens)?;
|
|
|
|
Some(self.ast.push_field_access(lhs, name, loc))
|
|
}
|
|
_ => None,
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
|
|
Ok(lhs)
|
|
}
|
|
|
|
fn push_error(&mut self, error: ParseError, loc: SourceLocation) -> Index {
|
|
self.errors.push(ErrorInfo { error, loc });
|
|
self.ast.push_error(error, loc)
|
|
}
|
|
|
|
/// converts the expression to a value expression, if it isn't one already.
|
|
fn convert_to_value_expr(&mut self, lrvalue: PlaceOrValue) -> Index {
|
|
match lrvalue {
|
|
PlaceOrValue::Value(index) => index,
|
|
PlaceOrValue::Place(index) => self.ast.push_place_to_value_conversion(index),
|
|
}
|
|
}
|
|
|
|
/// converts the expression to a place expression, if it isn't one already.
|
|
fn convert_to_place_expr(&mut self, lrvalue: PlaceOrValue) -> Index {
|
|
match lrvalue {
|
|
PlaceOrValue::Place(index) => index,
|
|
PlaceOrValue::Value(index) => self.ast.push_value_to_place_conversion(index),
|
|
}
|
|
}
|
|
|
|
/// PREFIX_EXPR <-
|
|
/// POSTFIX_EXPR
|
|
/// ! POSTFIX_EXPR
|
|
/// - POSTFIX_EXPR
|
|
/// & POSTFIX_EXPR
|
|
/// * POSTFIX_EXPR
|
|
fn parse_prefix_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<PlaceOrValue> {
|
|
let next = tokens.peek_token().ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedPrefixExpression,
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
|
|
let loc = next.source_location();
|
|
|
|
let expr = match next.token() {
|
|
Token::Bang => {
|
|
_ = tokens.next();
|
|
let lhs = self.parse_prefix_expr(tokens)?;
|
|
let lhs = self.convert_to_value_expr(lhs);
|
|
self.ast.push_unary(Tag::Not, lhs, loc)
|
|
}
|
|
Token::Minus => {
|
|
_ = tokens.next();
|
|
let lhs = self.parse_prefix_expr(tokens)?;
|
|
let lhs = self.convert_to_value_expr(lhs);
|
|
self.ast.push_unary(Tag::Negate, lhs, loc)
|
|
}
|
|
Token::Ampersand => {
|
|
_ = tokens.next();
|
|
// the address-of operator requires lhs to be a place
|
|
// expression. not all expressions that might be the lhs
|
|
// are automatically place expressions: the construct `let a
|
|
// = &3;` has `3`, which is a value expression, as the lhs
|
|
// of the address-of operator.
|
|
let lhs = self.parse_prefix_expr(tokens)?;
|
|
let lhs = self.convert_to_place_expr(lhs);
|
|
self.ast.push_unary(Tag::AddressOf, lhs, loc)
|
|
}
|
|
Token::Star => {
|
|
_ = tokens.next();
|
|
let lhs = self.parse_prefix_expr(tokens)?;
|
|
self.ast.push_unary(Tag::Deref, lhs.into_index(), loc)
|
|
}
|
|
_ => self.parse_postfix_expr(tokens)?,
|
|
};
|
|
|
|
Ok(expr)
|
|
}
|
|
|
|
/// AS_EXPR <-
|
|
/// PREFIX_EXPR
|
|
/// PREFIX_EXPR as TYPENAME
|
|
fn parse_as_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<PlaceOrValue> {
|
|
let loc = tokens.current_source_location();
|
|
let expr = self.parse_prefix_expr(tokens)?;
|
|
|
|
if tokens.eat_token(Token::As).is_some() {
|
|
let typename = self.parse_type(tokens)?;
|
|
let expr = self.convert_to_value_expr(expr);
|
|
|
|
return Ok(PlaceOrValue::Value(self.ast.push_cast(expr, typename, loc)));
|
|
} else {
|
|
return Ok(expr);
|
|
}
|
|
}
|
|
|
|
/// BINARY_EXPR <-
|
|
/// AS_EXPR
|
|
/// AS_EXPR * EXPRESSION
|
|
/// AS_EXPR / EXPRESSION
|
|
/// AS_EXPR % EXPRESSION
|
|
/// AS_EXPR + EXPRESSION
|
|
/// AS_EXPR - EXPRESSION
|
|
/// AS_EXPR << EXPRESSION
|
|
/// AS_EXPR >> EXPRESSION
|
|
/// AS_EXPR < EXPRESSION
|
|
/// AS_EXPR > EXPRESSION
|
|
/// AS_EXPR <= EXPRESSION
|
|
/// AS_EXPR >= EXPRESSION
|
|
/// AS_EXPR == EXPRESSION
|
|
/// AS_EXPR != EXPRESSION
|
|
/// AS_EXPR & EXPRESSION
|
|
/// AS_EXPR ^ EXPRESSION
|
|
/// AS_EXPR | EXPRESSION
|
|
/// AS_EXPR && EXPRESSION
|
|
/// AS_EXPR || EXPRESSION
|
|
fn parse_binary_expr(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
precedence: u32,
|
|
) -> ParseResult<PlaceOrValue> {
|
|
let mut node = self.parse_as_expr(tokens)?;
|
|
|
|
loop {
|
|
let Some(tok) = tokens.peek_token() else {
|
|
break;
|
|
};
|
|
let loc = tok.source_location();
|
|
let Some(prec) = PRECEDENCE_MAP.get(&tok.token()).cloned() else {
|
|
break;
|
|
};
|
|
|
|
if prec < precedence {
|
|
break;
|
|
}
|
|
|
|
// SAFETY: we peeked `tok`
|
|
let tok = tokens.next().unwrap();
|
|
|
|
let lhs = self.convert_to_value_expr(node);
|
|
let rhs = self.parse_binary_expr(tokens, prec + 1)?;
|
|
let rhs = self.convert_to_value_expr(rhs);
|
|
|
|
let tag = match tok.token() {
|
|
Token::PipePipe => Tag::Or,
|
|
Token::AmpersandAmpersand => Tag::And,
|
|
Token::Pipe => Tag::BitOr,
|
|
Token::Caret => Tag::BitXOr,
|
|
Token::Ampersand => Tag::BitAnd,
|
|
Token::BangEqual => Tag::NEq,
|
|
Token::EqualEqual => Tag::Eq,
|
|
Token::LessEqual => Tag::Le,
|
|
Token::GreaterEqual => Tag::Ge,
|
|
Token::Less => Tag::Lt,
|
|
Token::Greater => Tag::Gt,
|
|
Token::GreaterGreater => Tag::Shr,
|
|
Token::LessLess => Tag::Shl,
|
|
Token::Plus => Tag::Add,
|
|
Token::Minus => Tag::Sub,
|
|
Token::Percent => Tag::Rem,
|
|
Token::Star => Tag::Mul,
|
|
Token::Slash => Tag::Div,
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
node = PlaceOrValue::Value(self.ast.push_binary(tag, lhs, rhs, loc));
|
|
}
|
|
|
|
Ok(node)
|
|
}
|
|
|
|
/// ASSIGNMENT_EXPR <-
|
|
/// BINARY_EXPRESSION
|
|
/// BINARY_EXPRESSION ASSIGNMENT_OP EXPRESSION
|
|
/// ASSIGNMENT_OP <-
|
|
/// = += -= *= /= %= ...
|
|
fn parse_assignment_expr(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
) -> ParseResult<PlaceOrValue> {
|
|
let lhs = self.parse_binary_expr(tokens, 0)?;
|
|
|
|
if tokens
|
|
.peek_token()
|
|
.map(|itm| itm.token().is_assignment_op())
|
|
== Some(true)
|
|
{
|
|
// SAFETY: we peeked
|
|
let op = tokens.next().unwrap();
|
|
let loc = op.source_location();
|
|
// rhs (src) must be a value
|
|
let rhs = self.parse_value_expr(tokens)?;
|
|
|
|
let rhs = if op.token() == Token::Equal {
|
|
rhs
|
|
} else {
|
|
let tag = match op.token() {
|
|
Token::PlusEqual => Tag::Add,
|
|
Token::MinusEqual => Tag::Sub,
|
|
Token::StarEqual => Tag::Mul,
|
|
Token::SlashEqual => Tag::Sub,
|
|
Token::PercentEqual => Tag::Rem,
|
|
Token::PipeEqual => Tag::BitOr,
|
|
Token::CaretEqual => Tag::BitXOr,
|
|
Token::AmpersandEqual => Tag::BitAnd,
|
|
Token::LessLessEqual => Tag::Shl,
|
|
Token::GreaterGreaterEqual => Tag::Shr,
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
};
|
|
|
|
// convert lhs (dest) to value
|
|
let lhs = self.convert_to_value_expr(lhs);
|
|
self.ast.push_binary(tag, lhs, rhs, loc)
|
|
};
|
|
|
|
// for the assignment, lhs (dest) must be a place
|
|
// I think this is the only case where the AST is a dag.
|
|
let lhs = self.convert_to_place_expr(lhs);
|
|
// the assignment is a value
|
|
Ok(PlaceOrValue::Value(self.ast.push_assign(lhs, rhs, loc)))
|
|
} else {
|
|
// but if we don't have an assignment, this might be a place
|
|
Ok(lhs)
|
|
}
|
|
}
|
|
|
|
/// ELSE_EXPR <-
|
|
/// 'else' (IF_EXPR | EXPR_OR_STATEMENT_OR_BLOCK)
|
|
fn parse_else_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<PlaceOrValue> {
|
|
// SAFETY: function invariance
|
|
let _else_ = tokens.eat_token(Token::Else).unwrap();
|
|
|
|
if tokens.is_next_token(Token::If) {
|
|
self.parse_if_expr(tokens)
|
|
} else {
|
|
self.parse_expr_or_block_as_block(tokens)
|
|
}
|
|
}
|
|
|
|
/// IF_EXPR <-
|
|
/// 'if' ( EXPR ) EXPR_OR_STATEMENT_OR_BLOCK ELSE_EXPR?
|
|
fn parse_if_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<PlaceOrValue> {
|
|
// SAFETY: function invariance
|
|
let iff = tokens.eat_token(Token::If).unwrap();
|
|
let loc = iff.source_location();
|
|
|
|
let cond =
|
|
self.parse_parenthesised(tokens, |this, tokens| this.parse_value_expr(tokens))?;
|
|
|
|
let body = self.parse_expr_or_block_as_block(tokens)?;
|
|
|
|
if tokens.is_next_token(Token::Else) {
|
|
let else_expr = self.parse_else_expr(tokens)?;
|
|
Ok(body.with_index(self.ast.push_if_else(
|
|
cond,
|
|
body.into_index(),
|
|
else_expr.into_index(),
|
|
loc,
|
|
)))
|
|
} else {
|
|
Ok(body.with_index(self.ast.push_if(cond, body.into_index(), loc)))
|
|
}
|
|
}
|
|
|
|
fn parse_expr_or_block_as_block(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
) -> ParseResult<PlaceOrValue> {
|
|
let Some(next) = tokens.peek_token() else {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::ExpectedExpression,
|
|
loc: tokens.current_source_location(),
|
|
});
|
|
};
|
|
|
|
match next.token() {
|
|
Token::OpenBrace => self.parse_block(tokens),
|
|
_ => {
|
|
let loc = tokens.current_source_location();
|
|
let expr = self.parse_expr(tokens)?;
|
|
Ok(expr.with_index(self.ast.push_block([], Some(expr.into_index()), loc)))
|
|
}
|
|
}
|
|
}
|
|
|
|
fn parse_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<PlaceOrValue> {
|
|
let loc = tokens.current_source_location();
|
|
let Some(next) = tokens.peek_token() else {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::ExpectedExpression,
|
|
loc,
|
|
});
|
|
};
|
|
|
|
let expr = match next.token() {
|
|
Token::If => self.parse_if_expr(tokens)?,
|
|
_ => self.parse_assignment_expr(tokens)?,
|
|
};
|
|
|
|
Ok(expr)
|
|
}
|
|
|
|
fn parse_place_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
// TODO: panic if not place expr
|
|
let expr = self.parse_expr(tokens)?;
|
|
let expr = self.convert_to_place_expr(expr);
|
|
|
|
Ok(expr)
|
|
}
|
|
fn parse_value_expr(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
// TODO: convert from place to value (lvalue-to-rvalue)
|
|
let expr = self.parse_expr(tokens)?;
|
|
let expr = self.convert_to_value_expr(expr);
|
|
|
|
Ok(expr)
|
|
}
|
|
|
|
/// TYPE_DECL <-
|
|
/// type IDENTIFIER = TYPE_UNION ;
|
|
/// type IDENTIFIER = '(' (TYPE,)* ')' ;
|
|
/// type IDENTIFIER = extern? union { (IDENTIFIER: TYPE,)* }
|
|
/// type IDENTIFIER = extern? packed? enum { (IDENTIFIER (= EXPRESSION),)* }
|
|
/// type IDENTIFIER = extern? packed? struct { (IDENTIFIER: TYPE,)* }
|
|
fn parse_type_decl(&mut self, tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
_ = tokens.eat_token(Token::Type).ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Type),
|
|
loc: tokens.current_source_location(),
|
|
});
|
|
|
|
let name = self.parse_ident(tokens)?;
|
|
let loc = tokens.current_source_location();
|
|
|
|
_ = tokens.eat_token(Token::Equal).ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Equal),
|
|
loc: tokens.current_source_location(),
|
|
});
|
|
|
|
let (has_attributes, c_like, packed) = {
|
|
let vec = tokens.eat_all_zero_or_once(&[Token::Extern, Token::Packed]);
|
|
(vec[0] || vec[1], vec[0], vec[1])
|
|
};
|
|
|
|
let Some(next) = tokens.peek_token() else {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::ExpectedTypeDeclaration,
|
|
loc: tokens.current_source_location(),
|
|
});
|
|
};
|
|
|
|
let decl = match next.token() {
|
|
Token::Struct => self.parse_struct_decl(tokens, name, c_like, packed, loc),
|
|
Token::Union => {
|
|
unimplemented!()
|
|
}
|
|
Token::Enum => {
|
|
unimplemented!()
|
|
}
|
|
_ => {
|
|
if has_attributes {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::UnexpectedTypeAttributes,
|
|
loc: tokens.current_source_location(),
|
|
});
|
|
}
|
|
match next.token() {
|
|
Token::OpenParens => {
|
|
// tuple
|
|
unimplemented!()
|
|
}
|
|
Token::Ident => {
|
|
// sumtype
|
|
unimplemented!()
|
|
}
|
|
_ => {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::ExpectedTypeDeclaration,
|
|
loc: tokens.current_source_location(),
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}?;
|
|
|
|
self.syms
|
|
.insert_symbol(self.current_scope(), name, SymbolKind::Type, decl);
|
|
|
|
Ok(decl)
|
|
}
|
|
|
|
/// SUMTYPE_DECL <-
|
|
/// type IDENTIFIER = TYPE_UNION
|
|
/// TYPE_UNION <-
|
|
/// TYPE (| TYPE_UNION)?
|
|
/// IDENTIFIER: TYPE (| TYPE_UNION)?
|
|
fn parse_sumtype_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
todo!()
|
|
}
|
|
|
|
/// TUPLE_DECL <-
|
|
/// type IDENTIFIER = (TYPE,* )
|
|
fn parse_tuple_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
todo!()
|
|
}
|
|
|
|
/// UNION_DECL <-
|
|
/// type IDENTIFIER = union { IDENTIFIER: TYPE,* }
|
|
fn parse_union_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
todo!()
|
|
}
|
|
|
|
/// ENUM_DECL <-
|
|
/// type IDENTIFIER = packed? enum { IDENTIFIER (= EXPRESSION),* }
|
|
fn parse_enum_decl(&mut self, _tokens: &mut TokenIterator) -> ParseResult<Index> {
|
|
todo!()
|
|
}
|
|
|
|
/// STRUCT_DECL <-
|
|
/// type IDENTIFIER = extern? packed? struct { STRUCT_FIELD,* }
|
|
fn parse_struct_decl(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
name: intern::Index,
|
|
c_like: bool,
|
|
packed: bool,
|
|
loc: SourceLocation,
|
|
) -> ParseResult<Index> {
|
|
// SAFETY: function invariance
|
|
|
|
_ = tokens.eat_token(Token::Struct).ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Struct),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
|
|
let decl = self.ast.reserve_node(Kind::GlobalDecl);
|
|
let decl = self.parse_braced(tokens, |this, tokens| {
|
|
this.parse_struct_fields(tokens).map(|fields| {
|
|
_ = tokens.eat_token(Token::Comma);
|
|
let flags = StructFlags::new(packed, c_like, fields.len() as u32);
|
|
|
|
this.intern.insert_or_replace_struct_type(
|
|
name,
|
|
decl,
|
|
flags.packed,
|
|
flags.c_like,
|
|
vec![],
|
|
);
|
|
|
|
this.ast.set_struct_decl(decl, name, flags, fields, loc)
|
|
})
|
|
})?;
|
|
|
|
Ok(decl)
|
|
}
|
|
|
|
fn parse_with_trailing_semi<F, I>(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
parse: F,
|
|
) -> ParseResult<I>
|
|
where
|
|
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<I>,
|
|
Index: Into<I>,
|
|
{
|
|
match parse(self, tokens) {
|
|
Ok(i) => {
|
|
_ = tokens.eat_token(Token::Semi).ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Semi),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
|
|
Ok(i)
|
|
}
|
|
Err(err) => {
|
|
tokens.advance_past_semi().ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Semi),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
Ok(self.push_error(err.error, err.loc).into())
|
|
}
|
|
}
|
|
}
|
|
|
|
fn parse_inner<F, I, E>(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
open: Token,
|
|
close: Token,
|
|
parse: F,
|
|
on_err: E,
|
|
) -> ParseResult<I>
|
|
where
|
|
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<I>,
|
|
E: FnOnce(&mut Self, &mut TokenIterator, ErrorInfo, TokenItem) -> ParseResult<I>,
|
|
{
|
|
let Some(start) = tokens.eat_token(open) else {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::ExpectedToken(open),
|
|
loc: tokens.current_source_location(),
|
|
});
|
|
};
|
|
|
|
match parse(self, tokens) {
|
|
Ok(i) => {
|
|
_ = tokens.eat_token(close).ok_or(ErrorInfo {
|
|
error: match open {
|
|
Token::OpenBrace => ParseError::UnmatchedBrace(start.token_pos().start),
|
|
Token::OpenParens => {
|
|
ParseError::UnmatchedParens(start.token_pos().start)
|
|
}
|
|
Token::OpenSquareBracket => {
|
|
ParseError::UnmatchedSquareBracket(start.token_pos().start)
|
|
}
|
|
_ => ParseError::UnmatchedDelimiter(start.token_pos().start),
|
|
},
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
|
|
Ok(i)
|
|
}
|
|
Err(e) => on_err(self, tokens, e, start),
|
|
}
|
|
}
|
|
|
|
fn parse_inner2<F, I>(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
open: Token,
|
|
close: Token,
|
|
parse: F,
|
|
) -> ParseResult<I>
|
|
where
|
|
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<I>,
|
|
Index: Into<I>,
|
|
// I: From<Index>,
|
|
{
|
|
self.parse_inner(tokens, open, close, parse, |this, tokens, err, start| {
|
|
match close {
|
|
Token::CloseBrace => {
|
|
tokens.advance_past_end_of_braced().ok_or(ErrorInfo {
|
|
error: ParseError::UnmatchedBrace(start.token_pos().start),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
}
|
|
Token::CloseParens => {
|
|
tokens.advance_past_end_of_parens().ok_or(ErrorInfo {
|
|
error: ParseError::UnmatchedParens(start.token_pos().start),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
}
|
|
Token::CloseSquareBracket => {
|
|
tokens.advance_past_end_of_bracketed().ok_or(ErrorInfo {
|
|
error: ParseError::UnmatchedSquareBracket(start.token_pos().start),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
}
|
|
Token::Semi => {
|
|
tokens.advance_past_semi().ok_or(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Semi),
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
}
|
|
_ => unimplemented!(),
|
|
}
|
|
Ok(this.push_error(err.error, err.loc).into())
|
|
})
|
|
}
|
|
|
|
fn parse_bracketed<F, I>(&mut self, tokens: &mut TokenIterator, parse: F) -> ParseResult<I>
|
|
where
|
|
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<I>,
|
|
Index: Into<I>,
|
|
{
|
|
self.parse_inner2(
|
|
tokens,
|
|
Token::OpenSquareBracket,
|
|
Token::CloseSquareBracket,
|
|
parse,
|
|
)
|
|
}
|
|
|
|
fn parse_braced<F, I>(&mut self, tokens: &mut TokenIterator, parse: F) -> ParseResult<I>
|
|
where
|
|
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<I>,
|
|
Index: Into<I>,
|
|
{
|
|
self.parse_inner2(tokens, Token::OpenBrace, Token::CloseBrace, parse)
|
|
}
|
|
|
|
fn parse_parenthesised<F, I>(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
parse: F,
|
|
) -> ParseResult<I>
|
|
where
|
|
F: FnOnce(&mut Self, &mut TokenIterator) -> ParseResult<I>,
|
|
Index: Into<I>,
|
|
{
|
|
self.parse_inner2(tokens, Token::OpenParens, Token::CloseParens, parse)
|
|
}
|
|
|
|
fn parse_struct_fields(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
) -> ParseResult<Vec<(intern::Index, Index)>> {
|
|
let mut fields = Vec::new();
|
|
loop {
|
|
fields.push(self.parse_struct_field(tokens)?);
|
|
|
|
if !tokens.is_next_token(Token::Comma) {
|
|
break;
|
|
}
|
|
if tokens.is_next_token2(Token::CloseBrace) {
|
|
break;
|
|
}
|
|
// skip comma
|
|
_ = tokens.next();
|
|
}
|
|
|
|
Ok(fields)
|
|
}
|
|
|
|
/// STRUCT_FIELD <-
|
|
/// IDENTIFIER: TYPE
|
|
fn parse_struct_field(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
) -> ParseResult<(intern::Index, Index)> {
|
|
let name = self.parse_ident(tokens)?;
|
|
let Some(_) = tokens.eat_token(Token::Colon) else {
|
|
return Err(ErrorInfo {
|
|
error: ParseError::ExpectedToken(Token::Colon),
|
|
loc: tokens.current_source_location(),
|
|
});
|
|
};
|
|
let ty = self.parse_type(tokens)?;
|
|
|
|
return Ok((name, ty));
|
|
}
|
|
|
|
/// CONSTANT_DECL <-
|
|
/// FUNCTION_DECL
|
|
/// GLOBAL_DECL
|
|
/// STRUCT_DECL
|
|
fn parse_constant_decls(
|
|
&mut self,
|
|
tokens: &mut TokenIterator,
|
|
) -> ParseResult<Option<Index>> {
|
|
let next = tokens.peek_token().ok_or(ErrorInfo {
|
|
error: ParseError::UnexpectedEndOfTokens,
|
|
loc: tokens.current_source_location(),
|
|
})?;
|
|
|
|
match next.token() {
|
|
Token::Fn => Ok(Some(self.parse_fn_decl(tokens))),
|
|
Token::Const => self.parse_const_decl(tokens).map(|i| Some(i)),
|
|
Token::Type => self.parse_type_decl(tokens).map(|i| Some(i)),
|
|
_ => Ok(None),
|
|
}
|
|
}
|
|
|
|
/// FILE <-
|
|
/// (FUNCTION_DECL | GLOBAL_DECL)*
|
|
fn parse_file(&mut self, tokens: &mut TokenIterator) -> Index {
|
|
let start = tokens.current_source_location();
|
|
let mut decls = Vec::new();
|
|
let file = self.ast.reserve_node(Kind::File);
|
|
self.push_scope(file, intern::Index::invalid());
|
|
|
|
while let Some(next) = tokens.peek_token() {
|
|
let loc = next.source_location();
|
|
let decl = match self.parse_constant_decls(tokens).and_then(|i| match i {
|
|
Some(i) => Ok(i),
|
|
None => {
|
|
let error = ParseError::UnexpectedTokenAtFileScope;
|
|
let node = self.push_error(error, loc);
|
|
|
|
self.find_next_fn_or_const(tokens);
|
|
|
|
Ok(node)
|
|
}
|
|
}) {
|
|
Ok(i) => i,
|
|
Err(err) => self.push_error(err.error, err.loc),
|
|
};
|
|
decls.push(decl);
|
|
}
|
|
self.pop_scope();
|
|
|
|
self.ast.set_file(file, decls, start);
|
|
file
|
|
}
|
|
|
|
/// FILE <-
|
|
/// (FUNCTION_DECL | GLOBAL_DECL)*
|
|
pub fn parse(&mut self, mut tokens: TokenIterator) {
|
|
let file = self.parse_file(&mut tokens);
|
|
self.ast.set_root([file]);
|
|
eprintln!("resolving decls:");
|
|
self.resolve_decl_refs();
|
|
self.create_comptime_folding_graph(intern::AMD64_POINTER_BITS);
|
|
eprintln!("interning types:");
|
|
self.intern_types();
|
|
self.fold_more_patterns();
|
|
}
|
|
|
|
fn push_scope(&mut self, ast: Index, name: intern::Index) {
|
|
let parent = self.scopes.last().cloned();
|
|
self.scopes.push(ast);
|
|
|
|
if let Some(parent) = parent {
|
|
self.syms.insert_symbol(
|
|
ast,
|
|
intern::Index::invalid(),
|
|
SymbolKind::ParentScope,
|
|
parent,
|
|
);
|
|
}
|
|
self.syms.insert_scope(name, ast);
|
|
}
|
|
|
|
fn pop_scope(&mut self) {
|
|
self.scopes.pop();
|
|
}
|
|
|
|
fn is_statement(&self, tokens: &mut TokenIterator) -> bool {
|
|
let mut tokens = tokens.clone();
|
|
let mut braces = 0;
|
|
let mut parens = 0;
|
|
let mut brackets = 0;
|
|
while let Some(itm) = tokens.next() {
|
|
match itm.token() {
|
|
Token::OpenBrace => {
|
|
braces += 1;
|
|
}
|
|
Token::CloseBrace => {
|
|
braces -= 1;
|
|
}
|
|
Token::OpenParens => {
|
|
parens += 1;
|
|
}
|
|
Token::CloseParens => {
|
|
parens -= 1;
|
|
}
|
|
Token::OpenSquareBracket => {
|
|
brackets += 1;
|
|
}
|
|
Token::CloseSquareBracket => {
|
|
brackets -= 1;
|
|
}
|
|
Token::Semi => {
|
|
if braces == 0 && parens == 0 && brackets == 0 {
|
|
return true;
|
|
}
|
|
}
|
|
_ => {}
|
|
}
|
|
if braces < 0 || parens < 0 || brackets < 0 {
|
|
break;
|
|
}
|
|
}
|
|
false
|
|
}
|
|
|
|
fn find_next_fn_or_const(&mut self, tokens: &mut TokenIterator) -> Option<()> {
|
|
tokens
|
|
.advance_until_before_one_of(&[Token::Const, Token::Fn, Token::Type])
|
|
.map(|_| ())
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Ast {
|
|
fn visit_all_functions_mut<V>(&mut self, visitor: &mut impl AstVisitorTrait) {
|
|
for i in
|
|
(0..self.tags.functions.len()).map(|i| Index::new(Kind::Function, i as u32).unwrap())
|
|
{
|
|
visitor.visit_function_decl(self, i);
|
|
}
|
|
}
|
|
|
|
fn visit_function_mut<F: FnMut(&mut Self)>(&mut self) {}
|
|
}
|
|
|
|
pub trait AstVisitorTrait {
|
|
type Error;
|
|
type Value;
|
|
const UNIMPL: Self::Error;
|
|
|
|
fn visit_function_decl(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_parameter(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_parameter_list(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_block(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_block_trailing_expr(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_block_maybe_trailing(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
use visitor::AstExt;
|
|
match ast.get_node_tag_and_data(idx).0 {
|
|
Tag::BlockTrailingExpr => self.visit_block(ast, idx),
|
|
Tag::Block => self.visit_block_trailing_expr(ast, idx),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
fn visit_function_proto(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_call_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_add_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_sub_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_mul_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_div_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_rem_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_eq_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_neq_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_lt_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_gt_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_le_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_ge_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_shl_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_shr_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_bitor_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_bitxor_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_bitand_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_or_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_and_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_not_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_negate_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_deref_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_address_of_expr(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_explicit_cast_expr(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_assign(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_subscript_expr(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_if_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_if_else_expr(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_argument(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
|
|
fn visit_any_argument(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
use visitor::AstExt;
|
|
match ast.get_node_tag_and_data(idx).0 {
|
|
Tag::Argument => self.visit_argument(ast, idx),
|
|
Tag::NamedArgument => self.visit_named_argument(ast, idx),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
|
|
fn visit_named_argument(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
|
|
fn visit_argument_list(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
|
|
fn visit_constant(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
|
|
fn visit_return(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_return_expr(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_global_decl(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_var_decl(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_mut_var_decl(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_var_assign_decl(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_mut_var_assign_decl(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_decl_ref(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
Err(Self::UNIMPL)
|
|
}
|
|
fn visit_value_to_place_conversion(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let idx = ast
|
|
.get_node_data_for_tag(idx, Tag::ValueToPlaceConversion)
|
|
.unwrap()
|
|
.as_index();
|
|
self.visit_any(ast, idx)
|
|
}
|
|
fn visit_place_to_value_conversion(
|
|
&mut self,
|
|
ast: &mut Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let idx = ast
|
|
.get_node_data_for_tag(idx, Tag::PlaceToValueConversion)
|
|
.unwrap()
|
|
.as_index();
|
|
self.visit_any(ast, idx)
|
|
}
|
|
|
|
fn visit_any(&mut self, ast: &mut Ast, idx: Index) -> Result<Self::Value, Self::Error> {
|
|
use visitor::AstExt;
|
|
match ast.get_node_tag_and_data(idx).0 {
|
|
Tag::FunctionProto => self.visit_function_proto(ast, idx),
|
|
Tag::FunctionDecl => self.visit_function_decl(ast, idx),
|
|
Tag::ParameterList => self.visit_parameter_list(ast, idx),
|
|
Tag::Parameter => self.visit_parameter(ast, idx),
|
|
Tag::Block => self.visit_block(ast, idx),
|
|
Tag::BlockTrailingExpr => self.visit_block_trailing_expr(ast, idx),
|
|
Tag::Constant => self.visit_constant(ast, idx),
|
|
Tag::ExprStmt => todo!(),
|
|
Tag::ReturnStmt => self.visit_return(ast, idx),
|
|
Tag::ReturnExprStmt => self.visit_return_expr(ast, idx),
|
|
Tag::VarDecl => self.visit_var_decl(ast, idx),
|
|
Tag::MutVarDecl => self.visit_mut_var_decl(ast, idx),
|
|
Tag::VarDeclAssignment => self.visit_var_assign_decl(ast, idx),
|
|
Tag::MutVarDeclAssignment => self.visit_mut_var_assign_decl(ast, idx),
|
|
Tag::GlobalDecl => self.visit_global_decl(ast, idx),
|
|
Tag::StructDecl => todo!(),
|
|
Tag::FieldDecl => todo!(),
|
|
Tag::DeclRef => self.visit_decl_ref(ast, idx),
|
|
Tag::DeclRefUnresolved => todo!(),
|
|
Tag::InternedType => todo!(),
|
|
Tag::TypeDeclRef => todo!(),
|
|
Tag::TypeDeclRefUnresolved => todo!(),
|
|
Tag::PointerType => todo!(),
|
|
Tag::ArrayType => todo!(),
|
|
Tag::CallExpr => self.visit_call_expr(ast, idx),
|
|
Tag::FieldAccess => todo!(),
|
|
Tag::ArgumentList => self.visit_argument_list(ast, idx),
|
|
Tag::Argument => self.visit_argument(ast, idx),
|
|
Tag::NamedArgument => self.visit_named_argument(ast, idx),
|
|
Tag::ExplicitCast => self.visit_explicit_cast_expr(ast, idx),
|
|
Tag::Deref => self.visit_deref_expr(ast, idx),
|
|
Tag::AddressOf => self.visit_add_expr(ast, idx),
|
|
Tag::Not => self.visit_not_expr(ast, idx),
|
|
Tag::Negate => self.visit_negate_expr(ast, idx),
|
|
Tag::Or => self.visit_or_expr(ast, idx),
|
|
Tag::And => self.visit_and_expr(ast, idx),
|
|
Tag::BitOr => self.visit_bitor_expr(ast, idx),
|
|
Tag::BitXOr => self.visit_bitxor_expr(ast, idx),
|
|
Tag::BitAnd => self.visit_bitand_expr(ast, idx),
|
|
Tag::Eq => self.visit_eq_expr(ast, idx),
|
|
Tag::NEq => self.visit_neq_expr(ast, idx),
|
|
Tag::Lt => self.visit_lt_expr(ast, idx),
|
|
Tag::Gt => self.visit_gt_expr(ast, idx),
|
|
Tag::Le => self.visit_le_expr(ast, idx),
|
|
Tag::Ge => self.visit_ge_expr(ast, idx),
|
|
Tag::Shl => self.visit_shl_expr(ast, idx),
|
|
Tag::Shr => self.visit_shr_expr(ast, idx),
|
|
Tag::Add => self.visit_add_expr(ast, idx),
|
|
Tag::Sub => self.visit_sub_expr(ast, idx),
|
|
Tag::Mul => self.visit_mul_expr(ast, idx),
|
|
Tag::Div => self.visit_div_expr(ast, idx),
|
|
Tag::Rem => self.visit_rem_expr(ast, idx),
|
|
Tag::Assign => self.visit_assign(ast, idx),
|
|
Tag::SubscriptExpr => self.visit_subscript_expr(ast, idx),
|
|
Tag::IfExpr => self.visit_if_expr(ast, idx),
|
|
Tag::IfElseExpr => self.visit_if_else_expr(ast, idx),
|
|
Tag::PlaceToValueConversion => self.visit_place_to_value_conversion(ast, idx),
|
|
Tag::ValueToPlaceConversion => self.visit_value_to_place_conversion(ast, idx),
|
|
Tag::Error => todo!(),
|
|
Tag::Undefined => todo!(),
|
|
Tag::Root => todo!(),
|
|
Tag::File => todo!(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Ast {
|
|
fn get_node_data_for_tag(&self, idx: Index, tag: Tag) -> Option<Data> {
|
|
use visitor::AstExt;
|
|
let (t, data) = self.get_node_tag_and_data(idx);
|
|
if t == tag {
|
|
Some(data)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
fn expect_node_data_for_tag(&self, idx: Index, tag: Tag) -> Data {
|
|
self.get_node_data_for_tag(idx, tag)
|
|
.expect(&format!("node {idx} is not a {tag:?}"))
|
|
}
|
|
}
|
|
|
|
pub mod ir {
|
|
use std::collections::HashMap;
|
|
|
|
use crate::{
|
|
ast2::{
|
|
intern::{self, AMD64_POINTER_TYPE_INFO},
|
|
Index,
|
|
},
|
|
triples::{self, Inst, IR},
|
|
};
|
|
|
|
#[derive(Debug, thiserror::Error)]
|
|
enum Error {
|
|
#[error("This visitor does not implement visiting this tag.")]
|
|
Unimplemented,
|
|
}
|
|
|
|
use super::{intern::InternPool, visitor::AstExt, AstVisitorTrait, TypeCache};
|
|
|
|
struct IrBuilder {
|
|
functions: Vec<Function>,
|
|
}
|
|
|
|
struct Function {
|
|
ir: IR,
|
|
}
|
|
|
|
struct IrFunctionBuilder<'a> {
|
|
ir: &'a mut IR,
|
|
type_cache: &'a mut TypeCache,
|
|
ref_lookup: &'a mut HashMap<Index, u32>,
|
|
ip: &'a InternPool,
|
|
function: Function,
|
|
}
|
|
|
|
impl<'a> AstVisitorTrait for IrFunctionBuilder<'a> {
|
|
type Error = Error;
|
|
type Value = Option<u32>;
|
|
const UNIMPL: Self::Error = Error::Unimplemented;
|
|
|
|
fn visit_block(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: super::Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::Block);
|
|
let (a, b) = data.as_extra_range();
|
|
|
|
ast.extra[a..b]
|
|
.to_vec()
|
|
.into_iter()
|
|
.map(|i| Index::from_u32(i).unwrap())
|
|
.map(|i| self.visit_any(ast, i))
|
|
.try_fold((), |_, e| e.map(crate::unit))?;
|
|
|
|
Ok(None)
|
|
}
|
|
|
|
fn visit_place_to_value_conversion(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::PlaceToValueConversion);
|
|
let expr = data.as_index();
|
|
|
|
// idx's (this) type is the pointee type
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
|
|
|
|
let expr = self.visit_any(ast, expr)?.unwrap();
|
|
|
|
let ir = self.ir.push(Inst::Load(ty), Some(triples::Data::lhs(expr)));
|
|
Ok(Some(ir))
|
|
}
|
|
|
|
fn visit_value_to_place_conversion(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::ValueToPlaceConversion);
|
|
let expr = data.as_index();
|
|
|
|
// expr's type is the pointee type
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
|
|
|
|
let expr = self.visit_any(ast, expr)?.unwrap();
|
|
|
|
let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO);
|
|
|
|
let alloca = self.ir.push(
|
|
Inst::Alloca,
|
|
Some(triples::Data::new(info.size(), info.align())),
|
|
);
|
|
|
|
_ = self
|
|
.ir
|
|
.push(Inst::Store(ty), Some(triples::Data::new(expr, alloca)));
|
|
|
|
Ok(Some(alloca))
|
|
}
|
|
|
|
fn visit_decl_ref(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::DeclRef);
|
|
let decl = data.as_index();
|
|
|
|
let alloca = self.ref_lookup.get(&decl).cloned().expect("declref");
|
|
|
|
Ok(Some(alloca))
|
|
}
|
|
|
|
fn visit_var_decl(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_var_decl_common(ast, idx)
|
|
}
|
|
|
|
fn visit_mut_var_decl(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_var_decl_common(ast, idx)
|
|
}
|
|
|
|
fn visit_var_assign_decl(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_var_decl_common(ast, idx)
|
|
}
|
|
|
|
fn visit_mut_var_assign_decl(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_var_decl_common(ast, idx)
|
|
}
|
|
|
|
fn visit_return(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
_ = (ast, idx);
|
|
|
|
let ir = self.ir.push(Inst::Return, None);
|
|
Ok(Some(ir))
|
|
}
|
|
fn visit_return_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::ReturnExprStmt);
|
|
let expr = data.as_index();
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
|
|
|
|
let expr = self.visit_any(ast, expr)?.unwrap();
|
|
|
|
let ir = self
|
|
.ir
|
|
.push(Inst::ReturnValue(ty), Some(triples::Data::lhs(expr)));
|
|
Ok(Some(ir))
|
|
}
|
|
|
|
fn visit_constant(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::Constant);
|
|
let (ty, value) = data.as_index_intern();
|
|
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty);
|
|
let ir = self.ir.push(Inst::Constant, Some((ty, value).into()));
|
|
|
|
Ok(Some(ir))
|
|
}
|
|
|
|
fn visit_subscript_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::SubscriptExpr);
|
|
let (lhs, index) = data.as_two_indices();
|
|
|
|
// pointer type
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
|
|
|
|
let lhs = self.visit_any(ast, lhs)?.unwrap();
|
|
let index = self.visit_any(ast, index)?.unwrap();
|
|
|
|
// TODO: make getelementptr take a variable instead of a constant index.
|
|
let ir = self.ir.push(
|
|
Inst::GetElementPtr(ty),
|
|
Some(triples::Data::new(lhs, index)),
|
|
);
|
|
|
|
Ok(Some(ir))
|
|
}
|
|
|
|
fn visit_call_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::CallExpr);
|
|
let (func, arguments) = data.as_two_indices();
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
|
|
|
|
let len = self.visit_parameter_list(ast, arguments)?.unwrap();
|
|
_ = self.ir.push(Inst::InlineType(ty), None);
|
|
let end = self.ir.nodes.len() as u32;
|
|
|
|
let func = self.visit_any(ast, func)?.unwrap();
|
|
|
|
let result = self
|
|
.ir
|
|
.push(Inst::Call(func), Some(triples::Data::new(end - len, end)));
|
|
|
|
Ok(Some(result))
|
|
}
|
|
|
|
fn visit_argument(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::Argument);
|
|
let expr = data.as_index();
|
|
|
|
let arg = self.visit_any(ast, expr)?.unwrap();
|
|
|
|
// let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
|
|
// self.ir.push(Inst::Argument(ty), Some(triples::Data::lhs(arg)));
|
|
|
|
Ok(Some(arg))
|
|
}
|
|
|
|
// fn visit_named_argument(
|
|
// &mut self,
|
|
// ast: &mut super::Ast,
|
|
// idx: Index,
|
|
// ) -> Result<Self::Value, Self::Error> {
|
|
// todo!()
|
|
// }
|
|
|
|
fn visit_argument_list(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::ArgumentList);
|
|
let (a, b) = data.as_extra_range();
|
|
|
|
let args = ast.extra[a..b]
|
|
.to_vec()
|
|
.into_iter()
|
|
.map(|i| Index::from_u32(i).unwrap())
|
|
.map(|i| {
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, i);
|
|
let arg = self.visit_any_argument(ast, i)?.unwrap();
|
|
Ok((ty, arg))
|
|
})
|
|
.collect::<Result<Vec<_>, _>>()?;
|
|
let count = args.len();
|
|
for (ty, arg) in args {
|
|
_ = self
|
|
.ir
|
|
.push(Inst::Argument(ty), Some(triples::Data::lhs(arg)));
|
|
}
|
|
// .try_fold((), |_, e| e.map(crate::unit))?;
|
|
|
|
Ok(Some(count as u32))
|
|
}
|
|
|
|
fn visit_block_trailing_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::BlockTrailingExpr);
|
|
|
|
let (a, b) = data.as_extra_range();
|
|
|
|
let expr = ast.extra[a..b]
|
|
.to_vec()
|
|
.into_iter()
|
|
.map(|i| Index::from_u32(i).unwrap())
|
|
.map(|i| self.visit_any(ast, i))
|
|
// the last node is the trailing
|
|
.try_fold(None, |_, e| e)?;
|
|
|
|
Ok(expr)
|
|
}
|
|
|
|
fn visit_function_proto(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: super::Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::FunctionProto);
|
|
|
|
let (_, extra) = data.as_intern_and_extra_offset();
|
|
let (_return_type, parameter_list) = (
|
|
Index::from_u32(ast.extra[extra]).unwrap(),
|
|
Index::from_u32(ast.extra[extra + 1]).unwrap(),
|
|
);
|
|
|
|
self.visit_parameter_list(ast, parameter_list)?;
|
|
// push parameters to ir
|
|
Ok(None)
|
|
}
|
|
|
|
fn visit_parameter_list(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::ParameterList);
|
|
let (a, b) = data.as_extra_range();
|
|
|
|
ast.extra[a..b]
|
|
.to_vec()
|
|
.into_iter()
|
|
.map(|i| Index::from_u32(i).unwrap())
|
|
.map(|i| self.visit_parameter(ast, i))
|
|
.try_fold((), |_, e| e.map(crate::unit))?;
|
|
|
|
Ok(None)
|
|
}
|
|
|
|
fn visit_parameter(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::Parameter);
|
|
let (ty, _name) = data.as_index_intern();
|
|
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty);
|
|
let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO);
|
|
let ir = self.ir.push(
|
|
Inst::Parameter(ty),
|
|
Some(triples::Data::new(info.size(), info.align())),
|
|
);
|
|
self.ref_lookup.insert(idx, ir);
|
|
|
|
Ok(None)
|
|
}
|
|
|
|
fn visit_address_of_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::AddressOf);
|
|
let expr = data.as_index();
|
|
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
|
|
let expr = self.visit_any(ast, expr)?.unwrap();
|
|
let r = self
|
|
.ir
|
|
.push(Inst::GetElementPtr(ty), Some(triples::Data::new(expr, 0)));
|
|
|
|
Ok(Some(r))
|
|
}
|
|
|
|
fn visit_assign(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::Assign);
|
|
let (dst, src) = data.as_two_indices();
|
|
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
|
|
let dst = self.visit_any(ast, dst)?.unwrap();
|
|
let src = self.visit_any(ast, src)?.unwrap();
|
|
|
|
let ir = self
|
|
.ir
|
|
.push(Inst::Store(ty.into()), Some(triples::Data::new(src, dst)));
|
|
|
|
Ok(Some(ir))
|
|
}
|
|
|
|
fn visit_explicit_cast_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::ExplicitCast);
|
|
let (lhs, ty) = data.as_two_indices();
|
|
|
|
let lty = ast.get_type_of_node(&self.ip, &mut self.type_cache, lhs);
|
|
let rty = ast.get_type_of_node(&self.ip, &mut self.type_cache, ty);
|
|
|
|
let lhs = self.visit_any(ast, lhs)?.unwrap();
|
|
|
|
// TODO: if bitwidth is the same, then this is a noop?
|
|
let cast = self
|
|
.ir
|
|
.push(Inst::ExplicitCast(lty, rty), Some(triples::Data::lhs(lhs)));
|
|
|
|
Ok(Some(cast))
|
|
}
|
|
|
|
fn visit_if_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::IfExpr);
|
|
let (cond, body) = data.as_two_indices();
|
|
|
|
let cond = self.visit_any(ast, cond)?.unwrap();
|
|
let br = self.ir.push(Inst::Branch(cond), None);
|
|
|
|
let lbody = self
|
|
.ir
|
|
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
|
|
_ = self.visit_any(ast, body);
|
|
let jmp = self.ir.push(Inst::Jump, None);
|
|
let skip = self
|
|
.ir
|
|
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
|
|
|
|
self.ir.data[br as usize] = Some(triples::Data::new(lbody, skip));
|
|
self.ir.data[jmp as usize] = Some(triples::Data::lhs(skip));
|
|
|
|
Ok(Some(br))
|
|
}
|
|
|
|
fn visit_if_else_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::IfElseExpr);
|
|
let (cond, extra) = data.as_index_and_extra_offset();
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
|
|
|
|
let [a, b] = ast.extra[extra..][..2] else {
|
|
unreachable!()
|
|
};
|
|
|
|
let cond = self.visit_any(ast, cond)?.unwrap();
|
|
let br = self.ir.push(Inst::Branch(cond), None);
|
|
|
|
let la = self
|
|
.ir
|
|
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
|
|
let a = self.visit_any(ast, Index::from_u32(a).unwrap())?.unwrap();
|
|
let jmpa = self.ir.push(Inst::Jump, None);
|
|
|
|
let lb = self
|
|
.ir
|
|
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
|
|
let b = self.visit_any(ast, Index::from_u32(b).unwrap())?.unwrap();
|
|
let jmpb = self.ir.push(Inst::Jump, None);
|
|
|
|
let lphi = self
|
|
.ir
|
|
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
|
|
|
|
let phi = if ty == intern::Index::VOID {
|
|
br
|
|
} else {
|
|
self.ir.push(Inst::Phi2(ty), Some(triples::Data::new(a, b)))
|
|
};
|
|
|
|
self.ir.data[br as usize] = Some(triples::Data::new(la, lb));
|
|
self.ir.data[jmpa as usize] = Some(triples::Data::lhs(lphi));
|
|
self.ir.data[jmpb as usize] = Some(triples::Data::lhs(lphi));
|
|
|
|
Ok(Some(phi))
|
|
}
|
|
|
|
fn visit_deref_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::Not);
|
|
let expr = data.as_index();
|
|
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
|
|
let expr = self.visit_any(ast, expr)?.unwrap();
|
|
let not = self.ir.push(Inst::Load(ty), Some(triples::Data::lhs(expr)));
|
|
|
|
Ok(Some(not))
|
|
}
|
|
|
|
fn visit_not_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::Not);
|
|
let expr = data.as_index();
|
|
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
|
|
let expr = self.visit_any(ast, expr)?.unwrap();
|
|
let not = self.ir.push(Inst::Not(ty), Some(triples::Data::lhs(expr)));
|
|
|
|
Ok(Some(not))
|
|
}
|
|
|
|
fn visit_negate_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::Negate);
|
|
let expr = data.as_index();
|
|
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, expr);
|
|
let expr = self.visit_any(ast, expr)?.unwrap();
|
|
let not = self
|
|
.ir
|
|
.push(Inst::Negate(ty), Some(triples::Data::lhs(expr)));
|
|
|
|
Ok(Some(not))
|
|
}
|
|
|
|
fn visit_or_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::Or);
|
|
let (a, b) = data.as_two_indices();
|
|
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
|
|
|
|
// TODO: make this an error instead of a panic
|
|
let a = self.visit_any(ast, a)?.unwrap();
|
|
let not_a = self.ir.push(Inst::Not(ty), Some(triples::Data::lhs(a)));
|
|
|
|
// branch taken if a
|
|
let br = self.ir.push(Inst::Branch(not_a), None);
|
|
let lb = self
|
|
.ir
|
|
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
|
|
|
|
let b = self.visit_any(ast, b)?.unwrap();
|
|
let jmp = self.ir.push(Inst::Jump, None);
|
|
|
|
let la = self
|
|
.ir
|
|
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
|
|
|
|
self.ir.data[br as usize] = Some(triples::Data::new(lb, la));
|
|
self.ir.data[jmp as usize] = Some(triples::Data::lhs(la));
|
|
|
|
let or = self.ir.push(
|
|
Inst::Phi2(intern::Index::BOOL),
|
|
Some(triples::Data::new(a, b)),
|
|
);
|
|
|
|
Ok(Some(or))
|
|
}
|
|
|
|
fn visit_and_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::Or);
|
|
let (a, b) = data.as_two_indices();
|
|
|
|
// TODO: make this an error instead of a panic
|
|
let a = self.visit_any(ast, a)?.unwrap();
|
|
|
|
// branch taken if a
|
|
let br = self.ir.push(Inst::Branch(a), None);
|
|
|
|
let lb = self
|
|
.ir
|
|
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
|
|
let b = self.visit_any(ast, b)?.unwrap();
|
|
|
|
let skip = self
|
|
.ir
|
|
.push(Inst::Label, Some(intern::Index::EMPTY_STRING.into()));
|
|
|
|
self.ir.data[br as usize] = Some(triples::Data::new(lb, skip));
|
|
let and = self.ir.push(
|
|
Inst::Phi2(intern::Index::BOOL),
|
|
Some(triples::Data::new(a, b)),
|
|
);
|
|
|
|
Ok(Some(and))
|
|
}
|
|
|
|
fn visit_add_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_sub_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_div_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_rem_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_mul_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_bitand_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_bitor_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_bitxor_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_eq_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_neq_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_lt_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_gt_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_le_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_ge_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_shl_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
fn visit_shr_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Self::Value, Self::Error> {
|
|
self.visit_binop_expr(ast, idx)
|
|
}
|
|
}
|
|
|
|
impl IrFunctionBuilder<'_> {
|
|
fn visit_var_decl_common(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Option<u32>, Error> {
|
|
let (tag, data) = ast.get_node_tag_and_data(idx);
|
|
let (a, b) = data.as_extra_range();
|
|
|
|
let range = &ast.extra[a..b];
|
|
let _name = range.get(0).unwrap();
|
|
|
|
let (expr, typed_index) = match tag {
|
|
super::Tag::VarDecl | super::Tag::MutVarDecl => {
|
|
let typed_index = range
|
|
.get(1)
|
|
.cloned()
|
|
.map(Index::from_u32)
|
|
.flatten()
|
|
.unwrap();
|
|
(None, typed_index)
|
|
}
|
|
super::Tag::VarDeclAssignment | super::Tag::MutVarDeclAssignment => {
|
|
let expr = range
|
|
.get(1)
|
|
.cloned()
|
|
.map(Index::from_u32)
|
|
.flatten()
|
|
.unwrap();
|
|
let typed_index = range
|
|
.get(2)
|
|
.cloned()
|
|
.map(Index::from_u32)
|
|
.flatten()
|
|
.unwrap_or(expr);
|
|
(Some(expr), typed_index)
|
|
}
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, typed_index);
|
|
let info = self.ip.size_of_type(ty, AMD64_POINTER_TYPE_INFO);
|
|
|
|
let alloca = self.ir.push(
|
|
Inst::Alloca,
|
|
Some(triples::Data::new(info.size(), info.align())),
|
|
);
|
|
|
|
if let Some(idx) = expr {
|
|
let expr = self.visit_any(ast, idx)?.unwrap();
|
|
_ = self
|
|
.ir
|
|
.push(Inst::Store(ty), Some(triples::Data::new(expr, alloca)));
|
|
}
|
|
|
|
self.ref_lookup.insert(idx, alloca);
|
|
|
|
Ok(Some(alloca))
|
|
}
|
|
|
|
/// handles all binary operations that don't short circuit and visit
|
|
/// both lhs and rhs.
|
|
fn visit_binop_expr(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: Index,
|
|
) -> Result<Option<u32>, Error> {
|
|
use triples::Data;
|
|
let (tag, data) = ast.get_node_tag_and_data(idx);
|
|
let (lhs, rhs) = data.as_two_indices();
|
|
|
|
let ty = ast.get_type_of_node(&self.ip, &mut self.type_cache, idx);
|
|
|
|
// TODO: make this an error instead of a panic
|
|
let lhs = self.visit_any(ast, lhs)?.unwrap();
|
|
let rhs = self.visit_any(ast, rhs)?.unwrap();
|
|
|
|
let (inst, data) = match tag {
|
|
super::Tag::BitOr => (Inst::BitOr(ty), Data::new(lhs, rhs)),
|
|
super::Tag::BitXOr => (Inst::BitOr(ty), Data::new(lhs, rhs)),
|
|
super::Tag::BitAnd => (Inst::BitOr(ty), Data::new(lhs, rhs)),
|
|
|
|
super::Tag::Eq => (Inst::Eq(ty), Data::new(lhs, rhs)),
|
|
super::Tag::NEq => (Inst::Neq(ty), Data::new(lhs, rhs)),
|
|
super::Tag::Lt => (Inst::Lt(ty), Data::new(lhs, rhs)),
|
|
super::Tag::Gt => (Inst::Gt(ty), Data::new(lhs, rhs)),
|
|
super::Tag::Le => (Inst::Le(ty), Data::new(lhs, rhs)),
|
|
super::Tag::Ge => (Inst::Ge(ty), Data::new(lhs, rhs)),
|
|
|
|
super::Tag::Shl => (Inst::ShiftLeft(ty), Data::new(lhs, rhs)),
|
|
super::Tag::Shr => (Inst::ShiftRight(ty), Data::new(lhs, rhs)),
|
|
super::Tag::Add => (Inst::Add(ty), Data::new(lhs, rhs)),
|
|
super::Tag::Sub => (Inst::Sub(ty), Data::new(lhs, rhs)),
|
|
super::Tag::Div => (Inst::Div(ty), Data::new(lhs, rhs)),
|
|
super::Tag::Rem => (Inst::Rem(ty), Data::new(lhs, rhs)),
|
|
super::Tag::Mul => (Inst::Mul(ty), Data::new(lhs, rhs)),
|
|
_ => panic!("not a binop"),
|
|
};
|
|
|
|
Ok(Some(self.ir.push(inst, Some(data))))
|
|
}
|
|
}
|
|
|
|
impl AstVisitorTrait for IrBuilder {
|
|
type Value = ();
|
|
type Error = Error;
|
|
const UNIMPL: Self::Error = Error::Unimplemented;
|
|
|
|
fn visit_function_decl(
|
|
&mut self,
|
|
ast: &mut super::Ast,
|
|
idx: super::Index,
|
|
) -> Result<(), Self::Error> {
|
|
let data = ast.expect_node_data_for_tag(idx, super::Tag::FunctionDecl);
|
|
let (proto, block) = data.as_two_indices();
|
|
|
|
// visit proto
|
|
|
|
// visit block
|
|
|
|
todo!()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub mod irgen {
|
|
|
|
use super::*;
|
|
use crate::{symbol_table::syms2::Symbols, triples::*};
|
|
use std::collections::HashMap;
|
|
|
|
struct IRGen {
|
|
ast: Ast,
|
|
syms: Symbols,
|
|
ir: IR,
|
|
ip: intern::InternPool,
|
|
}
|
|
|
|
impl IRGen {
|
|
fn build(&mut self) {
|
|
let mut mapping = HashMap::<Index, u32>::new();
|
|
self.ast.visitor().visit(
|
|
|ast, scopes, i, tag, data| {
|
|
_ = (&mapping, ast, scopes, i, tag, data);
|
|
// pre
|
|
match tag {
|
|
Tag::Root => todo!(),
|
|
Tag::File => todo!(),
|
|
Tag::FunctionProto => todo!(),
|
|
Tag::FunctionDecl => todo!(),
|
|
Tag::ParameterList => todo!(),
|
|
Tag::Parameter => todo!(),
|
|
Tag::Block => todo!(),
|
|
Tag::BlockTrailingExpr => todo!(),
|
|
Tag::Constant => todo!(),
|
|
Tag::ExprStmt => todo!(),
|
|
Tag::ReturnStmt => todo!(),
|
|
Tag::ReturnExprStmt => todo!(),
|
|
Tag::VarDecl => todo!(),
|
|
Tag::MutVarDecl => todo!(),
|
|
Tag::VarDeclAssignment => todo!(),
|
|
Tag::MutVarDeclAssignment => todo!(),
|
|
Tag::GlobalDecl => todo!(),
|
|
Tag::StructDecl => todo!(),
|
|
Tag::FieldDecl => todo!(),
|
|
Tag::DeclRef => todo!(),
|
|
Tag::DeclRefUnresolved => todo!(),
|
|
Tag::InternedType => todo!(),
|
|
Tag::TypeDeclRef => todo!(),
|
|
Tag::TypeDeclRefUnresolved => todo!(),
|
|
Tag::PointerType => todo!(),
|
|
Tag::ArrayType => todo!(),
|
|
Tag::CallExpr => todo!(),
|
|
Tag::FieldAccess => todo!(),
|
|
Tag::ArgumentList => todo!(),
|
|
Tag::Argument => todo!(),
|
|
Tag::NamedArgument => todo!(),
|
|
Tag::ExplicitCast => todo!(),
|
|
Tag::Deref => todo!(),
|
|
Tag::AddressOf => todo!(),
|
|
Tag::Not => todo!(),
|
|
Tag::Negate => todo!(),
|
|
Tag::Or => todo!(),
|
|
Tag::And => todo!(),
|
|
Tag::BitOr => todo!(),
|
|
Tag::BitXOr => todo!(),
|
|
Tag::BitAnd => todo!(),
|
|
Tag::Eq => todo!(),
|
|
Tag::NEq => todo!(),
|
|
Tag::Lt => todo!(),
|
|
Tag::Gt => todo!(),
|
|
Tag::Le => todo!(),
|
|
Tag::Ge => todo!(),
|
|
Tag::Shl => todo!(),
|
|
Tag::Shr => todo!(),
|
|
Tag::Add => todo!(),
|
|
Tag::Sub => todo!(),
|
|
Tag::Mul => todo!(),
|
|
Tag::Div => todo!(),
|
|
Tag::Rem => todo!(),
|
|
Tag::Assign => todo!(),
|
|
Tag::SubscriptExpr => todo!(),
|
|
Tag::IfExpr => todo!(),
|
|
Tag::IfElseExpr => todo!(),
|
|
Tag::Error => todo!(),
|
|
Tag::Undefined => todo!(),
|
|
Tag::PlaceToValueConversion => todo!(),
|
|
Tag::ValueToPlaceConversion => todo!(),
|
|
}
|
|
},
|
|
|ast, scopes, i, tag, data| {
|
|
_ = (&mapping, ast, scopes, i, tag, data);
|
|
// post
|
|
match tag {
|
|
Tag::Root => todo!(),
|
|
Tag::File => todo!(),
|
|
Tag::FunctionProto => todo!(),
|
|
Tag::FunctionDecl => {
|
|
todo!()
|
|
}
|
|
Tag::ParameterList => todo!(),
|
|
Tag::Parameter => todo!(),
|
|
Tag::Block => todo!(),
|
|
Tag::BlockTrailingExpr => todo!(),
|
|
Tag::Constant => todo!(),
|
|
Tag::ExprStmt => todo!(),
|
|
Tag::ReturnStmt => todo!(),
|
|
Tag::ReturnExprStmt => todo!(),
|
|
Tag::VarDecl => todo!(),
|
|
Tag::MutVarDecl => todo!(),
|
|
Tag::VarDeclAssignment => todo!(),
|
|
Tag::MutVarDeclAssignment => todo!(),
|
|
Tag::GlobalDecl => todo!(),
|
|
Tag::StructDecl => todo!(),
|
|
Tag::FieldDecl => todo!(),
|
|
Tag::DeclRef => todo!(),
|
|
Tag::DeclRefUnresolved => todo!(),
|
|
Tag::InternedType => todo!(),
|
|
Tag::TypeDeclRef => todo!(),
|
|
Tag::TypeDeclRefUnresolved => todo!(),
|
|
Tag::PointerType => todo!(),
|
|
Tag::ArrayType => todo!(),
|
|
Tag::CallExpr => todo!(),
|
|
Tag::FieldAccess => todo!(),
|
|
Tag::ArgumentList => todo!(),
|
|
Tag::Argument => todo!(),
|
|
Tag::NamedArgument => todo!(),
|
|
Tag::ExplicitCast => todo!(),
|
|
Tag::Deref => todo!(),
|
|
Tag::AddressOf => todo!(),
|
|
Tag::Not => todo!(),
|
|
Tag::Negate => todo!(),
|
|
Tag::Or => todo!(),
|
|
Tag::And => todo!(),
|
|
Tag::BitOr => todo!(),
|
|
Tag::BitXOr => todo!(),
|
|
Tag::BitAnd => todo!(),
|
|
Tag::Eq => todo!(),
|
|
Tag::NEq => todo!(),
|
|
Tag::Lt => todo!(),
|
|
Tag::Gt => todo!(),
|
|
Tag::Le => todo!(),
|
|
Tag::Ge => todo!(),
|
|
Tag::Shl => todo!(),
|
|
Tag::Shr => todo!(),
|
|
Tag::Add => todo!(),
|
|
Tag::Sub => todo!(),
|
|
Tag::Mul => todo!(),
|
|
Tag::Div => todo!(),
|
|
Tag::Rem => todo!(),
|
|
Tag::Assign => todo!(),
|
|
Tag::SubscriptExpr => todo!(),
|
|
Tag::IfExpr => todo!(),
|
|
Tag::IfElseExpr => todo!(),
|
|
Tag::Error => todo!(),
|
|
Tag::Undefined => todo!(),
|
|
Tag::PlaceToValueConversion => todo!(),
|
|
Tag::ValueToPlaceConversion => todo!(),
|
|
}
|
|
},
|
|
);
|
|
}
|
|
}
|
|
}
|