Compare commits

..

No commits in common. "bottom-up-value-place" and "main" have entirely different histories.

20 changed files with 2777 additions and 5858 deletions

1
.envrc
View file

@ -1 +0,0 @@
use flake

View file

@ -1,7 +1,7 @@
[package]
name = "compiler"
version = "0.1.0"
edition = "2024"
edition = "2021"
[dependencies]
ansi_term = "0.12.1"
@ -12,9 +12,6 @@ log = "0.4.22"
num-bigint = "0.4.6"
num-traits = "0.2.19"
ordered-float = "4.2.2"
paste = "1.0.15"
petgraph = "0.6.5"
thiserror = "1.0.63"
unicode-xid = "0.2.4"
werkzeug = { path = "../../rust/werkzeug" }

View file

@ -1,96 +0,0 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1753939845,
"narHash": "sha256-K2ViRJfdVGE8tpJejs8Qpvvejks1+A4GQej/lBk5y7I=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "94def634a20494ee057c76998843c015909d6311",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1744536153,
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlays": "rust-overlays"
}
},
"rust-overlays": {
"inputs": {
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1754102567,
"narHash": "sha256-d6nZ+1e4VDqW6VAwfx9EAUDJdPxSwqwGiuli32FEgoE=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "08ff39bf869cadca3102b39824f4c7025186b7dc",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

View file

@ -1,31 +0,0 @@
{
description = "A nix flake for nightly rust";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlays.url = "github:oxalica/rust-overlay";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, rust-overlays, ...}:
flake-utils.lib.eachDefaultSystem (system: let
overlays = [
(import rust-overlays)
];
pkgs = import nixpkgs {
inherit system overlays;
};
rust = pkgs.rust-bin.selectLatestNightlyWith (toolchain: toolchain.default.override {
extensions = ["rust-src" "rust-analyzer"];
targets = [ "x86_64-unknown-linux-gnu" ];
});
in with pkgs; {
devShells.default = pkgs.mkShell {
buildInputs = [
pkg-config
git
rust
];
};
});
}

View file

@ -1,88 +0,0 @@
//! Type checking for the AST.
//! This module implements a bi-unification type-checking algorithm to infer
//! types for each node in the AST.
// Visitor pattern has lots of unused arguments
#![allow(unused_variables)]
use std::collections::HashMap;
use super::{Ast, Index, intern, visitor::AstVisitorTrait};
type Id = u32;
enum Type {
Reified(intern::Index),
Variable(Id),
}
/// Variance of a type parameter or constraint.
/// A function of type `A -> B` is covariant in `B` and contravariant in `A`.
/// This means that a type `T` may be substituted for `A` if `T` is a subtype of `A`, but
/// a type `T` may only be substituted for `B` if `T` is a supertype of `B`.
///
/// Namely, in a type system with `int` and `nat <: int`, for a function `f: int
/// -> int` in the expression `let u: int = 3; let t: nat = f(u);`, `u` may
/// safely be used as an argument to `f` because `nat <: int`, but `f(u`)` may
/// not be assigned to `t` because `int <: nat` is not true.
enum Variance {
#[doc(alias = "Positive")]
Covariant,
#[doc(alias = "Negative")]
Contravariant,
}
#[derive(Debug, Clone, Copy)]
struct Value(Id);
#[derive(Debug, Clone, Copy)]
struct Use(Id);
/// Typechecking error.
#[derive(Debug, Clone, thiserror::Error)]
enum Error {
#[error("Unimplemented feature")]
Unimplemented,
}
type Result<T> = std::result::Result<T, Error>;
struct Bindings {
inner: HashMap<super::Index, Value>,
}
struct TypeChecker<'a> {
pool: &'a mut intern::InternPool,
}
// Core
impl TypeChecker<'_> {
pub fn new(pool: &mut intern::InternPool) -> TypeChecker {
TypeChecker { pool }
}
fn var(&mut self) -> (Value, Use) {
todo!()
}
}
// Frontend
impl<'a> AstVisitorTrait<&'a Ast> for TypeChecker<'_> {
type Error = Error;
type Value = Value;
const UNIMPL: Self::Error = Error::Unimplemented;
fn visit_constant_impl(
&mut self,
ast: &'a Ast,
idx: Index,
ty: Index,
value: intern::Index,
) -> std::result::Result<Self::Value, Self::Error> {
// constants may be of type `comptime_int`, which is a special type that
// cannot exist at runtime.
todo!()
}
}

View file

@ -1,159 +0,0 @@
use std::fmt::Display;
use crate::{lexer::SourceLocation, writeln_indented};
use super::{
intern::{self, InternPoolWrapper as InternPool},
visitor::AstVisitorTrait,
Ast, Children, ComptimeCache, Index, Tag, TypeCache,
};
struct AstRenderVisitor<'a, W: core::fmt::Write> {
syms: &'a crate::symbol_table::syms2::Symbols,
ip: &'a InternPool,
cache: TypeCache,
comptime_cache: ComptimeCache,
scopes: Vec<Index>,
w: &'a mut W,
}
impl<'a, W: core::fmt::Write> AstVisitorTrait<&'a Ast> for AstRenderVisitor<'_, W> {
type Error = core::fmt::Error;
type Value = ();
const UNIMPL: Self::Error = core::fmt::Error;
fn visit_any(&mut self, ast: &'a Ast, idx: Index) -> Result<Self::Value, Self::Error> {
let display = NodeDisplay::new(ast, self.ip, idx).with_indent(self.scopes.len() as u32 * 2);
match display.tag {
Tag::File
| Tag::FunctionDecl
| Tag::GlobalDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
self.scopes.push(idx);
}
_ => {}
}
write!(self.w, "{display}")?;
for child in display.children.0 {
self.visit_any(ast, child)?;
}
match display.tag {
Tag::File
| Tag::FunctionDecl
| Tag::GlobalDecl
| Tag::Block
| Tag::BlockTrailingExpr => {
self.scopes.pop();
}
_ => {}
}
Ok(())
}
}
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 {
node: Index,
tag: Tag,
loc: SourceLocation,
children: Children,
is_comptime: bool,
ty: intern::Index,
indent: u32,
}
impl NodeDisplay {
pub fn new(ast: &Ast, ip: &InternPool, node: Index) -> NodeDisplay {
let tag = ast.tags[node];
let loc = ast.source_locs[node];
let children = Children(ast.get_node_children(node));
let ty = ast.get_type_of_node(ip, &mut TypeCache::new(), node);
let is_comptime = ast.is_node_comptime_evaluable(&mut ComptimeCache::default(), node);
Self {
node,
tag,
loc,
children,
is_comptime,
ty,
indent: 0,
}
}
fn with_indent(self, indent: u32) -> Self {
Self { indent, ..self }
}
}
impl Display for NodeDisplay {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self {
node,
tag,
loc,
children,
is_comptime,
ty,
indent,
} = self;
writeln_indented!(
*indent,
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(),
}
}
pub(crate) fn render<W: core::fmt::Write>(&mut self, w: &mut W) -> core::fmt::Result {
let mut visitor = AstRenderVisitor {
syms: self.syms,
ip: self.ip,
cache: TypeCache::new(),
comptime_cache: ComptimeCache::default(),
scopes: Vec::new(),
w,
};
for idx in self.ast.get_root_file_indices() {
visitor.visit_any(self.ast, idx)?;
}
Ok(())
}
}

View file

