use llvm_native_core::opcode::Opcode;
use llvm_native_core::types::{TypeId, TypeKind};
use std::collections::{BTreeMap, HashMap, HashSet};
#[derive(Debug, Clone, PartialEq)]
pub enum Token {
KwDefine,
KwDeclare,
KwGlobal,
KwConstant,
KwPrivate,
KwInternal,
KwExternal,
KwWeak,
KwLinkonce,
KwAppending,
KwCommon,
KwDllimport,
KwDllexport,
KwHidden,
KwProtected,
KwDefault,
KwTarget,
KwTriple,
KwDatalayout,
KwSourceFilename,
KwModuleId,
KwAttributes,
KwAlign,
KwAlignStack,
KwAllocSize,
KwAlwaysInline,
KwArgMemOnly,
KwBuiltin,
KwByVal,
KwCold,
KwConvergent,
KwDereferenceable,
KwDereferenceableOrNull,
KwInAlloca,
KwInReg,
KwInaccessibleMemOnly,
KwInaccessibleMemOrArgMemOnly,
KwInlineHint,
KwJumpTable,
KwMinSize,
KwMustProgress,
KwNaked,
KwNest,
KwNoAlias,
KwNoBuiltin,
KwNoCallback,
KwNoCapture,
KwNoCfCheck,
KwNoDuplicate,
KwNoFree,
KwNoImplicitFloat,
KwNoInline,
KwNoMerge,
KwNoProfile,
KwNoRecurse,
KwNoRedZone,
KwNoReturn,
KwNoSync,
KwNoUnwind,
KwNonLazyBind,
KwNonNull,
KwNoUndef,
KwOptDebug,
KwOptForFuzzing,
KwOptimizeNone,
KwOptimizeForSize,
KwPreallocated,
KwReadNone,
KwReadOnly,
KwReturned,
KwReturnsTwice,
KwSExt,
KwSafeStack,
KwSanitizeAddress,
KwSanitizeHwAddress,
KwSanitizeMemory,
KwSanitizeThread,
KwShadowCallStack,
KwSpeculatable,
KwSpeculativeLoadHardening,
KwSsp,
KwSspReq,
KwSspStrong,
KwStackProtect,
KwStrictFP,
KwSwiftAsync,
KwSwiftError,
KwSwiftSelf,
KwUWTable,
KwWillReturn,
KwWriteOnly,
KwZExt,
KwNoSanitize,
KwSanitizeCoverage,
KwSanitizeMemTag,
KwDisableSanitizerInstrumentation,
KwComdat,
KwPersonality,
KwCleanup,
KwCatch,
KwFilter,
KwTo,
KwUnwind,
KwFrom,
KwLandingpad,
KwResume,
KwUnreachable,
KwAddrspace,
KwExact,
KwNuw,
KwNsw,
KwInbounds,
KwTail,
KwMustTail,
KwNoTail,
KwVolatile,
KwAtomic,
KwAcquire,
KwRelease,
KwAcqRel,
KwSeqCst,
KwMonotonic,
KwUnordered,
KwSyncscope,
KwCmpXchgWeak,
KwXchg,
KwAdd,
KwSub,
KwFAdd,
KwFSub,
LParen,
RParen,
LBrace,
RBrace,
LBracket,
RBracket,
LAngle,
RAngle,
Comma,
Colon,
Equals,
Star,
DotDot,
Exclaim,
Hash,
Arrow,
Ident(String),
GlobalIdent(String),
LocalIdent(String),
Label(String),
IntegerLit(u64),
FloatLit(f64),
StringLit(String),
MetadataId(u64),
AttrGroupId(u64),
Ellipsis,
Newline,
EndOfFile,
Unknown(char),
}
#[derive(Debug, Clone)]
pub enum ASTNode {
Module(ModuleAST),
Function(FunctionAST),
Global(GlobalAST),
Alias(AliasAST),
IFunc(IFuncAST),
AttributeGroup(AttrGroupAST),
Comdat(ComdatAST),
Metadata(MetadataAST),
NamedMetadata(NamedMetadataAST),
TypeDef(TypeDefAST),
UseListOrder(UseListOrderAST),
SummaryEntry(SummaryEntryAST),
}
#[derive(Debug, Clone)]
pub struct ModuleAST {
pub module_id: Option<String>,
pub source_filename: Option<String>,
pub target_triple: Option<String>,
pub data_layout: Option<String>,
pub inline_asm: String,
pub type_defs: Vec<TypeDefAST>,
pub globals: Vec<GlobalAST>,
pub functions: Vec<FunctionAST>,
pub aliases: Vec<AliasAST>,
pub ifuncs: Vec<IFuncAST>,
pub attr_groups: Vec<AttrGroupAST>,
pub comdats: Vec<ComdatAST>,
pub named_metadata: Vec<NamedMetadataAST>,
pub metadata: Vec<MetadataAST>,
}
#[derive(Debug, Clone)]
pub struct FunctionAST {
pub linkage: LinkageAST,
pub visibility: VisibilityAST,
pub dll_storage: DLLStorageAST,
pub calling_conv: Option<String>,
pub return_type: TypeAST,
pub name: String,
pub params: Vec<ParamAST>,
pub is_vararg: bool,
pub unnamed_addr: Option<UnnamedAddrAST>,
pub fn_attrs: Vec<FnAttrAST>,
pub section: Option<String>,
pub comdat: Option<String>,
pub align: Option<u32>,
pub gc: Option<String>,
pub prefix: Option<String>,
pub prologue: Option<String>,
pub personality: Option<String>,
pub metadata_attachments: Vec<MetadataAttachmentAST>,
pub body: Option<FunctionBodyAST>,
}
#[derive(Debug, Clone)]
pub struct FunctionBodyAST {
pub blocks: Vec<BasicBlockAST>,
}
#[derive(Debug, Clone)]
pub struct BasicBlockAST {
pub label: String,
pub instructions: Vec<InstructionAST>,
pub terminator: Option<TerminatorAST>,
}
#[derive(Debug, Clone)]
pub enum InstructionAST {
Add(String, ValueRefAST, ValueRefAST),
Sub(String, ValueRefAST, ValueRefAST),
Mul(String, ValueRefAST, ValueRefAST),
UDiv(String, ValueRefAST, ValueRefAST),
SDiv(String, ValueRefAST, ValueRefAST),
URem(String, ValueRefAST, ValueRefAST),
SRem(String, ValueRefAST, ValueRefAST),
Shl(String, ValueRefAST, ValueRefAST),
LShr(String, ValueRefAST, ValueRefAST),
AShr(String, ValueRefAST, ValueRefAST),
And(String, ValueRefAST, ValueRefAST),
Or(String, ValueRefAST, ValueRefAST),
Xor(String, ValueRefAST, ValueRefAST),
FAdd(String, ValueRefAST, ValueRefAST),
FSub(String, ValueRefAST, ValueRefAST),
FMul(String, ValueRefAST, ValueRefAST),
FDiv(String, ValueRefAST, ValueRefAST),
FRem(String, ValueRefAST, ValueRefAST),
Alloca(String, TypeAST, Option<ValueRefAST>, Option<u32>),
Load(String, TypeAST, ValueRefAST, Option<u32>),
Store(ValueRefAST, ValueRefAST, Option<u32>),
GetElementPtr(String, TypeAST, ValueRefAST, Vec<ValueRefAST>),
Trunc(String, ValueRefAST, TypeAST),
ZExt(String, ValueRefAST, TypeAST),
SExt(String, ValueRefAST, TypeAST),
FPTrunc(String, ValueRefAST, TypeAST),
FPExt(String, ValueRefAST, TypeAST),
FPToUI(String, ValueRefAST, TypeAST),
FPToSI(String, ValueRefAST, TypeAST),
UIToFP(String, ValueRefAST, TypeAST),
SIToFP(String, ValueRefAST, TypeAST),
PtrToInt(String, ValueRefAST, TypeAST),
IntToPtr(String, ValueRefAST, TypeAST),
BitCast(String, ValueRefAST, TypeAST),
AddrSpaceCast(String, ValueRefAST, TypeAST),
ICmp(String, String, TypeAST, ValueRefAST, ValueRefAST),
FCmp(String, String, TypeAST, ValueRefAST, ValueRefAST),
Select(String, ValueRefAST, ValueRefAST, ValueRefAST),
VAArg(String, ValueRefAST, TypeAST),
ExtractElement(String, ValueRefAST, ValueRefAST),
InsertElement(String, ValueRefAST, ValueRefAST, ValueRefAST),
ShuffleVector(String, ValueRefAST, ValueRefAST, ValueRefAST),
ExtractValue(String, ValueRefAST, Vec<u32>),
InsertValue(String, ValueRefAST, ValueRefAST, Vec<u32>),
PHI(String, TypeAST, Vec<(ValueRefAST, String)>),
Call(String, TypeAST, ValueRefAST, Vec<ValueRefAST>),
Freeze(String, ValueRefAST),
AtomicRMW(String, String, ValueRefAST, ValueRefAST, String),
CmpXchg(
String,
ValueRefAST,
ValueRefAST,
ValueRefAST,
String,
String,
),
Fence(String),
}
#[derive(Debug, Clone)]
pub enum TerminatorAST {
RetVoid,
Ret(ValueRefAST),
Br(String),
CondBr(ValueRefAST, String, String),
Switch(ValueRefAST, String, Vec<(ValueRefAST, String)>),
IndirectBr(ValueRefAST, Vec<String>),
Invoke(TypeAST, ValueRefAST, Vec<ValueRefAST>, String, String),
CallBr(TypeAST, ValueRefAST, Vec<ValueRefAST>, String, String),
Resume(ValueRefAST),
CatchSwitch(ValueRefAST, Option<String>, Vec<String>),
CatchRet(ValueRefAST, String),
CleanupRet(ValueRefAST, Option<String>),
Unreachable,
}
#[derive(Debug, Clone)]
pub struct GlobalAST {
pub linkage: LinkageAST,
pub name: String,
pub ty: TypeAST,
pub initializer: Option<ValueRefAST>,
pub align: Option<u32>,
pub section: Option<String>,
pub is_constant: bool,
}
#[derive(Debug, Clone)]
pub struct AliasAST {
pub name: String,
pub aliasee: String,
pub linkage: LinkageAST,
}
#[derive(Debug, Clone)]
pub struct IFuncAST {
pub name: String,
pub resolver: String,
pub linkage: LinkageAST,
}
#[derive(Debug, Clone)]
pub struct AttrGroupAST {
pub id: u64,
pub attrs: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ComdatAST {
pub name: String,
pub kind: String,
}
#[derive(Debug, Clone)]
pub struct MetadataAST {
pub id: u64,
pub is_distinct: bool,
pub operands: Vec<MetadataOperandAST>,
}
#[derive(Debug, Clone)]
pub struct NamedMetadataAST {
pub name: String,
pub operands: Vec<u64>,
}
#[derive(Debug, Clone)]
pub enum MetadataOperandAST {
Null,
String(String),
Value(ValueRefAST),
MDNode(u64),
Int(u64),
}
#[derive(Debug, Clone)]
pub struct MetadataAttachmentAST {
pub kind: String,
pub node: u64,
}
#[derive(Debug, Clone)]
pub struct TypeAST {
pub kind: TypeKind,
}
#[derive(Debug, Clone)]
pub struct TypeDefAST {
pub name: String,
pub ty: TypeAST,
}
#[derive(Debug, Clone)]
pub struct ParamAST {
pub ty: TypeAST,
pub name: Option<String>,
pub attrs: Vec<String>,
}
#[derive(Debug, Clone)]
pub enum ValueRefAST {
Local(String),
Global(String),
Constant(ConstantAST),
MetadataRef(u64),
InlineAsm(String, String),
}
#[derive(Debug, Clone)]
pub enum ConstantAST {
Int(u64),
Float(f64),
Null,
Undef,
Poison,
ZeroInitializer,
Struct(Vec<ConstantAST>),
Array(Vec<ConstantAST>),
Vector(Vec<ConstantAST>),
String(String),
BlockAddress(String, String),
TokenNone,
Expr(ConstantExprAST),
AggregateZero,
}
#[derive(Debug, Clone)]
pub struct ConstantExprAST {
pub opcode: String,
pub operands: Vec<ConstantAST>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LinkageAST {
Private,
Internal,
External,
Weak,
WeakODR,
LinkOnce,
LinkOnceODR,
AvailableExternally,
Appending,
Common,
ExternalWeak,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VisibilityAST {
Default,
Hidden,
Protected,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DLLStorageAST {
Default,
Import,
Export,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnnamedAddrAST {
Local,
Global,
}
#[derive(Debug, Clone)]
pub enum FnAttrAST {
Simple(String),
StringKV(String, String),
IntValue(String, u64),
Align(u64),
}
#[derive(Debug, Clone)]
pub struct UseListOrderAST {
pub value_name: String,
pub indices: Vec<u32>,
}
#[derive(Debug, Clone)]
pub struct SummaryEntryAST {
pub kind: String, pub entries: Vec<SummaryFieldAST>,
}
#[derive(Debug, Clone)]
pub enum SummaryFieldAST {
Name(String),
Guid(u64),
Linkage(String),
InstCount(u32),
CalleeGuid(u64),
CalleeHotness(u32),
TypeId(String),
}
#[derive(Debug)]
pub struct ParserState {
pub tokens: Vec<Token>,
pub pos: usize,
pub errors: Vec<ParserError>,
pub module: Option<ModuleAST>,
}
#[derive(Debug)]
pub struct ParserError {
pub message: String,
pub line: u32,
pub column: u32,
}
impl ParserState {
pub fn new(tokens: Vec<Token>) -> Self {
ParserState {
tokens,
pos: 0,
errors: Vec::new(),
module: None,
}
}
pub fn peek(&self) -> Option<&Token> {
self.tokens.get(self.pos)
}
pub fn advance(&mut self) -> Option<Token> {
if self.pos < self.tokens.len() {
let t = self.tokens[self.pos].clone();
self.pos += 1;
Some(t)
} else {
None
}
}
pub fn expect(&mut self, expected: Token) -> bool {
match self.peek() {
Some(t) if *t == expected => {
self.advance();
true
}
_ => false,
}
}
pub fn error(&mut self, msg: &str) {
self.errors.push(ParserError {
message: msg.to_string(),
line: 0,
column: 0,
});
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parser_state_new() {
let ps = ParserState::new(vec![Token::EndOfFile]);
assert!(ps.peek().is_some());
assert_eq!(ps.errors.len(), 0);
}
#[test]
fn test_parser_advance() {
let mut ps = ParserState::new(vec![Token::Ident("x".to_string()), Token::EndOfFile]);
assert_eq!(ps.advance(), Some(Token::Ident("x".to_string())));
assert_eq!(ps.advance(), Some(Token::EndOfFile));
assert_eq!(ps.advance(), None);
}
#[test]
fn test_parser_expect() {
let mut ps = ParserState::new(vec![Token::KwDefine, Token::EndOfFile]);
assert!(ps.expect(Token::KwDefine));
assert!(!ps.expect(Token::KwDeclare));
}
#[test]
fn test_linkage_ast_variants() {
assert_eq!(LinkageAST::Private as u32, 0);
assert_ne!(LinkageAST::External, LinkageAST::Internal);
}
#[test]
fn test_fn_attr_ast() {
let a = FnAttrAST::Simple("noinline".to_string());
match a {
FnAttrAST::Simple(s) => assert_eq!(s, "noinline"),
_ => panic!(),
}
}
}