@ -22,12 +22,6 @@ pub enum SimpleType {
USize,
ISize,
ComptimeInt,
/// Top type: this is the supertype of all types, and any value can coerce into it.
/// Although Rust's `()` is not a top type, it can be thought of as a top type in some contexts.
Top,
/// Bottom type: this is the subtype of all types, and it can coerce into a value of any type.
/// Akin to Rust's `!`.
Bottom,
}
impl From<u8> for SimpleType {
@ -58,8 +52,6 @@ impl Display for SimpleType {
SimpleType::USize => "usize",
SimpleType::ISize => "isize",
SimpleType::ComptimeInt => "comptime_int",
SimpleType::Top => "",
SimpleType::Bottom => "",
}
)
}
@ -410,73 +402,6 @@ impl Index {
}
}
pub struct InternPoolWrapper(core::cell::UnsafeCell<InternPool>);
impl InternPoolWrapper {
pub fn as_mut(&self) -> &mut InternPool {
unsafe { &mut *self.0.get() }
}
pub fn as_ref(&self) -> &InternPool {
unsafe { &*self.0.get() }
}
pub fn new() -> Self {
InternPool::new().into()
}
}
impl From<InternPool> for InternPoolWrapper {
fn from(value: InternPool) -> Self {
Self(core::cell::UnsafeCell::new(value))
}
}
impl core::ops::Deref for InternPoolWrapper {
type Target = InternPool;
fn deref(&self) -> &Self::Target {
unsafe { &*self.0.get() }
}
}
impl core::ops::DerefMut for InternPoolWrapper {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut()
}
}
impl AsRef<InternPool> for InternPoolWrapper {
fn as_ref(&self) -> &InternPool {
Self::as_ref(self)
}
}
impl AsRef<InternPool> for InternPool {
fn as_ref(&self) -> &InternPool {
self
}
}
// impl AsMut<InternPool> for InternPoolWrapper {
// fn as_mut(&mut self) -> &mut InternPool {
// Self::as_mut(self)
// }
// }
// impl AsMut<InternPool> for InternPool {
// fn as_mut(&mut self) -> &mut InternPool {
// self
// }
// }
impl core::fmt::Debug for InternPoolWrapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("InternPoolWrapper")
.field(self.as_ref())
.finish()
}
}
pub struct InternPool {
tags: Vec<Tag>,
indices: Vec<u32>,
@ -535,8 +460,6 @@ macro_rules! static_keys {
}
static_keys!(
TOP => Key::SimpleType {ty: SimpleType::Top,},
BOTTOM => Key::SimpleType {ty: SimpleType::Bottom,},
BOOL => Key::SimpleType {ty: SimpleType::Bool,},
F32 => Key::SimpleType {ty: SimpleType::F32,},
F64 => Key::SimpleType {ty: SimpleType::F64,},
@ -642,18 +565,6 @@ impl InternPool {
pub fn get_i64_type(&self) -> Index {
self.get_assume_present(&Key::SIntType { bit_width: 64 })
}
pub fn get_top_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::Top,
})
}
pub fn get_bottom_type(&self) -> Index {
self.get_assume_present(&Key::SimpleType {
ty: SimpleType::Bottom,
})
}
}
#[derive(Debug, Clone, Copy)]
@ -663,17 +574,6 @@ pub struct TypeInfo {
pub signed: bool,
}
impl TypeInfo {
/// byte size
pub fn size(&self) -> u32 {
self.bitsize.div_ceil(8)
}
/// byte align
pub fn align(&self) -> u32 {
self.bitalign.div_ceil(8)
}
}
impl InternPool {
pub fn peer_type(&mut self, lhs: Index, rhs: Index) -> Option<Index> {
if lhs == rhs {
@ -762,8 +662,8 @@ impl InternPool {
todo!("void can't be turned into a mir type")
}
SimpleType::ISize | SimpleType::USize => Type::QWord,
SimpleType::Top | SimpleType::Bottom | SimpleType::ComptimeInt => {
panic!("{ty} can't be turned into a mir type")
SimpleType::ComptimeInt => {
panic!("comptime int can't be turned into a mir type")
}
},
Key::ArrayType { .. } => {
@ -838,9 +738,6 @@ impl InternPool {
},
SimpleType::USize => ptr_size,
SimpleType::ISize => ptr_size,
SimpleType::Top | SimpleType::Bottom => {
panic!("top and bottom types are not sized")
}
SimpleType::ComptimeInt => panic!("comptime int is unsized"),
},
Key::PointerType { .. } => ptr_size,
@ -978,9 +875,6 @@ impl InternPool {
SimpleType::USize => Type::Integer(IntegralType::new(false, pointer_bits)),
SimpleType::ISize => Type::Integer(IntegralType::new(true, pointer_bits)),
SimpleType::ComptimeInt => Type::comptime_number(),
SimpleType::Top | SimpleType::Bottom => {
panic!("top and bottom types cannot be converted to ast1 types")
}
},
Key::PointerType { pointee, flags } => Type::Pointer {
constness: flags.is_const,
@ -1403,20 +1297,6 @@ impl InternPool {
})
}
pub fn try_get_pointee_type(&self, pointer: Index) -> Option<Index> {
match self.get_key(pointer) {
Key::PointerType { pointee, .. } | Key::ArrayType { pointee, .. } => Some(pointee),
_ => None,
}
}
pub fn try_get_return_type(&self, func: Index) -> Option<Index> {
match self.get_key(func) {
Key::FunctionType { return_type, .. } => Some(return_type),
_ => None,
}
}
pub fn get_pointer_type(&mut self, pointee: Index, flags: Option<PointerFlags>) -> Index {
let key = Key::PointerType {
pointee,
@ -1424,7 +1304,6 @@ impl InternPool {
};
self.get_or_insert(key)
}
pub fn try_get_pointer_type(
&self,
pointee: Index,

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,631 +0,0 @@
use super::{
intern::{Index as Interned, PointerFlags, StructFlags},
visitor::AstExt,
Ast, Index, ParseError, Tag,
};
pub trait AstNodeExt {
fn get_ast_node(&self, idx: Index) -> AstNode;
}
impl AstNodeExt for &mut Ast {
fn get_ast_node(&self, idx: Index) -> AstNode {
<Ast as AstNodeExt>::get_ast_node(self, idx)
}
}
impl AstNodeExt for &Ast {
fn get_ast_node(&self, idx: Index) -> AstNode {
<Ast as AstNodeExt>::get_ast_node(self, idx)
}
}
impl AstNodeExt for Ast {
fn get_ast_node(&self, idx: Index) -> AstNode {
let (tag, data) = self.get_node_tag_and_data(idx);
match tag {
Tag::Root => {
unreachable!()
}
Tag::File => {
let (a, b) = data.as_extra_range();
let decls = unsafe { Index::from_slice_unchecked(&self.extra[a..b]).to_vec() };
AstNode::File { decls }
}
Tag::FunctionProto => {
let (name, extra) = data.as_intern_and_extra_offset();
let (return_type, parameter_list) = (
Index::from_u32(self.extra[extra]).unwrap(),
Index::from_u32(self.extra[extra + 1]).unwrap(),
);
AstNode::FunctionProto {
name,
return_type,
parameter_list,
}
}
Tag::FunctionProtoInterned => {
let (name, ty) = data.as_two_interns();
AstNode::FunctionProtoInterned { name, ty }
}
Tag::FunctionDecl => {
let (proto, body) = data.as_two_indices();
AstNode::FunctionDecl { proto, body }
}
Tag::ParameterList => {
let (a, b) = data.as_extra_range();
let params = unsafe { Index::from_slice_unchecked(&self.extra[a..b]).to_vec() };
AstNode::ParameterList { params }
}
Tag::Parameter => {
let (ty, name) = data.as_index_intern();
AstNode::Parameter { ty, name }
}
Tag::Block => {
let (a, b) = data.as_extra_range();
let statements = unsafe { Index::from_slice_unchecked(&self.extra[a..b]).to_vec() };
AstNode::Block {
statements,
expr: None,
}
}
Tag::BlockTrailingExpr => {
let (a, b) = data.as_extra_range();
let (expr, statements) = unsafe {
Index::from_slice_unchecked(&self.extra[a..b])
.split_last()
.unwrap()
};
AstNode::Block {
statements: statements.to_vec(),
expr: Some(*expr),
}
}
Tag::Constant => {
let (ty, value) = data.as_index_intern();
AstNode::Constant { ty, value }
}
Tag::ExprStmt => AstNode::ExprStmt {
expr: data.as_index(),
},
Tag::ReturnStmt => AstNode::ReturnStmt,
Tag::ReturnExprStmt => AstNode::ReturnExprStmt {
expr: data.as_index(),
},
Tag::VarDecl => {
let (a, _) = data.as_extra_range();
let name = Interned::from_u32(self.extra[a]);
let ty = Index::from_u32(self.extra[a + 1]).unwrap();
AstNode::VarDecl { name, ty }
}
Tag::MutVarDecl => {
let (a, _) = data.as_extra_range();
let name = Interned::from_u32(self.extra[a]);
let ty = Index::from_u32(self.extra[a + 1]).unwrap();
AstNode::MutVarDecl { name, ty }
}
Tag::VarDeclAssignment => {
let (a, b) = data.as_extra_range();
let extra = &self.extra[a..b];
let name = Interned::from_u32(*extra.get(0).unwrap());
let expr = Index::from_u32(*extra.get(1).unwrap()).unwrap();
let ty = extra.get(2).map(|&inner| Index::from_u32(inner).unwrap());
AstNode::MutVarDeclAssignment { name, expr, ty }
}
Tag::MutVarDeclAssignment => {
let (a, b) = data.as_extra_range();
let extra = &self.extra[a..b];
let name = Interned::from_u32(*extra.get(0).unwrap());
let expr = Index::from_u32(*extra.get(1).unwrap()).unwrap();
let ty = extra.get(2).map(|&inner| Index::from_u32(inner).unwrap());
AstNode::MutVarDeclAssignment { name, expr, ty }
}
Tag::GlobalDecl => {
let (name, offset) = data.as_intern_and_extra_offset();
let ty = Index::from_u32(self.extra[offset]).unwrap();
let expr = Index::from_u32(self.extra[offset + 1]).unwrap();
AstNode::GlobalDecl { name, expr, ty }
}
Tag::StructDecl => {
let (name, offset) = data.as_intern_and_extra_offset();
let flags = StructFlags::unpack(self.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 field_types =
unsafe { Index::from_slice_unchecked(&self.extra[types]).to_vec() };
let field_names = self.extra[names]
.iter()
.map(|&i| Interned::from_u32(i))
.collect();
AstNode::StructDecl {
name,
flags,
field_names,
field_types,
}
}
Tag::StructDeclInterned => {
let (name, ty) = data.as_two_interns();
AstNode::StructDeclInterned { name, ty }
}
Tag::FieldDecl => {
let (ty, name) = data.as_index_intern();
AstNode::FieldDecl { name, ty }
}
Tag::DeclRef => AstNode::DeclRef {
decl: data.as_index(),
},
Tag::DeclRefUnresolved => {
let (scope, name) = data.as_index_intern();
AstNode::DeclRefUnresolved { scope, name }
}
Tag::InternedType => AstNode::InternedType {
intern: data.as_intern(),
},
Tag::TypeDeclRef => AstNode::TypeDeclRef {
decl: data.as_index(),
},
Tag::TypeDeclRefUnresolved => {
let (scope, name) = data.as_index_intern();
AstNode::TypeDeclRefUnresolved { scope, name }
}
Tag::PointerType => {
let (ty, flags) = data.as_index_and_opaque();
let flags = PointerFlags::unpack(flags as u8);
AstNode::PointerType { ty, flags }
}
Tag::ArrayType => {
let (length, pointer) = data.as_two_indices();
AstNode::ArrayType { length, pointer }
}
Tag::CallExpr => {
let (func, argument_list) = data.as_two_indices();
AstNode::CallExpr {
func,
argument_list,
}
}
Tag::FieldAccess => {
let (expr, field_name) = data.as_index_intern();
AstNode::FieldAccess { field_name, expr }
}
Tag::ArgumentList => {
let (a, b) = data.as_extra_range();
let arguments = unsafe { Index::from_slice_unchecked(&self.extra[a..b]).to_vec() };
AstNode::ArgumentList { arguments }
}
Tag::Argument => AstNode::Argument {
expr: data.as_index(),
name: None,
},
Tag::NamedArgument => {
let (expr, name) = data.as_index_intern();
AstNode::Argument {
expr,
name: Some(name),
}
}
Tag::ExplicitCast => {
let (expr, ty) = data.as_two_indices();
AstNode::ExplicitCast { expr, ty }
}
Tag::Deref => AstNode::Deref {
expr: data.as_index(),
},
Tag::AddressOf => AstNode::AddressOf {
expr: data.as_index(),
},
Tag::Not => AstNode::Not {
expr: data.as_index(),
},
Tag::Negate => AstNode::Negate {
expr: data.as_index(),
},
Tag::PlaceToValueConversion => AstNode::PlaceToValueConversion {
expr: data.as_index(),
},
Tag::ValueToPlaceConversion => AstNode::ValueToPlaceConversion {
expr: data.as_index(),
},
Tag::Or => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Or { lhs, rhs }
}
Tag::And => {
let (lhs, rhs) = data.as_two_indices();
AstNode::And { lhs, rhs }
}
Tag::BitOr => {
let (lhs, rhs) = data.as_two_indices();
AstNode::BitOr { lhs, rhs }
}
Tag::BitXOr => {
let (lhs, rhs) = data.as_two_indices();
AstNode::BitXOr { lhs, rhs }
}
Tag::BitAnd => {
let (lhs, rhs) = data.as_two_indices();
AstNode::BitAnd { lhs, rhs }
}
Tag::Eq => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Eq { lhs, rhs }
}
Tag::NEq => {
let (lhs, rhs) = data.as_two_indices();
AstNode::NEq { lhs, rhs }
}
Tag::Lt => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Lt { lhs, rhs }
}
Tag::Gt => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Gt { lhs, rhs }
}
Tag::Le => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Le { lhs, rhs }
}
Tag::Ge => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Ge { lhs, rhs }
}
Tag::Shl => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Shl { lhs, rhs }
}
Tag::Shr => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Shr { lhs, rhs }
}
Tag::Add => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Add { lhs, rhs }
}
Tag::Sub => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Sub { lhs, rhs }
}
Tag::Mul => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Mul { lhs, rhs }
}
Tag::Div => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Div { lhs, rhs }
}
Tag::Rem => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Rem { lhs, rhs }
}
Tag::Assign => {
let (lhs, rhs) = data.as_two_indices();
AstNode::Assign { lhs, rhs }
}
Tag::SubscriptExpr => {
let (lhs, index) = data.as_two_indices();
AstNode::SubscriptExpr { lhs, index }
}
Tag::IfExpr => {
let (cond, body) = data.as_two_indices();
AstNode::IfExpr { cond, body }
}
Tag::IfElseExpr => {
let (cond, extra) = data.as_index_and_extra_offset();
let [a, b] = self.extra[extra..][..2] else {
unreachable!()
};
AstNode::IfElseExpr {
cond,
a: Index::from_u32(a).unwrap(),
b: Index::from_u32(b).unwrap(),
}
}
Tag::Error => AstNode::Error {
err: data.as_error(),
},
Tag::Undefined => AstNode::Undefined,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AstNode {
/// pseudo tag, contains a range from a..b into extra of all files.
Root {
files: Vec<Index>,
},
/// `data` is a range from a..b into extra of all global nodes.
File {
decls: Vec<Index>,
},
/// `data` is an intern to a name, and an index into extra of [index: return_type, index: ParameterList]
FunctionProto {
name: Interned,
return_type: Index,
parameter_list: Index,
},
/// `data` is an intern to a name, and an intern to the function type
FunctionProtoInterned {
name: Interned,
ty: Interned,
},
/// `data` is an index to a FunctionProto and an index to a Block
FunctionDecl {
proto: Index,
body: Index,
},
/// `data` is a range from a..b into extra of indices to parameters
ParameterList {
params: Vec<Index>,
},
/// `data` is an index to a type, and an intern to a name
Parameter {
ty: Index,
name: Interned,
},
/// `data` is range from a..b into `extra` of indices to statements
Block {
statements: Vec<Index>,
expr: Option<Index>,
},
/// `data` is an index to a type, and an intern to a value
Constant {
ty: Index,
value: Interned,
},
/// `data` is an index to an expression
ExprStmt {
expr: Index,
},
/// `data` is none
ReturnStmt,
/// `data` is an index to an expr
ReturnExprStmt {
expr: Index,
},
/// `data` is a range from a..b into `extra` of `[name: intern, type: index]`
VarDecl {
name: Interned,
ty: Index,
},
/// `data` is a range from a..b into `extra` of `[name: intern, type: index]`
MutVarDecl {
name: Interned,
ty: Index,
},
/// `data` is a range from a..b into `extra` of `[name: intern, expr: index, type?: index]`
VarDeclAssignment {
name: Interned,
expr: Index,
ty: Option<Index>,
},
/// `data` is a range from a..b into `extra` of `[name: intern, expr: index, type?: index]`
MutVarDeclAssignment {
name: Interned,
expr: Index,
ty: Option<Index>,
},
/// `data` is an intern to a name, and an offset into `extra` of `[type: index, expr: index]`
GlobalDecl {
name: Interned,
expr: Index,
ty: Index,
},
/// `data` is an intern to a name, and an offset into extra of `[flags, type0 ,..., typeN ,name0 ,..., nameN]`
StructDecl {
name: Interned,
flags: StructFlags,
field_names: Vec<Interned>,
field_types: Vec<Index>,
},
/// `data` is an intern to a name, and an intern to the type of the struct
StructDeclInterned {
name: Interned,
ty: Interned,
},
/// `data` is an index to a type, and an intern to a name
FieldDecl {
name: Interned,
ty: Index,
},
/// `data` is an index to a Parameter, VarDecl, GlobalDecl or FunctionDecl, and an opaque DeclKind
DeclRef {
decl: Index,
},
/// `data` is an inlined key into the symbol table (scope: index, name: intern)
DeclRefUnresolved {
scope: Index,
name: Interned,
},
/// `data` is an intern of a type
InternedType {
intern: Interned,
},
/// `data` is an index to a StructDecl
TypeDeclRef {
decl: Index,
},
/// `data` is an inlined key into the symbol table (scope: index, name: intern)
TypeDeclRefUnresolved {
scope: Index,
name: Interned,
},
/// `data` is an index to a Type and u32 PointerFlags (extra offset)
PointerType {
ty: Index,
flags: PointerFlags,
},
/// `data` is an index to a length expression, and an underlying pointer type
ArrayType {
length: Index,
pointer: Index,
},
/// `data` is an index to an expr and an index to an ArgumentList
CallExpr {
func: Index,
argument_list: Index,
},
/// `data` is an index to an expr and an intern to a field name
FieldAccess {
field_name: Interned,
expr: Index,
},
/// `data` is a range from a..b into extra of indices to arguments
ArgumentList {
arguments: Vec<Index>,
},
/// `data` is an index to an expression
Argument {
expr: Index,
name: Option<Interned>,
},
/// `data` is an index to lhs, and an index to the type
ExplicitCast {
expr: Index,
ty: Index,
},
/// `data` is a single index to an expr
Deref {
expr: Index,
},
AddressOf {
expr: Index,
},
Not {
expr: Index,
},
Negate {
expr: Index,
},
PlaceToValueConversion {
expr: Index,
},
ValueToPlaceConversion {
expr: Index,
},
/// data is two indices for `lhs` and `rhs`
Or {
lhs: Index,
rhs: Index,
},
And {
lhs: Index,
rhs: Index,
},
BitOr {
lhs: Index,
rhs: Index,
},
BitXOr {
lhs: Index,
rhs: Index,
},
BitAnd {
lhs: Index,
rhs: Index,
},
Eq {
lhs: Index,
rhs: Index,
},
NEq {
lhs: Index,
rhs: Index,
},
Lt {
lhs: Index,
rhs: Index,
},
Gt {
lhs: Index,
rhs: Index,
},
Le {
lhs: Index,
rhs: Index,
},
Ge {
lhs: Index,
rhs: Index,
},
Shl {
lhs: Index,
rhs: Index,
},
Shr {
lhs: Index,
rhs: Index,
},
Add {
lhs: Index,
rhs: Index,
},
Sub {
lhs: Index,
rhs: Index,
},
Mul {
lhs: Index,
rhs: Index,
},
Div {
lhs: Index,
rhs: Index,
},
Rem {
lhs: Index,
rhs: Index,
},
Assign {
lhs: Index,
rhs: Index,
},
SubscriptExpr {
lhs: Index,
index: Index,
},
IfExpr {
cond: Index,
body: Index,
},
/// `data` is an index to an expression and an index into extra for [if, else]
IfElseExpr {
cond: Index,
a: Index,
b: Index,
},
// TODO:
/// `data` is a ParseError
Error {
err: ParseError,
},
/// placeholder tag for reserved indices/nodes, `data` is none
Undefined,
}

View file

@ -1,502 +0,0 @@
// Visitor pattern has lots of unused arguments
#![allow(unused_variables)]
use crate::variant;
use super::{
Ast, Data, Index, Tag,
intern::{self},
tag::{AstNode, AstNodeExt},
visitor::{AstExt, AstVisitorTrait},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ErrorKind {
MismatchingTypes,
DerefNonPointer,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Error {
idx: Index,
kind: ErrorKind,
}
struct TypeChecker<'a> {
ip: &'a mut intern::InternPool,
errors: Vec<Error>,
}
impl<'a> TypeChecker<'a> {
fn visit_children<'b>(
&mut self,
ast: &'b mut super::Ast,
idx: Index,
) -> Result<Option<intern::Index>, ()> {
for child in ast.get_node_children(idx) {
self.visit_any(ast, child)?;
}
Ok(None)
}
}
// TODO: actually handle errors here instead of aborting.
impl<'a> AstVisitorTrait<&'a mut Ast> for TypeChecker<'_> {
type Error = ();
type Value = Option<intern::Index>;
const UNIMPL: Self::Error = ();
fn visit_parameter_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
ty: Index,
name: intern::Index,
) -> Result<Self::Value, Self::Error> {
_ = (idx, name);
self.visit_any(ast, ty)
}
fn visit_array_type_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
length: Index,
pointer: Index,
) -> Result<Self::Value, Self::Error> {
_ = self.visit_any(ast, length)?;
let pointee = self.visit_any(ast, pointer)?.expect("no type?");
variant!(self.ip.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.ip.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.ip.get_array_type(pointee, Some(flags), length);
ast.tags[idx] = Tag::InternedType;
ast.datas[idx] = Data::intern(ty);
Ok(Some(ty))
}
fn visit_pointer_type_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
ty: Index,
flags: intern::PointerFlags,
) -> Result<Self::Value, Self::Error> {
let pointee = self.visit_any(ast, ty)?.expect("no type?");
let ty = self.ip.get_pointer_type(pointee, Some(flags));
ast.tags[idx] = Tag::InternedType;
ast.datas[idx] = Data::intern(ty);
Ok(Some(ty))
}
fn visit_type_decl_ref_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
decl: Index,
) -> Result<Self::Value, Self::Error> {
let ty = self.visit_any(ast, decl)?.expect("no type?");
ast.tags[idx] = Tag::InternedType;
ast.datas[idx] = Data::intern(ty);
Ok(Some(ty))
}
fn visit_function_proto_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
name: intern::Index,
return_type: Index,
parameter_list: Index,
) -> Result<Self::Value, Self::Error> {
variant!(ast.get_ast_node(parameter_list) => AstNode::ParameterList { params });
let return_type = self.visit_any(ast, return_type)?.expect("no type?");
let params = params
.into_iter()
.map(|param| self.visit_parameter(ast, param).map(|a| a.unwrap()))
.collect::<Result<Vec<_>, _>>()?;
let ty = self.ip.get_function_type(return_type, params);
ast.tags[idx] = Tag::FunctionProtoInterned;
ast.datas[idx] = Data::two_interns(name, ty);
Ok(Some(ty))
}
fn visit_function_proto_interned_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
name: intern::Index,
ty: intern::Index,
) -> Result<Self::Value, Self::Error> {
Ok(Some(ty))
}
fn visit_struct_decl_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
name: intern::Index,
flags: intern::StructFlags,
field_names: Vec<intern::Index>,
field_types: Vec<Index>,
) -> Result<Self::Value, Self::Error> {
let types = field_types
.into_iter()
.map(|i| self.visit_any(ast, i).map(Option::unwrap))
.collect::<Result<Vec<_>, _>>()?;
let ty = self.ip.insert_or_replace_struct_type(
name,
idx,
flags.packed,
flags.c_like,
field_names.into_iter().zip(types),
);
ast.tags[idx] = Tag::StructDeclInterned;
ast.datas[idx] = Data::two_interns(name, ty);
Ok(Some(ty))
}
fn visit_function_decl_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
proto: Index,
body: Index,
) -> Result<Self::Value, Self::Error> {
let ty = self.visit_any(ast, proto)?.expect("no type?");
let body = self.visit_block(ast, body)?.unwrap_or(intern::Index::VOID);
let ret_ty = self.ip.try_get_return_type(ty).expect("no type?");
if body != ret_ty {
self.errors.push(Error {
idx,
kind: ErrorKind::MismatchingTypes,
});
Ok(Some(intern::Index::VOID))
} else {
Ok(Some(ty))
}
}
fn visit_block_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
statements: Vec<Index>,
expr: Option<Index>,
) -> Result<Self::Value, Self::Error> {
for stmt in statements {
self.visit_any(ast, stmt)?;
}
expr.map(|expr| self.visit_any(ast, expr))
.transpose()
.map(Option::flatten)
}
fn visit_file_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
decls: Vec<Index>,
) -> Result<Self::Value, Self::Error> {
for decl in decls {
self.visit_any(ast, decl)?;
}
Ok(None)
}
fn visit_struct_decl_interned_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
name: intern::Index,
ty: intern::Index,
) -> Result<Self::Value, Self::Error> {
Ok(Some(ty))
}
fn visit_interned_type_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
intern: intern::Index,
) -> Result<Self::Value, Self::Error> {
Ok(Some(intern))
}
fn visit_any(
&mut self,
ast: &'a mut Ast,
idx: super::Index,
) -> Result<Self::Value, Self::Error> {
let (tag, data) = ast.get_node_tag_and_data(idx);
let _ty = match tag {
Tag::Root => unreachable!(),
Tag::InternedType => Some(data.as_intern()),
Tag::File => self.visit_file(ast, idx)?,
Tag::ArrayType => self.visit_array_type(ast, idx)?,
Tag::PointerType => self.visit_pointer_type(ast, idx)?,
Tag::TypeDeclRef => self.visit_type_decl_ref(ast, idx)?,
Tag::FunctionProtoInterned => self.visit_function_proto_interned(ast, idx)?,
Tag::FunctionProto => self.visit_function_proto(ast, idx)?,
Tag::Parameter => self.visit_parameter(ast, idx)?,
Tag::StructDecl => self.visit_struct_decl(ast, idx)?,
Tag::StructDeclInterned => self.visit_struct_decl_interned(ast, idx)?,
Tag::FunctionDecl => self.visit_function_decl(ast, idx)?,
Tag::ParameterList => todo!(),
Tag::Block | Tag::BlockTrailingExpr => self.visit_block(ast, idx)?,
Tag::Constant => self.visit_constant(ast, idx)?,
Tag::ExprStmt => self.visit_expr_stmt(ast, idx)?,
Tag::ReturnStmt => self.visit_return_stmt(ast, idx)?,
Tag::ReturnExprStmt => todo!(),
Tag::VarDecl => todo!(),
Tag::MutVarDecl => todo!(),
Tag::VarDeclAssignment => todo!(),
Tag::MutVarDeclAssignment => todo!(),
Tag::GlobalDecl => todo!(),
Tag::FieldDecl => todo!(),
Tag::DeclRef => todo!(),
Tag::DeclRefUnresolved => todo!(),
Tag::TypeDeclRefUnresolved => todo!(),
Tag::CallExpr => todo!(),
Tag::FieldAccess => todo!(),
Tag::ArgumentList => todo!(),
Tag::Argument => todo!(),
Tag::NamedArgument => todo!(),
Tag::ExplicitCast => self.visit_explicit_cast(ast, idx)?,
Tag::Deref => self.visit_deref(ast, idx)?,
Tag::AddressOf => self.visit_address_of(ast, idx)?,
Tag::Not | Tag::Negate => {
let ty = self.visit_any(ast, data.as_index())?;
ty
}
Tag::PlaceToValueConversion => self.visit_place_to_value_conversion(ast, idx)?,
Tag::ValueToPlaceConversion => self.visit_value_to_place_conversion(ast, idx)?,
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 => {
let (lhs, rhs) = data.as_two_indices();
let lhs = self.visit_any(ast, lhs)?.unwrap();
let rhs = self.visit_any(ast, rhs)?.unwrap();
if lhs != rhs {
self.errors.push(Error {
idx,
kind: ErrorKind::MismatchingTypes,
});
}
Some(lhs)
}
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::Error => todo!(),
Tag::Undefined => todo!(),
};
todo!()
}
fn visit_explicit_cast_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
expr: Index,
ty: Index,
) -> Result<Self::Value, Self::Error> {
_ = self.visit_any(ast, expr)?;
// TODO: make sure this cast is legal
let ty = self.visit_any(ast, ty)?;
Ok(ty)
}
fn visit_address_of_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
expr: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_any(ast, expr)
}
fn visit_deref_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
expr: Index,
) -> Result<Self::Value, Self::Error> {
let ty = self.visit_any(ast, expr)?.unwrap();
if let intern::Key::PointerType { pointee, .. } = self.ip.get_key(ty) {
Ok(Some(pointee))
} else {
Ok(None)
}
}
fn visit_place_to_value_conversion_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
expr: Index,
) -> Result<Self::Value, Self::Error> {
let ty = self.visit_any(ast, expr)?;
if let Some(ty) = ty {
Ok(self.ip.try_get_pointee_type(ty))
} else {
self.errors.push(Error {
idx,
kind: ErrorKind::DerefNonPointer,
});
Ok(None)
}
}
fn visit_value_to_place_conversion_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
expr: Index,
) -> Result<Self::Value, Self::Error> {
let ty = self.visit_any(ast, expr)?;
if let Some(ty) = ty {
Ok(Some(self.ip.get_pointer_type(ty, None)))
} else {
Ok(None)
}
}
fn visit_if_else_expr_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
cond: Index,
a: Index,
b: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_any(ast, cond)?;
let a = self.visit_block(ast, a)?;
let b = self.visit_block(ast, b)?;
if a != b {
self.errors.push(Error {
idx,
kind: ErrorKind::MismatchingTypes,
});
}
Ok(a)
}
fn visit_if_expr_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
cond: Index,
body: Index,
) -> Result<Self::Value, Self::Error> {
self.visit_any(ast, cond)?;
self.visit_block(ast, body)?;
Ok(None)
}
fn visit_subscript_expr_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
lhs: Index,
index: Index,
) -> Result<Self::Value, Self::Error> {
let lhs = self.visit_any(ast, lhs)?.unwrap();
let index = self.visit_any(ast, index)?.unwrap();
if index != intern::Index::USIZE {
self.errors.push(Error {
idx,
kind: ErrorKind::MismatchingTypes,
});
}
let pointee = self.ip.try_get_pointee_type(lhs).unwrap();
let pointer = self.ip.get_pointer_type(pointee, None);
Ok(Some(pointer))
}
fn visit_assign_impl(
&mut self,
ast: &'a mut Ast,
idx: Index,
lhs: Index,
rhs: Index,
) -> Result<Self::Value, Self::Error> {
let lhs = self.visit_any(ast, lhs)?.unwrap();
let rhs = self.visit_any(ast, rhs)?.unwrap();
if self.ip.try_get_pointee_type(lhs) != Some(rhs) {
self.errors.push(Error {
idx,
kind: ErrorKind::MismatchingTypes,
});
}
Ok(None)
}
}

View file

@ -1,625 +0,0 @@
use crate::{ast2::tag::AstNode, variant};
use super::{tag::AstNodeExt, *};
pub trait AstExt {
fn get_node_children(&self, node: Index) -> Vec<Index>;
fn get_node_tag_and_data(&self, node: Index) -> (Tag, Data);
fn get_node_data_for_tag(&self, idx: Index, tag: Tag) -> Option<Data> {
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:?}"))
}
}
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),
}
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,
}
}
}
macro_rules! tag_visit_fn {
($($tag:tt {$($field_name:ident : $field_ty:ty),* $(,)?}),* $(,)?) => {
$(
paste::paste! {
fn [<visit_ $tag:snake>](&mut self, ast: Ast, idx: Index) -> Result<Self::Value, Self::Error> {
variant!(ast.get_ast_node(idx) => AstNode::$tag { $($field_name),* });
self.[<visit_ $tag:snake _impl>](ast, idx, $($field_name),*)
}
fn [<visit_ $tag:snake _impl>](&mut self, ast: Ast, idx: Index, $($field_name: $field_ty),*) -> Result<Self::Value, Self::Error> {
_ = (ast, idx, $($field_name),*);
Err(Self::UNIMPL)
}
}
)*
};
}
use intern::Index as Interned;
pub trait AstVisitorTrait<Ast: AstExt + AstNodeExt> {
type Error;
type Value;
const UNIMPL: Self::Error;
tag_visit_fn!(
File {
decls: Vec<Index>,
},
FunctionProto {
name: Interned,
return_type: Index,
parameter_list: Index,
},
FunctionProtoInterned {
name: Interned,
ty: Interned,
},
FunctionDecl {
proto: Index,
body: Index,
},
ParameterList {
params: Vec<Index>,
},
Parameter {
ty: Index,
name: Interned,
},
Block {
statements: Vec<Index>,
expr: Option<Index>,
},
Constant {
ty: Index,
value: Interned,
},
ExprStmt {
expr: Index,
},
ReturnStmt {},
ReturnExprStmt {
expr: Index,
},
VarDecl {
name: Interned,
ty: Index,
},
MutVarDecl {
name: Interned,
ty: Index,
},
VarDeclAssignment {
name: Interned,
expr: Index,
ty: Option<Index>,
},
MutVarDeclAssignment {
name: Interned,
expr: Index,
ty: Option<Index>,
},
GlobalDecl {
name: Interned,
expr: Index,
ty: Index,
},
StructDecl {
name: Interned,
flags: StructFlags,
field_names: Vec<Interned>,
field_types: Vec<Index>,
},
StructDeclInterned {
name: Interned,
ty: Interned,
},
FieldDecl {
name: Interned,
ty: Index,
},
DeclRef {
decl: Index,
},
DeclRefUnresolved {
scope: Index,
name: Interned,
},
InternedType {
intern: Interned,
},
TypeDeclRef {
decl: Index,
},
TypeDeclRefUnresolved {
scope: Index,
name: Interned,
},
PointerType {
ty: Index,
flags: PointerFlags,
},
ArrayType {
length: Index,
pointer: Index,
},
CallExpr {
func: Index,
argument_list: Index,
},
FieldAccess {
field_name: Interned,
expr: Index,
},
ArgumentList {
arguments: Vec<Index>,
},
Argument {
expr: Index,
name: Option<Interned>,
},
ExplicitCast {
expr: Index,
ty: Index,
},
Deref {
expr: Index,
},
AddressOf {
expr: Index,
},
Not {
expr: Index,
},
Negate {
expr: Index,
},
PlaceToValueConversion {
expr: Index,
},
ValueToPlaceConversion {
expr: Index,
},
Or {
lhs: Index,
rhs: Index,
},
And {
lhs: Index,
rhs: Index,
},
BitOr {
lhs: Index,
rhs: Index,
},
BitXOr {
lhs: Index,
rhs: Index,
},
BitAnd {
lhs: Index,
rhs: Index,
},
Eq {
lhs: Index,
rhs: Index,
},
NEq {
lhs: Index,
rhs: Index,
},
Lt {
lhs: Index,
rhs: Index,
},
Gt {
lhs: Index,
rhs: Index,
},
Le {
lhs: Index,
rhs: Index,
},
Ge {
lhs: Index,
rhs: Index,
},
Shl {
lhs: Index,
rhs: Index,
},
Shr {
lhs: Index,
rhs: Index,
},
Add {
lhs: Index,
rhs: Index,
},
Sub {
lhs: Index,
rhs: Index,
},
Mul {
lhs: Index,
rhs: Index,
},
Div {
lhs: Index,
rhs: Index,
},
Rem {
lhs: Index,
rhs: Index,
},
Assign {
lhs: Index,
rhs: Index,
},
SubscriptExpr {
lhs: Index,
index: Index,
},
IfExpr {
cond: Index,
body: Index,
},
IfElseExpr {
cond: Index,
a: Index,
b: Index,
},
Error {
err: ParseError,
},
Undefined {},
);
fn visit_any(&mut self, ast: Ast, idx: Index) -> Result<Self::Value, Self::Error> {
match ast.get_ast_node(idx) {
AstNode::File { decls } => self.visit_file_impl(ast, idx, decls),
AstNode::FunctionProto {
name,
return_type,
parameter_list,
} => self.visit_function_proto_impl(ast, idx, name, return_type, parameter_list),
AstNode::FunctionProtoInterned { name, ty } => {
self.visit_function_proto_interned_impl(ast, idx, name, ty)
}
AstNode::FunctionDecl { proto, body } => {
self.visit_function_decl_impl(ast, idx, proto, body)
}
AstNode::ParameterList { params } => self.visit_parameter_list_impl(ast, idx, params),
AstNode::Parameter { ty, name } => self.visit_parameter_impl(ast, idx, ty, name),
AstNode::Block { statements, expr } => {
self.visit_block_impl(ast, idx, statements, expr)
}
AstNode::Constant { ty, value } => self.visit_constant_impl(ast, idx, ty, value),
AstNode::ExprStmt { expr } => self.visit_expr_stmt_impl(ast, idx, expr),
AstNode::ReturnStmt => self.visit_return_stmt_impl(ast, idx),
AstNode::ReturnExprStmt { expr } => self.visit_return_expr_stmt_impl(ast, idx, expr),
AstNode::VarDecl { name, ty } => self.visit_var_decl_impl(ast, idx, name, ty),
AstNode::MutVarDecl { name, ty } => self.visit_mut_var_decl_impl(ast, idx, name, ty),
AstNode::VarDeclAssignment { name, expr, ty } => {
self.visit_var_decl_assignment_impl(ast, idx, name, expr, ty)
}
AstNode::MutVarDeclAssignment { name, expr, ty } => {
self.visit_mut_var_decl_assignment_impl(ast, idx, name, expr, ty)
}
AstNode::GlobalDecl { name, expr, ty } => {
self.visit_global_decl_impl(ast, idx, name, expr, ty)
}
AstNode::StructDecl {
name,
flags,
field_names,
field_types,
} => self.visit_struct_decl_impl(ast, idx, name, flags, field_names, field_types),
AstNode::StructDeclInterned { name, ty } => {
self.visit_struct_decl_interned_impl(ast, idx, name, ty)
}
AstNode::FieldDecl { name, ty } => self.visit_field_decl_impl(ast, idx, name, ty),
AstNode::DeclRef { decl } => self.visit_decl_ref_impl(ast, idx, decl),
AstNode::DeclRefUnresolved { scope, name } => {
self.visit_decl_ref_unresolved_impl(ast, idx, scope, name)
}
AstNode::InternedType { intern } => self.visit_interned_type_impl(ast, idx, intern),
AstNode::TypeDeclRef { decl } => self.visit_type_decl_ref_impl(ast, idx, decl),
AstNode::TypeDeclRefUnresolved { scope, name } => {
self.visit_type_decl_ref_unresolved_impl(ast, idx, scope, name)
}
AstNode::PointerType { ty, flags } => self.visit_pointer_type_impl(ast, idx, ty, flags),
AstNode::ArrayType { length, pointer } => {
self.visit_array_type_impl(ast, idx, length, pointer)
}
AstNode::CallExpr {
func,
argument_list,
} => self.visit_call_expr_impl(ast, idx, func, argument_list),
AstNode::FieldAccess { field_name, expr } => {
self.visit_field_access_impl(ast, idx, field_name, expr)
}
AstNode::ArgumentList { arguments } => {
self.visit_argument_list_impl(ast, idx, arguments)
}
AstNode::Argument { expr, name } => self.visit_argument_impl(ast, idx, expr, name),
AstNode::ExplicitCast { expr, ty } => self.visit_explicit_cast_impl(ast, idx, expr, ty),
AstNode::Deref { expr } => self.visit_deref_impl(ast, idx, expr),
AstNode::AddressOf { expr } => self.visit_address_of_impl(ast, idx, expr),
AstNode::Not { expr } => self.visit_not_impl(ast, idx, expr),
AstNode::Negate { expr } => self.visit_negate_impl(ast, idx, expr),
AstNode::PlaceToValueConversion { expr } => {
self.visit_place_to_value_conversion_impl(ast, idx, expr)
}
AstNode::ValueToPlaceConversion { expr } => {
self.visit_value_to_place_conversion_impl(ast, idx, expr)
}
AstNode::Or { lhs, rhs } => self.visit_or_impl(ast, idx, lhs, rhs),
AstNode::And { lhs, rhs } => self.visit_and_impl(ast, idx, lhs, rhs),
AstNode::BitOr { lhs, rhs } => self.visit_bit_or_impl(ast, idx, lhs, rhs),
AstNode::BitXOr { lhs, rhs } => self.visit_bit_x_or_impl(ast, idx, lhs, rhs),
AstNode::BitAnd { lhs, rhs } => self.visit_bit_and_impl(ast, idx, lhs, rhs),
AstNode::Eq { lhs, rhs } => self.visit_eq_impl(ast, idx, lhs, rhs),
AstNode::NEq { lhs, rhs } => self.visit_n_eq_impl(ast, idx, lhs, rhs),
AstNode::Lt { lhs, rhs } => self.visit_lt_impl(ast, idx, lhs, rhs),
AstNode::Gt { lhs, rhs } => self.visit_gt_impl(ast, idx, lhs, rhs),
AstNode::Le { lhs, rhs } => self.visit_le_impl(ast, idx, lhs, rhs),
AstNode::Ge { lhs, rhs } => self.visit_ge_impl(ast, idx, lhs, rhs),
AstNode::Shl { lhs, rhs } => self.visit_shl_impl(ast, idx, lhs, rhs),
AstNode::Shr { lhs, rhs } => self.visit_shr_impl(ast, idx, lhs, rhs),
AstNode::Add { lhs, rhs } => self.visit_add_impl(ast, idx, lhs, rhs),
AstNode::Sub { lhs, rhs } => self.visit_sub_impl(ast, idx, lhs, rhs),
AstNode::Mul { lhs, rhs } => self.visit_mul_impl(ast, idx, lhs, rhs),
AstNode::Div { lhs, rhs } => self.visit_div_impl(ast, idx, lhs, rhs),
AstNode::Rem { lhs, rhs } => self.visit_rem_impl(ast, idx, lhs, rhs),
AstNode::Assign { lhs, rhs } => self.visit_assign_impl(ast, idx, lhs, rhs),
AstNode::SubscriptExpr { lhs, index: rhs } => {
self.visit_subscript_expr_impl(ast, idx, lhs, rhs)
}
AstNode::IfExpr { cond, body } => self.visit_if_expr_impl(ast, idx, cond, body),
AstNode::IfElseExpr { cond, a, b } => {
self.visit_if_else_expr_impl(ast, idx, cond, a, b)
}
AstNode::Error { err } => self.visit_error_impl(ast, idx, err),
AstNode::Undefined => self.visit_undefined_impl(ast, idx),
AstNode::Root { .. } => unreachable!(),
}
}
}

View file

@ -55,7 +55,7 @@ fn main() {
println!("AST:\n{buf}");
}
"ast2" => {
let mut tree2 = compiler::ast2::parser::Parser::new();
let mut tree2 = compiler::ast2::ast_gen::Parser::new();
tree2.parse(tokens.iter());
eprintln!("{tree2:#?}");
println!("AST (new):\n{tree2}");

View file

@ -12,7 +12,10 @@ pub mod bigint {
pub struct BigInt(Vec<u32>);
impl BigInt {
pub fn parse_digits<C: IntoIterator<Item = char>>(text: C, radix: Radix) -> BigInt {
pub fn parse_digits<C: IntoIterator<Item = char>>(
text: C,
radix: Radix,
) -> BigInt {
Self(parse_bigint(text.into_iter(), radix))
}
pub fn from_u32(v: u32) -> BigInt {
@ -237,9 +240,13 @@ pub mod bigint {
fn sub(mut self, rhs: Self) -> Self::Output {
if self.0.len() < rhs.0.len() {
println!("extending self by {} zeroes", rhs.0.len() - self.0.len());
self.0
.extend(core::iter::repeat(0).take(rhs.0.len() - self.0.len()));
println!(
"extending self by {} zeroes",
rhs.0.len() - self.0.len()
);
self.0.extend(
core::iter::repeat(0).take(rhs.0.len() - self.0.len()),
);
println!("self: {self:?}");
}
sub_bigint(&mut self.0, &rhs.0);
@ -497,7 +504,10 @@ pub mod bigint {
_ => {
if scalar.is_power_of_two() {
lhs.push(0);
shl_bitint(lhs.as_mut_slice(), scalar.trailing_zeros() as usize);
shl_bitint(
lhs.as_mut_slice(),
scalar.trailing_zeros() as usize,
);
} else {
let mut carry = 0;
for a in lhs.iter_mut() {
@ -570,7 +580,7 @@ pub mod bigint {
fn trailing_zeros(lhs: &[u32]) -> usize {
lhs.iter()
.enumerate()
.find(|&(_, &c)| c != 0)
.find(|(_, &c)| c != 0)
.map(|(i, &c)| i * u32::BITS as usize + c.trailing_zeros() as usize)
.unwrap_or(0)
}
@ -583,7 +593,10 @@ pub mod bigint {
#[allow(dead_code)]
/// divident must be at least as wide as divisor
/// returns (quotient, remainder)
pub fn div_rem_bigint_ref(divident: &BigInt, divisor: &BigInt) -> (BigInt, BigInt) {
pub fn div_rem_bigint_ref(
divident: &BigInt,
divisor: &BigInt,
) -> (BigInt, BigInt) {
if bigint_is_zero(&divisor.0) {
panic!("divide by zero!");
}
@ -601,7 +614,8 @@ pub mod bigint {
if divisor.is_power_of_two() {
let exp = divisor.trailing_zeros();
let (div, rem) = divident.0.split_at(exp.div_floor(u32::BITS as usize));
let (div, rem) =
divident.0.split_at(exp.div_floor(u32::BITS as usize));
let (mut div, mut rem) = (div.to_vec(), rem.to_vec());
shr_bitint(&mut div, exp % u32::BITS as usize);
@ -627,7 +641,10 @@ pub mod bigint {
if shift == 0 {
div_rem_core(divident.clone(), &divisor.0)
} else {
let (q, r) = div_rem_core(divident.clone() << shift, &(divisor.clone() << shift).0);
let (q, r) = div_rem_core(
divident.clone() << shift,
&(divisor.clone() << shift).0,
);
(q, r >> shift)
}
@ -636,7 +653,10 @@ pub mod bigint {
#[allow(dead_code)]
/// divident must be at least as wide as divisor
/// returns (quotient, remainder)
pub fn div_rem_bigint(divident: BigInt, divisor: BigInt) -> (BigInt, BigInt) {
pub fn div_rem_bigint(
divident: BigInt,
divisor: BigInt,
) -> (BigInt, BigInt) {
let divident = divident.normalised();
let mut divisor = divisor.normalised();
@ -657,7 +677,8 @@ pub mod bigint {
if divisor.is_power_of_two() {
let exp = divisor.trailing_zeros();
let (div, rem) = divident.0.split_at(exp.div_floor(u32::BITS as usize));
let (div, rem) =
divident.0.split_at(exp.div_floor(u32::BITS as usize));
let (mut div, mut rem) = (div.to_vec(), rem.to_vec());
shr_bitint(&mut div, exp % u32::BITS as usize);
@ -789,7 +810,9 @@ pub mod bigint {
// q0 is too large if:
// [a2,a1,a0] < q0 * [b1,b0]
// (r << BITS) + a2 < q0 * b1
while r <= u32::MAX as u64 && from_lo_hi_dwords(r as u32, a2) < q0 as u64 * b1 as u64 {
while r <= u32::MAX as u64
&& from_lo_hi_dwords(r as u32, a2) < q0 as u64 * b1 as u64
{
q0 -= 1;
r += b0 as u64;
}
@ -1018,7 +1041,10 @@ pub mod bigint {
carry
}
pub fn parse_bigint(text: impl Iterator<Item = char>, radix: Radix) -> Vec<u32> {
pub fn parse_bigint(
text: impl Iterator<Item = char>,
radix: Radix,
) -> Vec<u32> {
let digits = text
.filter_map(|c| match c {
'_' => None,
@ -1086,14 +1112,20 @@ pub mod bigint {
#[test]
fn parse() {
let bigint = BigInt::parse_digits("2_cafe_babe_dead_beef".chars(), Radix::Hex);
let bigint = BigInt::parse_digits(
"2_cafe_babe_dead_beef".chars(),
Radix::Hex,
);
println!("{:#x?}", bigint);
let bigint = BigInt::parse_digits("f".chars(), Radix::Hex);
println!("{:#x?}", bigint);
}
#[test]
fn add() {
let a = BigInt::parse_digits("2_0000_0000_0000_0000".chars(), Radix::Hex);
let a = BigInt::parse_digits(
"2_0000_0000_0000_0000".chars(),
Radix::Hex,
);
println!("{:#x?}", a);
let b = BigInt::parse_digits("cafebabe".chars(), Radix::Hex);
println!("{:#x?}", b);
@ -1111,7 +1143,10 @@ pub mod bigint {
}
#[test]
fn overflowing_sub() {
let a = BigInt::parse_digits("2_0000_0000_0000_0000".chars(), Radix::Hex);
let a = BigInt::parse_digits(
"2_0000_0000_0000_0000".chars(),
Radix::Hex,
);
println!("{:#x?}", a);
let b = BigInt::parse_digits("ffff_ffff".chars(), Radix::Hex);
println!("{:#x?}", b);
@ -1120,7 +1155,8 @@ pub mod bigint {
}
#[test]
fn shr() {
let mut a = BigInt::parse_digits("cafe_babe_0000".chars(), Radix::Hex);
let mut a =
BigInt::parse_digits("cafe_babe_0000".chars(), Radix::Hex);
print!("{:0>8x?} >> 32 ", a);
shr_bitint(&mut a.0, 32);
println!("{:0>8x?}", a);
@ -1152,7 +1188,9 @@ pub mod bigint {
pub mod bigsint {
use std::{
cmp::Ordering,
ops::{Add, AddAssign, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub, SubAssign},
ops::{
Add, AddAssign, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub, SubAssign,
},
};
use super::bigint::{self, *};
@ -1295,11 +1333,13 @@ pub mod bigsint {
match (self.sign, rhs.sign) {
(_, Sign::None) => self,
(Sign::None, _) => rhs,
(Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => Self {
(Sign::Positive, Sign::Positive)
| (Sign::Negative, Sign::Negative) => Self {
sign: self.sign,
bigint: self.bigint + rhs.bigint,
},
(Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => {
(Sign::Positive, Sign::Negative)
| (Sign::Negative, Sign::Positive) => {
match self.bigint.cmp(&rhs.bigint) {
Ordering::Less => Self {
sign: rhs.sign,
@ -1321,11 +1361,13 @@ pub mod bigsint {
fn add(self, rhs: u32) -> Self::Output {
match self.sign {
Sign::Negative => match self.bigint.partial_cmp(&rhs).unwrap() {
Ordering::Less => Self::positive(rhs - self.bigint),
Ordering::Equal => Self::zero(),
Ordering::Greater => -Self::positive(self.bigint - rhs),
},
Sign::Negative => {
match self.bigint.partial_cmp(&rhs).unwrap() {
Ordering::Less => Self::positive(rhs - self.bigint),
Ordering::Equal => Self::zero(),
Ordering::Greater => -Self::positive(self.bigint - rhs),
}
}
Sign::None => Self::from_u32(rhs),
Sign::Positive => Self::positive(self.bigint + rhs),
}
@ -1337,11 +1379,13 @@ pub mod bigsint {
fn add(self, rhs: u64) -> Self::Output {
match self.sign {
Sign::Negative => match self.bigint.partial_cmp(&rhs).unwrap() {
Ordering::Less => Self::positive(rhs - self.bigint),
Ordering::Equal => Self::zero(),
Ordering::Greater => -Self::positive(self.bigint - rhs),
},
Sign::Negative => {
match self.bigint.partial_cmp(&rhs).unwrap() {
Ordering::Less => Self::positive(rhs - self.bigint),
Ordering::Equal => Self::zero(),
Ordering::Greater => -Self::positive(self.bigint - rhs),
}
}
Sign::None => Self::from_u64(rhs),
Sign::Positive => Self::positive(self.bigint + rhs),
}
@ -1362,11 +1406,13 @@ pub mod bigsint {
match (self.sign, rhs.sign) {
(_, Sign::None) => self,
(Sign::None, _) => -rhs,
(Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => Self {
(Sign::Positive, Sign::Negative)
| (Sign::Negative, Sign::Positive) => Self {
sign: self.sign,
bigint: self.bigint + rhs.bigint,
},
(Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
(Sign::Positive, Sign::Positive)
| (Sign::Negative, Sign::Negative) => {
match self.bigint.cmp(&rhs.bigint) {
Ordering::Less => Self {
sign: -self.sign,
@ -1470,7 +1516,11 @@ pub mod bigsint {
bigint: r,
};
if rhs.is_negative() { (-q, r) } else { (q, r) }
if rhs.is_negative() {
(-q, r)
} else {
(q, r)
}
}
fn shr_rounding(lhs: &BigSInt, shift: usize) -> bool {
@ -1498,7 +1548,7 @@ use std::{
};
use num_bigint::{BigInt, BigUint, Sign};
use num_traits::{ToBytes, cast::ToPrimitive};
use num_traits::{cast::ToPrimitive, ToBytes};
use crate::ast::{FloatingType, IntegralType, Type};
@ -1535,14 +1585,20 @@ impl ComptimeInt {
pub fn add(self, other: Self) -> Result<Self> {
let (a, b) = self.coalesce(other)?;
match (a, b) {
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
(
ComptimeInt::Native { bits: a, ty },
ComptimeInt::Native { bits: b, .. },
) => {
let bits = a.checked_add(b).ok_or(Error::IntegerOverflow)?;
if bits & !ty.u128_bitmask() != 0 {
return Err(Error::IntegerOverflow);
}
Ok(Self::Native { bits, ty })
}
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
(
ComptimeInt::BigInt { bits: a, ty },
ComptimeInt::BigInt { bits: b, .. },
) => {
let width = ty.bits - ty.signed as u16;
let bits = a + b;
if bits.bits() > width as u64 {
@ -1551,7 +1607,9 @@ impl ComptimeInt {
Ok(Self::BigInt { bits, ty })
}
}
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a + b)),
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
Ok(Self::Comptime(a + b))
}
_ => {
unreachable!()
}
@ -1561,14 +1619,20 @@ impl ComptimeInt {
pub fn sub(self, other: Self) -> Result<Self> {
let (a, b) = self.coalesce(other)?;
match (a, b) {
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
(
ComptimeInt::Native { bits: a, ty },
ComptimeInt::Native { bits: b, .. },
) => {
let bits = a.checked_sub(b).ok_or(Error::IntegerOverflow)?;
if bits & !ty.u128_bitmask() != 0 {
return Err(Error::IntegerOverflow);
}
Ok(Self::Native { bits, ty })
}
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
(
ComptimeInt::BigInt { bits: a, ty },
ComptimeInt::BigInt { bits: b, .. },
) => {
let width = ty.bits - ty.signed as u16;
let bits = a - b;
if bits.bits() > width as u64 {
@ -1577,7 +1641,9 @@ impl ComptimeInt {
Ok(Self::BigInt { bits, ty })
}
}
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a - b)),
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
Ok(Self::Comptime(a - b))
}
_ => {
unreachable!()
}
@ -1587,14 +1653,20 @@ impl ComptimeInt {
pub fn mul(self, other: Self) -> Result<Self> {
let (a, b) = self.coalesce(other)?;
match (a, b) {
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
(
ComptimeInt::Native { bits: a, ty },
ComptimeInt::Native { bits: b, .. },
) => {
let bits = a.checked_mul(b).ok_or(Error::IntegerOverflow)?;
if bits & !ty.u128_bitmask() != 0 {
return Err(Error::IntegerOverflow);
}
Ok(Self::Native { bits, ty })
}
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
(
ComptimeInt::BigInt { bits: a, ty },
ComptimeInt::BigInt { bits: b, .. },
) => {
let width = ty.bits - ty.signed as u16;
let bits = a * b;
if bits.bits() > width as u64 {
@ -1603,7 +1675,9 @@ impl ComptimeInt {
Ok(Self::BigInt { bits, ty })
}
}
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a * b)),
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
Ok(Self::Comptime(a * b))
}
_ => {
unreachable!()
}
@ -1613,14 +1687,20 @@ impl ComptimeInt {
pub fn div(self, other: Self) -> Result<Self> {
let (a, b) = self.coalesce(other)?;
match (a, b) {
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
(
ComptimeInt::Native { bits: a, ty },
ComptimeInt::Native { bits: b, .. },
) => {
let bits = a.checked_div(b).ok_or(Error::IntegerOverflow)?;
if bits & !ty.u128_bitmask() != 0 {
return Err(Error::IntegerOverflow);
}
Ok(Self::Native { bits, ty })
}
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
(
ComptimeInt::BigInt { bits: a, ty },
ComptimeInt::BigInt { bits: b, .. },
) => {
let width = ty.bits - ty.signed as u16;
let bits = a / b;
if bits.bits() > width as u64 {
@ -1629,7 +1709,9 @@ impl ComptimeInt {
Ok(Self::BigInt { bits, ty })
}
}
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a / b)),
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
Ok(Self::Comptime(a / b))
}
_ => {
unreachable!()
}
@ -1639,14 +1721,20 @@ impl ComptimeInt {
pub fn rem(self, other: Self) -> Result<Self> {
let (a, b) = self.coalesce(other)?;
match (a, b) {
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
(
ComptimeInt::Native { bits: a, ty },
ComptimeInt::Native { bits: b, .. },
) => {
let bits = a.checked_rem(b).ok_or(Error::IntegerOverflow)?;
if bits & !ty.u128_bitmask() != 0 {
return Err(Error::IntegerOverflow);
}
Ok(Self::Native { bits, ty })
}
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
(
ComptimeInt::BigInt { bits: a, ty },
ComptimeInt::BigInt { bits: b, .. },
) => {
let width = ty.bits - ty.signed as u16;
let bits = a % b;
if bits.bits() > width as u64 {
@ -1655,7 +1743,9 @@ impl ComptimeInt {
Ok(Self::BigInt { bits, ty })
}
}
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a % b)),
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
Ok(Self::Comptime(a % b))
}
_ => {
unreachable!()
}
@ -1665,15 +1755,23 @@ impl ComptimeInt {
pub fn bitand(self, other: Self) -> Result<Self> {
let (a, b) = self.coalesce(other)?;
match (a, b) {
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
(
ComptimeInt::Native { bits: a, ty },
ComptimeInt::Native { bits: b, .. },
) => {
let bits = a.bitand(b);
Ok(Self::Native { bits, ty })
}
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
(
ComptimeInt::BigInt { bits: a, ty },
ComptimeInt::BigInt { bits: b, .. },
) => {
let bits = a & b;
Ok(Self::BigInt { bits, ty })
}
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a & b)),
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
Ok(Self::Comptime(a & b))
}
_ => {
unreachable!()
}
@ -1683,15 +1781,23 @@ impl ComptimeInt {
pub fn bitor(self, other: Self) -> Result<Self> {
let (a, b) = self.coalesce(other)?;
match (a, b) {
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
(
ComptimeInt::Native { bits: a, ty },
ComptimeInt::Native { bits: b, .. },
) => {
let bits = a.bitor(b);
Ok(Self::Native { bits, ty })
}
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
(
ComptimeInt::BigInt { bits: a, ty },
ComptimeInt::BigInt { bits: b, .. },
) => {
let bits = a | b;
Ok(Self::BigInt { bits, ty })
}
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a | b)),
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
Ok(Self::Comptime(a | b))
}
_ => {
unreachable!()
}
@ -1701,15 +1807,23 @@ impl ComptimeInt {
pub fn bitxor(self, other: Self) -> Result<Self> {
let (a, b) = self.coalesce(other)?;
match (a, b) {
(ComptimeInt::Native { bits: a, ty }, ComptimeInt::Native { bits: b, .. }) => {
(
ComptimeInt::Native { bits: a, ty },
ComptimeInt::Native { bits: b, .. },
) => {
let bits = a.bitxor(b);
Ok(Self::Native { bits, ty })
}
(ComptimeInt::BigInt { bits: a, ty }, ComptimeInt::BigInt { bits: b, .. }) => {
(
ComptimeInt::BigInt { bits: a, ty },
ComptimeInt::BigInt { bits: b, .. },
) => {
let bits = a ^ b;
Ok(Self::BigInt { bits, ty })
}
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => Ok(Self::Comptime(a ^ b)),
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => {
Ok(Self::Comptime(a ^ b))
}
_ => {
unreachable!()
}
@ -1718,8 +1832,14 @@ impl ComptimeInt {
pub fn cmp(self, other: Self) -> Result<Ordering> {
let (a, b) = self.coalesce(other)?;
let ord = match (a, b) {
(ComptimeInt::Native { bits: a, .. }, ComptimeInt::Native { bits: b, .. }) => a.cmp(&b),
(ComptimeInt::BigInt { bits: a, .. }, ComptimeInt::BigInt { bits: b, .. }) => a.cmp(&b),
(
ComptimeInt::Native { bits: a, .. },
ComptimeInt::Native { bits: b, .. },
) => a.cmp(&b),
(
ComptimeInt::BigInt { bits: a, .. },
ComptimeInt::BigInt { bits: b, .. },
) => a.cmp(&b),
(ComptimeInt::Comptime(a), ComptimeInt::Comptime(b)) => a.cmp(&b),
_ => {
unreachable!()
@ -1737,11 +1857,13 @@ impl ComptimeInt {
let bits = if ty.signed {
(bits as i128)
.checked_shl(shift)
.ok_or(Error::IntegerOverflow)? as u128
.ok_or(Error::IntegerOverflow)?
as u128
} else {
(bits as u128)
.checked_shl(shift)
.ok_or(Error::IntegerOverflow)? as u128
.ok_or(Error::IntegerOverflow)?
as u128
} & ty.u128_bitmask();
Ok(Self::Native { bits, ty })
@ -1766,11 +1888,13 @@ impl ComptimeInt {
let bits = if ty.signed {
(bits as i128)
.checked_shr(shift)
.ok_or(Error::IntegerOverflow)? as u128
.ok_or(Error::IntegerOverflow)?
as u128
} else {
(bits as u128)
.checked_shr(shift)
.ok_or(Error::IntegerOverflow)? as u128
.ok_or(Error::IntegerOverflow)?
as u128
};
Ok(Self::Native { bits, ty })
@ -1789,7 +1913,9 @@ impl ComptimeInt {
if ty.signed {
return Err(Error::UnsignedNegation);
}
let bits = (a as i128).checked_neg().ok_or(Error::IntegerOverflow)? as u128;
let bits =
(a as i128).checked_neg().ok_or(Error::IntegerOverflow)?
as u128;
if bits & !ty.u128_bitmask() != 0 {
return Err(Error::IntegerOverflow);
@ -1807,7 +1933,9 @@ impl ComptimeInt {
bits: !bits | ty.u128_bitmask(),
ty,
}),
ComptimeInt::BigInt { bits, ty } => Ok(Self::BigInt { bits: !bits, ty }),
ComptimeInt::BigInt { bits, ty } => {
Ok(Self::BigInt { bits: !bits, ty })
}
ComptimeInt::Comptime(bigint) => Ok(Self::Comptime(!bigint)),
}
}
@ -1823,8 +1951,14 @@ impl ComptimeInt {
fn coalesce(self, other: Self) -> Result<(ComptimeInt, ComptimeInt)> {
match (self, other) {
(lhs @ ComptimeInt::Native { ty: a_ty, .. }, ComptimeInt::Comptime(b))
| (lhs @ ComptimeInt::Native { ty: a_ty, .. }, ComptimeInt::BigInt { bits: b, .. }) => {
(
lhs @ ComptimeInt::Native { ty: a_ty, .. },
ComptimeInt::Comptime(b),
)
| (
lhs @ ComptimeInt::Native { ty: a_ty, .. },
ComptimeInt::BigInt { bits: b, .. },
) => {
let b_signed = b.sign() == Sign::Minus;
if !a_ty.signed && b_signed {
return Err(Error::IncompatibleTypes);
@ -1841,8 +1975,14 @@ impl ComptimeInt {
};
Ok((lhs, Self::Native { bits: b, ty: a_ty }))
}
(ComptimeInt::Comptime(b), rhs @ ComptimeInt::Native { ty: a_ty, .. })
| (ComptimeInt::BigInt { bits: b, .. }, rhs @ ComptimeInt::Native { ty: a_ty, .. }) => {
(
ComptimeInt::Comptime(b),
rhs @ ComptimeInt::Native { ty: a_ty, .. },
)
| (
ComptimeInt::BigInt { bits: b, .. },
rhs @ ComptimeInt::Native { ty: a_ty, .. },
) => {
let b_signed = b.sign() == Sign::Minus;
if !a_ty.signed && b_signed {
return Err(Error::IncompatibleTypes);
@ -1859,7 +1999,10 @@ impl ComptimeInt {
};
Ok((Self::Native { bits: b, ty: a_ty }, rhs))
}
(lhs @ ComptimeInt::BigInt { ty, .. }, ComptimeInt::Comptime(b)) => {
(
lhs @ ComptimeInt::BigInt { ty, .. },
ComptimeInt::Comptime(b),
) => {
let b_signed = b.sign() == Sign::Minus;
if !ty.signed && b_signed {
return Err(Error::IncompatibleTypes);
@ -1871,7 +2014,10 @@ impl ComptimeInt {
}
Ok((lhs, Self::BigInt { bits: b, ty }))
}
(ComptimeInt::Comptime(b), rhs @ ComptimeInt::BigInt { ty, .. }) => {
(
ComptimeInt::Comptime(b),
rhs @ ComptimeInt::BigInt { ty, .. },
) => {
let b_signed = b.sign() == Sign::Minus;
if !ty.signed && b_signed {
return Err(Error::IncompatibleTypes);
@ -1883,14 +2029,20 @@ impl ComptimeInt {
}
Ok((Self::BigInt { bits: b, ty }, rhs))
}
(lhs @ ComptimeInt::Native { ty: a, .. }, rhs @ ComptimeInt::Native { ty: b, .. }) => {
(
lhs @ ComptimeInt::Native { ty: a, .. },
rhs @ ComptimeInt::Native { ty: b, .. },
) => {
if a == b {
Ok((lhs, rhs))
} else {
Err(Error::IncompatibleTypes)
}
}
(lhs @ ComptimeInt::BigInt { ty: a, .. }, rhs @ ComptimeInt::BigInt { ty: b, .. }) => {
(
lhs @ ComptimeInt::BigInt { ty: a, .. },
rhs @ ComptimeInt::BigInt { ty: b, .. },
) => {
if a == b {
Ok((lhs, rhs))
} else {
@ -1911,36 +2063,56 @@ pub enum ComptimeFloat {
impl ComptimeFloat {
pub fn add(self, other: Self) -> Result<ComptimeFloat> {
match (self, other) {
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => Ok(Self::Binary32(a + b)),
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => Ok(Self::Binary64(a + b)),
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
Ok(Self::Binary32(a + b))
}
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
Ok(Self::Binary64(a + b))
}
_ => Err(Error::IncompatibleTypes),
}
}
pub fn sub(self, other: Self) -> Result<ComptimeFloat> {
match (self, other) {
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => Ok(Self::Binary32(a - b)),
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => Ok(Self::Binary64(a - b)),
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
Ok(Self::Binary32(a - b))
}
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
Ok(Self::Binary64(a - b))
}
_ => Err(Error::IncompatibleTypes),
}
}
pub fn mul(self, other: Self) -> Result<ComptimeFloat> {
match (self, other) {
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => Ok(Self::Binary32(a * b)),
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => Ok(Self::Binary64(a * b)),
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
Ok(Self::Binary32(a * b))
}
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
Ok(Self::Binary64(a * b))
}
_ => Err(Error::IncompatibleTypes),
}
}
pub fn div(self, other: Self) -> Result<ComptimeFloat> {
match (self, other) {
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => Ok(Self::Binary32(a / b)),
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => Ok(Self::Binary64(a / b)),
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
Ok(Self::Binary32(a / b))
}
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
Ok(Self::Binary64(a / b))
}
_ => Err(Error::IncompatibleTypes),
}
}
pub fn rem(self, other: Self) -> Result<ComptimeFloat> {
match (self, other) {
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => Ok(Self::Binary32(a % b)),
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => Ok(Self::Binary64(a % b)),
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
Ok(Self::Binary32(a % b))
}
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
Ok(Self::Binary64(a % b))
}
_ => Err(Error::IncompatibleTypes),
}
}
@ -1952,8 +2124,12 @@ impl ComptimeFloat {
}
pub fn cmp(self, other: Self) -> Result<Ordering> {
let ord = match (self, other) {
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => a.partial_cmp(&b),
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => a.partial_cmp(&b),
(ComptimeFloat::Binary32(a), ComptimeFloat::Binary32(b)) => {
a.partial_cmp(&b)
}
(ComptimeFloat::Binary64(a), ComptimeFloat::Binary64(b)) => {
a.partial_cmp(&b)
}
_ => {
return Err(Error::IncompatibleTypes);
}
@ -2105,7 +2281,9 @@ impl ComptimeNumber {
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
// Ok(Self::Floating(a.sub(b)?))
// }
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a.bitand(b))),
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
Ok(Self::Bool(a.bitand(b)))
}
_ => Err(Error::IncompatibleTypes),
}
}
@ -2117,7 +2295,9 @@ impl ComptimeNumber {
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
// Ok(Self::Floating(a.bitor(b)?))
// }
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a.bitor(b))),
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
Ok(Self::Bool(a.bitor(b)))
}
_ => Err(Error::IncompatibleTypes),
}
}
@ -2129,7 +2309,9 @@ impl ComptimeNumber {
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
// Ok(Self::Floating(a.bitxor(b)?))
// }
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a.bitxor(b))),
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
Ok(Self::Bool(a.bitxor(b)))
}
_ => Err(Error::IncompatibleTypes),
}
}
@ -2165,7 +2347,9 @@ impl ComptimeNumber {
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
// Ok(Self::Floating(a.bitxor(b)?))
// }
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a || b)),
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
Ok(Self::Bool(a || b))
}
_ => Err(Error::IncompatibleTypes),
}
}
@ -2177,23 +2361,35 @@ impl ComptimeNumber {
// (ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
// Ok(Self::Floating(a.bitxor(b)?))
// }
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a && b)),
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
Ok(Self::Bool(a && b))
}
_ => Err(Error::IncompatibleTypes),
}
}
pub fn eq(self, other: Self) -> Result<Self> {
match (self, other) {
(ComptimeNumber::Integral(a), ComptimeNumber::Integral(b)) => Ok(Self::Bool(a == b)),
(ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => Ok(Self::Bool(a == b)),
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => Ok(Self::Bool(a == b)),
(ComptimeNumber::Integral(a), ComptimeNumber::Integral(b)) => {
Ok(Self::Bool(a == b))
}
(ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
Ok(Self::Bool(a == b))
}
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => {
Ok(Self::Bool(a == b))
}
_ => Err(Error::IncompatibleTypes),
}
}
pub fn cmp(self, other: Self) -> Result<Ordering> {
let ord = match (self, other) {
(ComptimeNumber::Integral(a), ComptimeNumber::Integral(b)) => a.cmp(b)?,
(ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => a.cmp(b)?,
(ComptimeNumber::Integral(a), ComptimeNumber::Integral(b)) => {
a.cmp(b)?
}
(ComptimeNumber::Floating(a), ComptimeNumber::Floating(b)) => {
a.cmp(b)?
}
(ComptimeNumber::Bool(a), ComptimeNumber::Bool(b)) => a.cmp(&b),
_ => {
return Err(Error::IncompatibleTypes);
@ -2233,12 +2429,17 @@ impl ComptimeNumber {
match self {
ComptimeNumber::Integral(i) => match i {
ComptimeInt::Native { bits, .. } => Ok((bits != 0).into()),
ComptimeInt::Comptime(bits) | ComptimeInt::BigInt { bits, .. } => {
ComptimeInt::Comptime(bits)
| ComptimeInt::BigInt { bits, .. } => {
Ok((bits.sign() != Sign::NoSign).into())
}
},
ComptimeNumber::Floating(ComptimeFloat::Binary32(f)) => Ok((f != 0.0).into()),
ComptimeNumber::Floating(ComptimeFloat::Binary64(f)) => Ok((f != 0.0).into()),
ComptimeNumber::Floating(ComptimeFloat::Binary32(f)) => {
Ok((f != 0.0).into())
}
ComptimeNumber::Floating(ComptimeFloat::Binary64(f)) => {
Ok((f != 0.0).into())
}
a => Ok(a),
}
}
@ -2246,19 +2447,29 @@ impl ComptimeNumber {
pub fn into_int(self, ty: IntegralType) -> Result<Self> {
match self {
ComptimeNumber::Integral(i) => match i {
ComptimeInt::Native { bits, .. } => Ok((bits & ty.u128_bitmask(), ty).into()),
ComptimeInt::Comptime(bits) | ComptimeInt::BigInt { bits, .. } => {
let max = BigUint::from(2u32).pow((ty.bits - ty.signed as u16) as u32);
ComptimeInt::Native { bits, .. } => {
Ok((bits & ty.u128_bitmask(), ty).into())
}
ComptimeInt::Comptime(bits)
| ComptimeInt::BigInt { bits, .. } => {
let max = BigUint::from(2u32)
.pow((ty.bits - ty.signed as u16) as u32);
let (sign, data) = bits.into_parts();
let data = data.clamp(BigUint::ZERO, max);
Ok((BigInt::from_biguint(sign, data), ty).into())
}
},
ComptimeNumber::Bool(b) => Ok((b as u128 & ty.u128_bitmask(), ty).into()),
ComptimeNumber::Bool(b) => {
Ok((b as u128 & ty.u128_bitmask(), ty).into())
}
ComptimeNumber::Floating(f) => match f {
ComptimeFloat::Binary32(f) => Ok((f as u128 & ty.u128_bitmask(), ty).into()),
ComptimeFloat::Binary64(f) => Ok((f as u128 & ty.u128_bitmask(), ty).into()),
ComptimeFloat::Binary32(f) => {
Ok((f as u128 & ty.u128_bitmask(), ty).into())
}
ComptimeFloat::Binary64(f) => {
Ok((f as u128 & ty.u128_bitmask(), ty).into())
}
},
ComptimeNumber::Void => {
return Err(Error::VoidConversion);
@ -2269,7 +2480,8 @@ impl ComptimeNumber {
let f = match self {
ComptimeNumber::Integral(i) => match i {
ComptimeInt::Native { bits, .. } => bits as f64,
ComptimeInt::Comptime(bits) | ComptimeInt::BigInt { bits, .. } => {
ComptimeInt::Comptime(bits)
| ComptimeInt::BigInt { bits, .. } => {
bits.to_f64().unwrap_or(f64::NAN)
}
},

View file

@ -1,6 +1,8 @@
#![feature(
extract_if,
iter_advance_by,
box_into_inner,
hash_extract_if,
bigint_helper_methods,
map_try_insert,
iter_intersperse,
@ -8,10 +10,9 @@
int_roundings,
if_let_guard,
debug_closure_helpers,
box_vec_non_null,
macro_metavar_expr
)]
#![allow(unused_macros, unsafe_op_in_unsafe_fn)]
#![allow(unused_macros)]
pub mod asm;
pub mod ast;
@ -28,9 +29,6 @@ pub mod symbol_table;
pub mod tokens;
pub mod triples;
pub mod utils;
use utils::unit;
pub fn tokenize<'a>(
bytes: &'a [u8],
) -> Result<lexer::Tokenizer<'a>, (lexer::Tokenizer<'a>, Vec<lexer::TokenizeError>)> {

View file

@ -2,7 +2,6 @@ use itertools::Itertools;
use num_bigint::{BigInt, BigUint};
use crate::{
BitSize,
ast::{self, FloatingType, IntegralType, LetOrVar, Node, Tag, Type},
ast2::intern::{self, AMD64_POINTER_BITS},
common::NextIf,
@ -10,7 +9,8 @@ use crate::{
error::{AnalysisError, AnalysisErrorTag},
lexer::{Radix, TokenIterator},
symbol_table::{SymbolKind, SymbolTable},
tokens::{PRECEDENCE_MAP, Token},
tokens::{Token, PRECEDENCE_MAP},
BitSize,
};
#[derive(Debug, thiserror::Error)]
@ -1767,10 +1767,10 @@ impl Tree {
}
pub fn peer_type_of_nodes_unwrap(&self, lhs: Node, rhs: Node) -> Type {
self.peer_type_of_nodes(lhs, rhs).expect(&{
self.peer_type_of_nodes(lhs, rhs).expect({
let at = self.type_of_node(lhs);
let bt = self.type_of_node(rhs);
format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
&format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
})
}
@ -1844,10 +1844,10 @@ impl Tree {
} => {
let ty = match (explicit_type.as_ref(), assignment) {
(None, b) => self.type_of_node(*b),
(Some(a), b) => self.peer_type_of_nodes(*a, *b).expect(&{
(Some(a), b) => self.peer_type_of_nodes(*a, *b).expect({
let at = self.type_of_node(*a);
let bt = self.type_of_node(*b);
format!("incompatible types for %{a}({at}) and %{b}({bt})")
&format!("incompatible types for %{a}({at}) and %{b}({bt})")
}),
};
@ -1863,10 +1863,10 @@ impl Tree {
(None, None) => panic!("%{node}: no type specified?"),
(None, Some(b)) => self.type_of_node(*b),
(Some(a), None) => self.type_of_node(*a),
(Some(a), Some(b)) => self.peer_type_of_nodes(*a, *b).expect(&{
(Some(a), Some(b)) => self.peer_type_of_nodes(*a, *b).expect({
let at = self.type_of_node(*a);
let bt = self.type_of_node(*b);
format!("incompatible types for %{a}({at}) and %{b}({bt})")
&format!("incompatible types for %{a}({at}) and %{b}({bt})")
}),
};
@ -1888,10 +1888,10 @@ impl Tree {
| Tag::And { lhs, rhs }
| Tag::BitOr { lhs, rhs }
| Tag::BitAnd { lhs, rhs }
| Tag::BitXOr { lhs, rhs } => self.peer_type_of_nodes(*lhs, *rhs).expect(&{
| Tag::BitXOr { lhs, rhs } => self.peer_type_of_nodes(*lhs, *rhs).expect({
let at = self.type_of_node(*lhs);
let bt = self.type_of_node(*rhs);
format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
&format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
}),
Tag::Shl { lhs, .. } => self.type_of_node(*lhs),
Tag::Shr { lhs, .. } => self.type_of_node(*lhs),
@ -1906,11 +1906,11 @@ impl Tree {
Tag::IfExpr { .. } => Type::void(),
Tag::IfElseExpr {
body, else_expr, ..
} => self.peer_type_of_nodes(*body, *else_expr).expect(&{
} => self.peer_type_of_nodes(*body, *else_expr).expect({
let (lhs, rhs) = (body, else_expr);
let at = self.type_of_node(*lhs);
let bt = self.type_of_node(*rhs);
format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
&format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
}),
_ => Type::void(),
}

View file

@ -35,13 +35,25 @@ impl SymbolPath {
for node in self.0.iter().skip(1).rev() {
match tree.nodes.get_node(node.unwrap()) {
Tag::VarDecl { name, .. } => {
_ = write!(&mut buf, "V{}::", tree.get_ident_str(*name).unwrap());
_ = write!(
&mut buf,
"V{}::",
tree.get_ident_str(*name).unwrap()
);
}
Tag::GlobalDecl { name, .. } => {
_ = write!(&mut buf, "G{}::", tree.get_ident_str(*name).unwrap());
_ = write!(
&mut buf,
"G{}::",
tree.get_ident_str(*name).unwrap()
);
}
Tag::FunctionProto { name, .. } => {
_ = write!(&mut buf, "F{}::", tree.get_ident_str(*name).unwrap());
_ = write!(
&mut buf,
"F{}::",
tree.get_ident_str(*name).unwrap()
);
}
_ => {}
}
@ -69,11 +81,11 @@ impl InnerSymbolTable {
Self::new_with(Self::new_inner)
}
fn new_with<G>(r#gen: G) -> NonNull<InnerSymbolTable>
fn new_with<G>(gen: G) -> NonNull<InnerSymbolTable>
where
G: FnOnce() -> Self,
{
Box::into_non_null(Box::new(r#gen()))
NonNull::new(Box::leak(Box::new(gen())) as *mut _).unwrap()
}
fn new_inner() -> InnerSymbolTable {
@ -130,7 +142,12 @@ impl Drop for InnerSymbolTable {
}
impl InnerSymbolTable {
fn insert_symbol(&mut self, name: &str, node: AstNode, kind: SymbolKind) -> &SymbolRecord {
fn insert_symbol(
&mut self,
name: &str,
node: AstNode,
kind: SymbolKind,
) -> &SymbolRecord {
match kind {
SymbolKind::Var => {
self.ordered_identifiers.push(SymbolRecord {
@ -143,7 +160,11 @@ impl InnerSymbolTable {
}
}
fn insert_orderless_symbol(&mut self, name: &str, node: AstNode) -> &SymbolRecord {
fn insert_orderless_symbol(
&mut self,
name: &str,
node: AstNode,
) -> &SymbolRecord {
self.orderless_identifiers.insert(
name.to_owned(),
SymbolRecord {
@ -154,7 +175,11 @@ impl InnerSymbolTable {
self.orderless_identifiers.get(name).unwrap()
}
fn find_symbol_or_insert_with<'a, F>(&'a mut self, name: &str, cb: F) -> &'a SymbolRecord
fn find_symbol_or_insert_with<'a, F>(
&'a mut self,
name: &str,
cb: F,
) -> &'a SymbolRecord
where
F: FnOnce() -> (AstNode, SymbolKind),
{
@ -177,7 +202,9 @@ impl InnerSymbolTable {
.find(|(_, v)| v.decl == decl)
.map(|(_, v)| v)
})
.or_else(|| self.parent_ref().and_then(|p| p.find_symbol_by_decl(decl)))
.or_else(|| {
self.parent_ref().and_then(|p| p.find_symbol_by_decl(decl))
})
}
fn find_any_symbol(&self, name: &str) -> Option<&SymbolRecord> {
@ -192,7 +219,9 @@ impl InnerSymbolTable {
self.ordered_identifiers
.iter()
.find(|r| r.name.as_str() == name)
.or_else(|| self.parent_ref().and_then(|p| p.find_ordered_symbol(name)))
.or_else(|| {
self.parent_ref().and_then(|p| p.find_ordered_symbol(name))
})
}
fn find_orderless_symbol(&self, name: &str) -> Option<&SymbolRecord> {
@ -286,7 +315,12 @@ impl SymbolTableWrapper {
}
impl SymbolTableWrapper {
pub fn insert_symbol(&mut self, name: &str, node: AstNode, kind: SymbolKind) -> &SymbolRecord {
pub fn insert_symbol(
&mut self,
name: &str,
node: AstNode,
kind: SymbolKind,
) -> &SymbolRecord {
self.current_mut().insert_symbol(name, node, kind)
}
@ -294,15 +328,27 @@ impl SymbolTableWrapper {
self.root_mut().find_orderless_symbol(name)
}
pub fn insert_root_symbol(&mut self, name: &str, node: AstNode) -> &SymbolRecord {
pub fn insert_root_symbol(
&mut self,
name: &str,
node: AstNode,
) -> &SymbolRecord {
self.root_mut().insert_orderless_symbol(name, node)
}
pub fn insert_orderless_symbol(&mut self, name: &str, node: AstNode) -> &SymbolRecord {
pub fn insert_orderless_symbol(
&mut self,
name: &str,
node: AstNode,
) -> &SymbolRecord {
self.current_mut().insert_orderless_symbol(name, node)
}
pub fn find_symbol_or_insert_with<'a, F>(&'a mut self, name: &str, cb: F) -> &'a SymbolRecord
pub fn find_symbol_or_insert_with<'a, F>(
&'a mut self,
name: &str,
cb: F,
) -> &'a SymbolRecord
where
F: FnOnce() -> (AstNode, SymbolKind),
{
@ -404,8 +450,8 @@ pub mod syms2 {
use std::collections::BTreeMap;
use std::fmt::Debug;
use crate::ast2::Index as AstIndex;
use crate::ast2::intern::Index as InternIndex;
use crate::ast2::Index as AstIndex;
use crate::lexer::SourceLocation;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@ -424,40 +470,6 @@ pub mod syms2 {
},
}
impl Key {
pub fn kind(&self) -> Option<SymbolKind> {
match self {
Key::Symbol { kind, .. } => Some(*kind),
_ => None,
}
}
}
#[repr(u32)]
pub enum DeclKind {
Local = 1,
Parameter,
}
impl DeclKind {
pub fn from_u32(v: u32) -> Option<Self> {
match v {
1 => Some(Self::Local),
2 => Some(Self::Parameter),
_ => None,
}
}
}
impl From<SymbolKind> for Option<DeclKind> {
fn from(value: SymbolKind) -> Self {
match value {
SymbolKind::Parameter(_) => Some(DeclKind::Parameter),
SymbolKind::Local(_) => Some(DeclKind::Local),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum SymbolKind {
__First,
@ -467,7 +479,6 @@ pub mod syms2 {
__TypeScope,
Scope,
ParentScope,
Parameter(SourceLocation),
Local(SourceLocation),
__Last,
}
@ -515,7 +526,9 @@ pub mod syms2 {
}
let entries = self.inner.iter().map(|(key, val)| {
let payload = match key {
Key::ScopeByIndex { .. } => ExpandedPayload::Intern(val.as_intern()),
Key::ScopeByIndex { .. } => {
ExpandedPayload::Intern(val.as_intern())
}
_ => ExpandedPayload::Ast(val.as_ast()),
};
@ -554,7 +567,7 @@ pub mod syms2 {
scope: AstIndex,
name: InternIndex,
loc: SourceLocation,
) -> Option<(Key, AstIndex)> {
) -> Option<AstIndex> {
use SymbolKind::*;
let range = self.inner.range(
Key::Symbol {
@ -568,8 +581,8 @@ pub mod syms2 {
},
);
if let Some((key, payload)) = range.rev().next() {
Some((*key, payload.as_ast()))
if let Some((_, payload)) = range.rev().next() {
Some(payload.as_ast())
} else {
if let Some(parent) = self.inner.get(&Key::Symbol {
scope,
@ -588,7 +601,7 @@ pub mod syms2 {
scope: AstIndex,
name: InternIndex,
loc: SourceLocation,
) -> Option<(Key, AstIndex)> {
) -> Option<AstIndex> {
use SymbolKind::*;
let range = self.inner.range(
Key::Symbol {
@ -602,15 +615,15 @@ pub mod syms2 {
},
);
if let Some((key, payload)) = range.rev().next() {
Some((*key, payload.as_ast()))
if let Some((_, payload)) = range.rev().next() {
Some(payload.as_ast())
} else {
if let Some(parent) = self.inner.get(&Key::Symbol {
scope,
name: InternIndex::invalid(),
kind: ParentScope,
}) {
self.find_type_symbol(parent.as_ast(), name, loc)
self.find_symbol(parent.as_ast(), name, loc)
} else {
None
}
@ -624,8 +637,10 @@ pub mod syms2 {
kind: SymbolKind,
ast: AstIndex,
) {
self.inner
.insert(Key::Symbol { scope, name, kind }, Payload::new_ast(ast));
self.inner.insert(
Key::Symbol { scope, name, kind },
Payload::new_ast(ast),
);
}
}
}

View file

@ -7,7 +7,7 @@ use std::{
use crate::{
ast::{Node as AstNode, Tag, Type},
ast2::intern::{self, AMD64_POINTER_BITS, AMD64_POINTER_TYPE_INFO, InternPool},
ast2::intern::{self, InternPool, AMD64_POINTER_BITS, AMD64_POINTER_TYPE_INFO},
parser::Tree,
variant, write_indented, writeln_indented,
};
@ -159,13 +159,10 @@ pub enum Inst {
Constant,
/// size, align
Alloca,
/// (pointee type)
/// src
Load(intern::Index),
/// (pointee type)
/// src, dst
Store(intern::Index),
/// (pointer type)
/// ptr, index,
GetElementPtr(intern::Index),
/// size, align
@ -608,10 +605,10 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
let ty = self
.tree
.peer_type_of_nodes(*lhs, *rhs)
.expect(&{
.expect({
let at = self.tree.type_of_node(*lhs);
let bt = self.tree.type_of_node(*rhs);
format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
&format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})")
})
.into();
@ -762,8 +759,8 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
}
pub struct IR {
pub(crate) nodes: Vec<Inst>,
pub(crate) data: Vec<Option<Data>>,
nodes: Vec<Inst>,
data: Vec<Option<Data>>,
// intern_pool: &'a mut InternPool,
}

View file

@ -1,25 +0,0 @@
use core::{cell::UnsafeCell, mem::ManuallyDrop};
pub fn unit<T>(_: T) {}
pub struct DropGuard<F: FnOnce()>(UnsafeCell<ManuallyDrop<F>>);
impl<F> DropGuard<F>
where
F: FnOnce(),
{
pub fn new(f: F) -> DropGuard<F> {
Self(UnsafeCell::new(ManuallyDrop::new(f)))
}
}
impl<F> Drop for DropGuard<F>
where
F: FnOnce(),
{
fn drop(&mut self) {
unsafe {
ManuallyDrop::take(&mut *self.0.get())();
}
}
}